diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index ef38c21..a475c0e 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -12,6 +12,20 @@ These rules are **MANDATORY** for all commits: ## Development Workflow +### Cleaning Build Artifacts + +To clean all build artifacts across the entire workspace: + +```bash +cargo xtask clean +``` + +This removes: +- Rust build artifacts (`target/`, `Cargo.lock`) +- tree-sitter node_modules and build output +- Zed extension build artifacts (`grammars/`, `extension.wasm`) +- mdbook build artifacts (`docs/book/`) + ### Installing the LSP To reinstall/update the Storybook LSP after making changes: diff --git a/Cargo.lock b/Cargo.lock index 92f478c..eacb9c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1533,7 +1533,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "storybook" -version = "0.2.0" +version = "0.3.1" dependencies = [ "anyhow", "clap", @@ -2253,6 +2253,13 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +[[package]] +name = "xtask" +version = "0.1.0" +dependencies = [ + "anyhow", +] + [[package]] name = "yoke" version = "0.8.1" diff --git a/Cargo.toml b/Cargo.toml index ba55268..bbc0ede 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,10 @@ +[workspace] +members = [".", "xtask"] +exclude = ["tree-sitter-storybook"] + [package] name = "storybook" -version = "0.2.0" +version = "0.3.1" edition = "2021" [lib] diff --git a/design/year-long-schedule-system-revision.md b/design/year-long-schedule-system-revision.md index ecb331e..1fe53fb 100644 --- a/design/year-long-schedule-system-revision.md +++ b/design/year-long-schedule-system-revision.md @@ -11,7 +11,7 @@ This revision addresses Sienna's feedback: -1. ✅ **Simplified composition** - Keep only `extends` and `override`, remove `remove`/`append`/`replace all` +1. ✅ **Simplified composition** - Keep only `modifies` and `override`, remove `remove`/`append`/`replace all` 2. ✅ **User-configurable calendars** - Define seasons/days as enums in schema, not hardcoded 3. ✅ **Behavior references** - Blocks reference behaviors/actions, not string activity names 4. ✅ **Required block names** - All blocks must be named for override system @@ -26,7 +26,7 @@ This revision addresses Sienna's feedback: This document proposes a **year-long, composable schedule system** for the Storybook DSL that: - **User-defined calendars**: Seasons, days, months defined as enums (8 seasons? 5-day weeks? You decide!) -- **Simple composition**: Only `extends` and `override` (no complex operators) +- **Simple composition**: Only `modifies` and `override` (no complex operators) - **Behavior integration**: Schedule blocks reference behaviors, not string activities - **Temporal patterns**: Day-specific, seasonal, and recurring event patterns - **Type-safe**: Validator ensures calendar references are valid @@ -166,7 +166,7 @@ Users can `use schema::standard_calendar::*` or define their own! ### 2.1 Only Two Operators **Keep:** -- `extends` - Inherit from base schedule +- `modifies` - Inherit from base schedule - `override` - Replace specific blocks **Remove:** @@ -185,7 +185,7 @@ schedule BaseWorkday { block sleep_late { 22:00 - 24:00, action: Sleep } } -schedule BakerSchedule extends BaseWorkday { +schedule BakerSchedule modifies BaseWorkday { override work { 5:00 - 13:00, action: BakeryWork } block baking { 3:00 - 5:00, action: PrepBread } // New block, not override } @@ -207,7 +207,7 @@ schedule Base { block work { 9:00 - 17:00, action: GenericWork } } -schedule Baker extends Base { +schedule Baker modifies Base { override work { 5:00 - 13:00, action: BakeryWork } } // Baker's 'work' block replaces Base's 'work' block entirely @@ -222,7 +222,7 @@ schedule Base { block work { 9:00 - 17:00, action: GenericWork, location: Office } } -schedule Remote extends Base { +schedule Remote modifies Base { override work { location: Home } // Only change location } // Result: work { 9:00 - 17:00, action: GenericWork, location: Home } @@ -322,7 +322,7 @@ schedule WeeklyRoutine { **Can extend base schedule per day:** ```storybook schedule WeeklyRoutine { - on Fireday extends BaseWorkday { + on Fireday modifies BaseWorkday { override work { action: FireWork } block ritual { 6:00 - 7:00, action: FireRitual } } @@ -363,7 +363,7 @@ season (Bloom, Growth) { // Both use same schedule **Named recurring events:** ```storybook -schedule AnnualPattern extends BaseWorkday { +schedule AnnualPattern modifies BaseWorkday { recurrence MarketDay on Earthday { block market { 8:00 - 13:00, action: SellAtMarket } } @@ -527,7 +527,7 @@ block work { #[derive(Debug, Clone, PartialEq)] pub struct Schedule { pub name: String, - pub extends: Option>, // extends BaseSchedule + pub modifies: Option>, // modifies BaseSchedule pub items: Vec, // blocks and patterns pub span: Span, } @@ -567,7 +567,7 @@ pub struct ScheduleOverride { #[derive(Debug, Clone, PartialEq)] pub struct DayPattern { pub day: String, // Reference to DayOfWeek enum value - pub extends: Option>, // Optional base schedule + pub modifies: Option>, // Optional base schedule pub blocks: Vec, pub span: Span, } @@ -604,13 +604,13 @@ pub enum RecurrenceSpec { ```lalrpop pub Schedule: Schedule = { - "schedule" "{" + "schedule" "{" - "}" => Schedule { name, extends, items, span } + "}" => Schedule { name, modifies, items, span } }; -ExtendsClause: Vec = { - "extends" +ModifiesClause: Vec = { + "modifies" }; ScheduleItem: ScheduleItem = { @@ -664,8 +664,8 @@ ScheduleOverride: ScheduleOverride = { // Day pattern: on Fireday { blocks } DayPattern: DayPattern = { - "{" "}" => - DayPattern { day, extends, blocks, span } + "{" "}" => + DayPattern { day, modifies, blocks, span } }; // Season pattern: season (Bloom, Growth) { blocks } @@ -797,7 +797,7 @@ schedule BaseWorkday { block sleep_late { 22:00 - 24:00, action: Sleep } } -schedule BakerSchedule extends BaseWorkday { +schedule BakerSchedule modifies BaseWorkday { override work { 5:00 - 13:00, action: BakeryWork } block prep { 3:00 - 5:00, action: PrepBread } } @@ -896,7 +896,7 @@ schedule MageSchedule { ### Example 5: Recurring Market Days ```storybook -schedule BakerAnnual extends BaseWorkday { +schedule BakerAnnual modifies BaseWorkday { recurrence MarketDay on Earthday { block market { 8:00 - 13:00, action: SellBread } } @@ -921,11 +921,11 @@ schedule BaseHuman { block sleep_late { 22:00 - 24:00, action: Sleep } } -schedule Worker extends BaseHuman { +schedule Worker modifies BaseHuman { block work { 9:00 - 17:00, action: GenericWork } } -schedule Baker extends Worker { +schedule Baker modifies Worker { override work { 5:00 - 13:00, action: BakeryWork } override breakfast { 13:30 - 14:00, action: Eat } // Late breakfast after work block prep { 3:00 - 5:00, action: PrepBread } @@ -996,7 +996,7 @@ SCHEDULES Section: Schedule: - name: String - - parent_schedule_id: Option // extends reference + - parent_schedule_id: Option // modifies reference - blocks: [ScheduleBlock...] - patterns: [SchedulePattern...] @@ -1032,7 +1032,7 @@ PatternKind: Character: Martha uses schedule: BakerSchedule -BakerSchedule extends BaseWorkday +BakerSchedule modifies BaseWorkday Merge result for today (Fireday, EarlySummer): 03:00-05:00 → PrepBread @@ -1063,7 +1063,7 @@ Merge result for today (Fireday, EarlySummer): 5. Write tests for custom calendars ### Phase 3: Parser Implementation (Week 1-2) -1. Implement simplified `extends`/`override` parsing +1. Implement simplified `modifies`/`override` parsing 2. Implement `on ` patterns 3. Implement `season ()` patterns 4. Implement `recurrence on ` patterns @@ -1100,7 +1100,7 @@ Merge result for today (Fireday, EarlySummer): ### Must Have - [x] User-defined calendars via enums -- [x] Simplified composition (`extends`, `override` only) +- [x] Simplified composition (`modifies`, `override` only) - [x] Behavior references (not string activities) - [x] Required block names - [x] Required time ranges diff --git a/design/year-long-schedule-system.md b/design/year-long-schedule-system.md index 977047c..be222c8 100644 --- a/design/year-long-schedule-system.md +++ b/design/year-long-schedule-system.md @@ -9,7 +9,7 @@ ## Executive Summary -This document proposes a **year-long, composable schedule system** for the Storybook DSL that extends the current simple daily schedules to support: +This document proposes a **year-long, composable schedule system** for the Storybook DSL that modifies the current simple daily schedules to support: - **Temporal composition**: Days → Weeks → Months → Seasons → Year - **Template inheritance**: Schedules extend and override like behavior templates @@ -162,7 +162,7 @@ schedule BakeryHours { **Yearly Schedule** - Full year with events and overrides: ```storybook -schedule AnnualPattern extends WorkWeek { +schedule AnnualPattern modifies WorkWeek { event Christmas on Dec 25 { block rest { 0:00 - 24:00, activity: rest } } @@ -175,9 +175,9 @@ schedule AnnualPattern extends WorkWeek { --- -## 4. Composition System (i just want `override` support, we can yank `remove` and `append` and `remove all`, but `extends` is good) +## 4. Composition System (i just want `override` support, we can yank `remove` and `append` and `remove all`, but `modifies` is good) -### 4.1 Template Inheritance with `extends` +### 4.1 Template Inheritance with `modifies` **Base Schedule:** ```storybook @@ -191,7 +191,7 @@ schedule BaseWorkday { **Extended Schedule:** ```storybook -schedule BakerSchedule extends BaseWorkday { +schedule BakerSchedule modifies BaseWorkday { override work { 5:00 - 13:00 } // Earlier hours append baking { 3:00 - 5:00, activity: prepare } } @@ -209,7 +209,7 @@ Block sleep: 22:00 - 24:00 + 0:00 - 6:00 (sleep) ← inherited **`override { fields }`** - Replace specific block properties: ```storybook -schedule BakerSchedule extends BaseWorkday { +schedule BakerSchedule modifies BaseWorkday { override work { time: 5:00 - 13:00, location: Bakery @@ -219,14 +219,14 @@ schedule BakerSchedule extends BaseWorkday { **`remove `** - Delete inherited block: ```storybook -schedule RetiredSchedule extends BaseWorkday { +schedule RetiredSchedule modifies BaseWorkday { remove work // No more work! } ``` **`append { fields }`** - Add new block: ```storybook -schedule ExtendedDay extends BaseWorkday { +schedule ExtendedDay modifies BaseWorkday { append meditation { 5:00 - 5:30, activity: meditate } } ``` @@ -246,11 +246,11 @@ schedule Base { block work { 9:00 - 17:00, activity: work } } -schedule WorkerSchedule extends Base { +schedule WorkerSchedule modifies Base { override work { 8:00 - 16:00 } } -schedule SeniorWorkerSchedule extends WorkerSchedule { +schedule SeniorWorkerSchedule modifies WorkerSchedule { override work { 9:00 - 15:00 } // Shorter hours } @@ -271,7 +271,7 @@ schedule SeniorWorkerSchedule extends WorkerSchedule { **Simple Weekday/Weekend Split:** ```storybook schedule WorkWeek { - weekday (mon, tue, wed, thu, fri) extends BaseWorkday { + weekday (mon, tue, wed, thu, fri) modifies BaseWorkday { // Monday-Friday use BaseWorkday } @@ -285,11 +285,11 @@ schedule WorkWeek { **Day-Specific Customization:** ```storybook schedule DetailedWeek { - on monday extends WorkdaySchedule { + on monday modifies WorkdaySchedule { append meeting { 9:00 - 10:00, activity: meeting } } - on friday extends WorkdaySchedule { + on friday modifies WorkdaySchedule { override work { 9:00 - 15:00 } // Early finish! } @@ -345,7 +345,7 @@ schedule FarmerSchedule { **Holiday Definitions:** ```storybook -schedule AnnualSchedule extends WorkWeek { +schedule AnnualSchedule modifies WorkWeek { event Christmas on Dec 25 { block family { 0:00 - 24:00, activity: family_time } } @@ -362,7 +362,7 @@ schedule AnnualSchedule extends WorkWeek { **Recurring Events:** (hmmmmmmmmmm sell me on this one.) ```storybook -schedule MarketSchedule extends BaseSchedule { +schedule MarketSchedule modifies BaseSchedule { every saturday { block market { 8:00 - 13:00, activity: sell_at_market } } @@ -385,7 +385,7 @@ schedule MarketSchedule extends BaseSchedule { #[derive(Debug, Clone, PartialEq)] pub struct Schedule { pub name: String, - pub extends: Option>, // NEW: extends BaseSchedule + pub modifies: Option>, // NEW: modifies BaseSchedule pub items: Vec, // NEW: blocks, patterns, events pub span: Span, } @@ -423,7 +423,7 @@ pub struct ScheduleOverride { #[derive(Debug, Clone, PartialEq)] pub struct WeekdayPattern { pub days: Vec, // [mon, tue, wed] - pub extends: Option>, // Optional base schedule + pub modifies: Option>, // Optional base schedule pub blocks: Vec, pub span: Span, } @@ -431,7 +431,7 @@ pub struct WeekdayPattern { #[derive(Debug, Clone, PartialEq)] pub struct DayPattern { pub day: DayOfWeek, // monday - pub extends: Option>, + pub modifies: Option>, pub blocks: Vec, pub span: Span, } @@ -485,13 +485,13 @@ pub enum RecurringPattern { // In parser.lalrpop pub Schedule: Schedule = { - "schedule" "{" + "schedule" "{" - "}" => Schedule { name, extends, items, span } + "}" => Schedule { name, modifies, items, span } }; -ExtendsClause: Vec = { - "extends" +ModifiesClause: Vec = { + "modifies" }; ScheduleItem: ScheduleItem = { @@ -537,16 +537,16 @@ ReplaceAllStmt = { // Weekday pattern: weekday (mon, tue, wed) { blocks } WeekdayPattern: WeekdayPattern = { - "weekday" "(" > ")" "{" + "weekday" "(" > ")" "{" - "}" => WeekdayPattern { days, extends, blocks, span } + "}" => WeekdayPattern { days, modifies, blocks, span } }; // Day pattern: on monday { blocks } DayPattern: DayPattern = { - "on" "{" + "on" "{" - "}" => DayPattern { day, extends, blocks, span } + "}" => DayPattern { day, modifies, blocks, span } }; // Season pattern: season summer { blocks } @@ -602,7 +602,7 @@ DateSpec: DateSpec = { ### 8.1 Schedule Merge Algorithm **Same as Behavior Merging:** -1. Resolve `extends` reference to base schedule +1. Resolve `modifies` reference to base schedule 2. Collect base schedule's blocks 3. Apply overrides/removes/appends from extending schedule 4. Override by block name (not by time) @@ -748,7 +748,7 @@ schedule BaseWorkday { block sleep { 22:00 - 24:00, activity: sleep } } -schedule BakerSchedule extends BaseWorkday { +schedule BakerSchedule modifies BaseWorkday { override work { time: 5:00 - 13:00, location: Bakery } append prep { time: 3:00 - 5:00, activity: bake_prep } } @@ -788,7 +788,7 @@ schedule BakeryHours { ### Example 5: Full Year with Events ```storybook -schedule AnnualSchedule extends WorkWeek { +schedule AnnualSchedule modifies WorkWeek { event Christmas on Dec 25 { block family { 0:00 - 24:00, activity: family_time } } @@ -813,17 +813,17 @@ schedule BaseHuman { block sleep { 22:00 - 24:00, activity: sleep } } -schedule Worker extends BaseHuman { +schedule Worker modifies BaseHuman { block work { 9:00 - 17:00, activity: work } } -schedule Baker extends Worker { +schedule Baker modifies Worker { override work { time: 5:00 - 13:00, location: Bakery } override breakfast { time: 13:30 - 14:00 } // Late breakfast append prep { time: 3:00 - 5:00, activity: bake } } -schedule RetiredBaker extends BaseHuman { +schedule RetiredBaker modifies BaseHuman { // No work, just keep eating/sleeping schedule append hobby { time: 10:00 - 16:00, activity: hobby } } @@ -842,7 +842,7 @@ SCHEDULES Section: Schedule: - name: String - - parent_schedule_id: Option // extends reference + - parent_schedule_id: Option // modifies reference - blocks: [ScheduleBlock...] - patterns: [SchedulePattern...] // weekday, season, event @@ -876,7 +876,7 @@ PatternKind: ``` Character Martha uses BakerSchedule ↓ -BakerSchedule extends BaseWorkday +BakerSchedule modifies BaseWorkday ↓ Merge: BaseWorkday blocks + Baker overrides ↓ @@ -888,14 +888,14 @@ Result: Martha's schedule for today ## 12. Implementation Plan ### Phase 1: AST Extension (Week 1) -1. Add extended Schedule struct with `extends` and `items` +1. Add extended Schedule struct with `modifies` and `items` 2. Add ScheduleItem enum (Block, Override, Remove, etc.) 3. Add pattern types (WeekdayPattern, SeasonPattern, EventPattern) 4. Add DayOfWeek, Season, DateSpec enums 5. Update existing ScheduleBlock to support optional names ### Phase 2: Parser Implementation (Week 1-2) -1. Implement `extends` clause parsing +1. Implement `modifies` clause parsing 2. Implement override/remove/append operators 3. Implement weekday/day patterns 4. Implement season patterns @@ -970,7 +970,7 @@ Which calendar system? ### Must Have - [x] Backward compatible with current simple schedules -- [x] Template inheritance with `extends` +- [x] Template inheritance with `modifies` - [x] Override/remove/append operators - [x] Weekday patterns (weekday/weekend) - [x] Day-specific patterns (on monday) @@ -1000,7 +1000,7 @@ Which calendar system? | Aspect | Behavior Linking | Schedule Linking | |--------|------------------|------------------| -| **Inheritance** | `from Template` | `extends Base` | +| **Inheritance** | `from Template` | `modifies Base` | | **Merge Rule** | Concatenation + override by name | Same | | **Override** | Character's behavior replaces template's | Child's block replaces parent's | | **Selection** | Priority + conditions | Temporal + conditions | diff --git a/docs/SBIR-v0.2.0-SPEC.md b/docs/SBIR-v0.2.0-SPEC.md index f38b34a..5fd0ebd 100644 --- a/docs/SBIR-v0.2.0-SPEC.md +++ b/docs/SBIR-v0.2.0-SPEC.md @@ -936,7 +936,7 @@ Character: **Source:** ```storybook -schedule WorkWeek extends BaseSchedule { +schedule WorkWeek modifies BaseSchedule { block morning { 08:00 - 12:00: WorkTasks } block lunch { 12:00 - 13:00: EatLunch } block afternoon { 13:00 - 17:00: WorkTasks } diff --git a/docs/SBIR-v0.3.0-SPEC.md b/docs/SBIR-v0.3.0-SPEC.md deleted file mode 100644 index 6f1b267..0000000 --- a/docs/SBIR-v0.3.0-SPEC.md +++ /dev/null @@ -1,1247 +0,0 @@ -# Storybook Intermediate Representation (SBIR) v0.3.0 Specification - -**Version:** 0.3.0 -**Status:** Draft -**Date:** February 2026 - ---- - -## Table of Contents - -1. [Introduction](#1-introduction) -2. [File Format Overview](#2-file-format-overview) -3. [Section 1: Header](#3-section-1-header) -4. [Section 2: String Table](#4-section-2-string-table) -5. [Section 3: Types](#5-section-3-types) -6. [Section 4: Characters](#6-section-4-characters) -7. [Section 5: Templates](#7-section-5-templates) -8. [Section 6: Species](#8-section-6-species) -9. [Section 7: Behaviors](#9-section-7-behaviors) -10. [Section 8: Schedules](#10-section-8-schedules) -11. [Section 9: Institutions](#11-section-9-institutions) -12. [Section 10: Relationships](#12-section-10-relationships) -13. [Section 11: Locations](#13-section-11-locations) -14. [Section 12: Life Arcs](#14-section-12-life-arcs) -15. [Section 13: Enums](#15-section-13-enums) -16. [Changelog](#16-changelog) - ---- - -## 1. Introduction - -### 1.1 Purpose - -The Storybook Intermediate Representation (SBIR) is a binary format that represents compiled Storybook programs. It serves as the interchange format between the Storybook compiler and runtime engines. - -### 1.2 Design Goals - -- **Compact:** Efficient binary encoding for large story worlds -- **Fast to load:** Direct memory mapping when possible -- **Versioned:** Clear version tracking for format evolution -- **Complete:** Represents all semantic information from source -- **Runtime-ready:** Minimal post-processing required - -### 1.3 Changes in v0.3.0 - -**Major additions:** -1. **Type System** - Concepts, sub-concepts (enum/record), and concept comparisons with pattern matching -2. **Species-Based Template Inheritance** - Templates can declare a species base for field inheritance -3. **Life Arc Field Requirements** - Life arcs can declare required fields with type annotations - -**Breaking changes:** -- TYPES section now populated with concept, sub_concept, and concept_comparison definitions -- Value discriminants renamed: Int→Number, Float→Decimal, String→Text, Bool→Boolean -- Expression discriminants renamed: IntLit→NumberLit, FloatLit→DecimalLit, StringLit→TextLit, BoolLit→BooleanLit -- TEMPLATES section extended with species_base field -- LIFE ARCS section extended with required_fields - -### 1.4 Changes in v0.2.0 - -**Major additions:** -1. **Resource Linking System** - Characters and institutions can link to behaviors and schedules with conditions and priorities -2. **Year-Long Schedule System** - Schedules support temporal patterns (day-specific, seasonal, recurrence) -3. **Behavior Tree Enhancements** - Named nodes, decorator parameters, keyword transformations - -**Breaking changes:** -- CHARACTERS section extended with behavior_links and schedule_links -- INSTITUTIONS section extended with behavior_links and schedule_links -- SCHEDULES section redesigned with patterns and inheritance -- BEHAVIORS section extended with named nodes and parameterized decorators - ---- - -## 2. File Format Overview - -### 2.1 File Structure - -``` -[Header] -[String Table] -[Type Definitions] -[Characters Section] -[Templates Section] -[Species Section] -[Behaviors Section] -[Schedules Section] -[Institutions Section] -[Relationships Section] -[Locations Section] -[Life Arcs Section] -[Enums Section] -``` - -### 2.2 Primitive Types - -| Type | Size | Description | -|------|------|-------------| -| `u8` | 1 byte | Unsigned 8-bit integer | -| `u16` | 2 bytes | Unsigned 16-bit integer (little-endian) | -| `u32` | 4 bytes | Unsigned 32-bit integer (little-endian) | -| `u64` | 8 bytes | Unsigned 64-bit integer (little-endian) | -| `i32` | 4 bytes | Signed 32-bit integer (little-endian) | -| `i64` | 8 bytes | Signed 64-bit integer (little-endian) | -| `f32` | 4 bytes | IEEE 754 single-precision float | -| `f64` | 8 bytes | IEEE 754 double-precision float | -| `bool` | 1 byte | 0 = false, 1 = true | -| `String` | Variable | Length-prefixed UTF-8: `u32 length` + `[u8; length]` | -| `StringRef` | 4 bytes | Index into string table (u32) | - -### 2.3 Common Structures - -#### Option - -Optional values are encoded with a discriminant byte followed by the value if present: - -``` -u8 discriminant: - 0 = None → No additional bytes, next field starts immediately - 1 = Some → T data follows immediately after discriminant -``` - -**Encoding:** -- **None case:** Just 1 byte (0x00), nothing else -- **Some case:** 1 byte (0x01) + full T encoding - -**Examples:** - -`Option` when None: -``` -0x00 ← 1 byte total -``` - -`Option` when Some(42): -``` -0x01 ← discriminant (Some) -0x2A 0x00 0x00 0x00 ← StringRef = 42 (u32) - ← 5 bytes total -``` - -`Option>` when None: -``` -0x00 ← 1 byte total -``` - -`Option>` when Some([field1, field2]): -``` -0x01 ← discriminant (Some) -0x02 0x00 0x00 0x00 ← count = 2 (u32) -[Field 1 encoding] ← First field -[Field 2 encoding] ← Second field - ← 5+ bytes (depends on field sizes) -``` - -#### Vec -``` -u32 count -[T; count] -``` - -### 2.4 Binary Format Conventions - -**IMPORTANT: SBIR is a packed binary format with no separators.** - -#### No Delimiter Bytes - -All data is laid out **sequentially in memory** with **no separator characters** between: -- Items in a Vec -- Fields in a struct -- Sections in the file -- Values of any kind - -The file is a continuous stream of bytes where each element's size determines where the next element begins. - -#### Length-Prefix Pattern - -All variable-length data uses a **length-prefix pattern**: - -1. **Length/count field** (u32) tells you "how much data is coming" -2. **Data bytes** - read exactly that amount -3. **Next field** starts immediately after (no gap, no separator) - -#### Reading Variable-Length Vec - -When `T` itself is variable-length, each item carries its own size information: - -**Example: Vec** -``` -u32 count = 3 ← "There are 3 strings" - String 1: - u32 length = 5 ← "First string is 5 bytes" - [u8; 5] = "hello" ← Read 5 bytes, next item starts immediately - String 2: - u32 length = 5 ← "Second string is 5 bytes" - [u8; 5] = "world" ← Read 5 bytes - String 3: - u32 length = 3 ← "Third string is 3 bytes" - [u8; 3] = "foo" ← Read 3 bytes -``` - -**Example: Vec** (complex variable-length structs) -``` -u32 count = 2 ← "There are 2 characters" - Character 1: - u32 name_len = 6 - [u8; 6] = "Martha" - u8 species_discriminant = 1 ← Option::Some - u32 species_ref = 10 - u32 fields_count = 2 - Field 1: (name_ref, value_discriminant, value_data) - Field 2: (name_ref, value_discriminant, value_data) - u32 template_refs_count = 1 - StringRef = 15 - u32 behavior_links_count = 0 - u32 schedule_links_count = 0 - Character 2: - (starts immediately after Character 1 ends) - u32 name_len = 5 - [u8; 5] = "David" - ... (continues) -``` - -#### Parsing Algorithm - -The parser reads **sequentially** using each length field to know how many bytes to consume: - -``` -position = 0 -while position < file_size: - read_length_or_discriminant() - read_exactly_that_many_bytes() - position += bytes_read - // Next field starts here (no seeking, no separator scanning) -``` - -#### Key Rules - -1. **Fixed-size types** (u8, u32, f64, etc.) take their exact size - no padding -2. **Variable-size types** always start with a length prefix (u32) -3. **Option** starts with a discriminant byte (0=None, 1=Some) -4. **Enums/discriminated unions** start with a discriminant byte -5. **No alignment padding** - all data is tightly packed - -There are no: - -- No newline characters (`\n`) -- No separators (`,`, `;`, spaces) -- No null terminators (except inside UTF-8 string data) -- No padding bytes between fields (unless explicitly specified) -- No section markers or headers (sections just follow each other) - -The documentation uses newlines and indentation for **readability only** - the actual binary file is a continuous stream of bytes with no whitespace. - ---- - -## 3. Section 1: Header - -``` -Magic: [u8; 4] // "SBIR" (0x53 0x42 0x49 0x52) -Version: u16 // Major version (0x0003 for v0.3.0) -MinorVersion: u16 // Minor version (0x0000) -Flags: u32 // Reserved (0x00000000) -SectionCount: u32 // Number of sections (currently 13) -``` - -**Version History:** -- v0.1.0: Implicit version (pre-release) -- v0.2.0: First formal versioned release -- v0.3.0: Type system, species inheritance, life arc requirements - ---- - -## 4. Section 2: String Table - -The string table stores all strings used in the SBIR file. - -``` -Count: u32 -Strings: [String; Count] -``` - -**Usage:** All `StringRef` types reference an index in this table. - -**Encoding:** UTF-8 with length prefix. - -**Example:** -``` -Count: 3 -Strings: - [0]: "Alice" - [1]: "Wonderland" - [2]: "rabbit_hole" -``` - ---- - -## 5. Section 3: Types - -**Note:** New in v0.3.0. This section encodes the concept type system. - -### 5.1 Structure - -``` -ConceptCount: u32 -Concepts: [Concept; ConceptCount] -SubConceptCount: u32 -SubConcepts: [SubConcept; SubConceptCount] -ConceptComparisonCount: u32 -ConceptComparisons: [ConceptComparison; ConceptComparisonCount] -``` - -### 5.2 Concept Encoding - -``` -Concept: - name: StringRef -``` - -A concept is a named type declaration with no additional data. Sub-concepts reference -their parent concept by name. - -### 5.3 SubConcept Encoding - -``` -SubConcept: - name: StringRef - parent_concept: StringRef - kind: u8 - data: -``` - -**Kind Discriminants:** -``` -0x01 = Enum -0x02 = Record -``` - -**Enum (0x01):** -``` -variants: Vec -``` - -**Record (0x02):** -``` -fields: Vec -``` - -Where `Field` is encoded as: -``` -Field: - name: StringRef - value: Value -``` - -### 5.4 ConceptComparison Encoding - -``` -ConceptComparison: - name: StringRef - concept_ref: StringRef // The concept being compared - sub_concept_ref: StringRef // The sub-concept (enum) being matched - arms: Vec -``` - -**ComparisonArm:** -``` -ComparisonArm: - variant: StringRef // Enum variant to match - fields: Vec // Field assignments for this arm - condition: Option // Optional guard condition -``` - -### 5.5 Binary Example - -**Source:** -```storybook -concept Cup -sub_concept Cup.Type { Small, Medium, Large } -sub_concept Cup.Material { weight: 100, fragile: true } - -concept_comparison CupDefaults for Cup matching Cup.Type { - Small { capacity: 200 } - Medium { capacity: 350 } - Large { capacity: 500 } -} -``` - -**Binary (conceptual):** -``` -ConceptCount: 1 -Concepts: - [0]: name = StringRef("Cup") - -SubConceptCount: 2 -SubConcepts: - [0]: SubConcept { - name: StringRef("Type") - parent_concept: StringRef("Cup") - kind: 0x01 (Enum) - variants: [StringRef("Small"), StringRef("Medium"), StringRef("Large")] - } - [1]: SubConcept { - name: StringRef("Material") - parent_concept: StringRef("Cup") - kind: 0x02 (Record) - fields: [ - Field { name: StringRef("weight"), value: Number(100) }, - Field { name: StringRef("fragile"), value: Boolean(true) } - ] - } - -ConceptComparisonCount: 1 -ConceptComparisons: - [0]: ConceptComparison { - name: StringRef("CupDefaults") - concept_ref: StringRef("Cup") - sub_concept_ref: StringRef("Type") - arms: [ - { variant: StringRef("Small"), fields: [("capacity", Number(200))], condition: None }, - { variant: StringRef("Medium"), fields: [("capacity", Number(350))], condition: None }, - { variant: StringRef("Large"), fields: [("capacity", Number(500))], condition: None } - ] - } -``` - ---- - -## 6. Section 4: Characters - -### 6.1 Structure - -``` -Count: u32 -Characters: [Character; Count] -``` - -### 6.2 Character Encoding - -``` -Character: - name: StringRef - species: Option - fields: Map - template_refs: Vec // Templates this character uses - behavior_links: Vec // NEW in v0.2.0 - schedule_links: Vec // NEW in v0.2.0 -``` - -### 6.3 BehaviorLink (NEW in v0.2.0) - -``` -BehaviorLink: - behavior_id: u32 // Index into BEHAVIORS section - priority: u8 // 0=Low, 1=Normal, 2=High, 3=Critical - condition: Option // Optional activation condition - is_default: bool // Default behavior (no condition) -``` - -**Priority Encoding:** -``` -enum Priority { - Low = 0, - Normal = 1, - High = 2, - Critical = 3, -} -``` - -**Selection Algorithm:** -1. Filter links where `condition` evaluates to true (or is None) -2. Sort by priority (descending) -3. Return highest priority link -4. If tie, use declaration order - -### 6.4 ScheduleLink (NEW in v0.2.0) - -``` -ScheduleLink: - schedule_id: u32 // Index into SCHEDULES section - condition: Option // Optional activation condition - is_default: bool // Default schedule (fallback) -``` - -**Selection Algorithm:** -1. Iterate schedule_links in order -2. Skip default links initially -3. Return first link where `condition` is true (or None) -4. If no match, use default link (if present) - -### 6.5 Value Encoding - -``` -Value: - discriminant: u8 - data: -``` - -**Discriminants:** -``` -0x01 = Number(i64) // Renamed from Int in v0.3.0 -0x02 = Decimal(f64) // Renamed from Float in v0.3.0 -0x03 = Text(StringRef) // Renamed from String in v0.3.0 -0x04 = Boolean(bool) // Renamed from Bool in v0.3.0 -0x05 = Range(Value, Value) -0x06 = Time(u8 hour, u8 minute, u8 second) -0x07 = Duration(u32 hours, u32 minutes, u32 seconds) -0x08 = Identifier(Vec) // Qualified path -0x09 = List(Vec) -0x0A = Object(Vec) -0x0B = ProseBlock(StringRef tag, String content) -0x0C = Override(...) -``` - -**Note:** The wire format (discriminant bytes 0x01-0x0C) is unchanged from v0.2.0. -Only the semantic names have been updated to match the Storybook language's type -terminology. - -### 6.6 Expression Encoding - -``` -Expression: - discriminant: u8 - data: -``` - -**Discriminants:** -``` -0x01 = NumberLit(i64) // Renamed from IntLit in v0.3.0 -0x02 = DecimalLit(f64) // Renamed from FloatLit in v0.3.0 -0x03 = TextLit(StringRef) // Renamed from StringLit in v0.3.0 -0x04 = BooleanLit(bool) // Renamed from BoolLit in v0.3.0 -0x05 = Identifier(Vec) -0x06 = FieldAccess(Box, StringRef) -0x07 = Comparison(Box, CompOp, Box) -0x08 = Logical(Box, LogicalOp, Box) -0x09 = Unary(UnaryOp, Box) -0x0A = Quantifier(QuantifierKind, StringRef var, Box collection, Box predicate) -``` - -**CompOp:** `u8` (0x01=Eq, 0x02=Ne, 0x03=Lt, 0x04=Le, 0x05=Gt, 0x06=Ge) - -**LogicalOp:** `u8` (0x01=And, 0x02=Or) - -**UnaryOp:** `u8` (0x01=Not, 0x02=Neg) - -**QuantifierKind:** `u8` (0x01=ForAll, 0x02=Exists) - ---- - -## 7. Section 5: Templates - -``` -Count: u32 -Templates: [Template; Count] - -Template: - name: StringRef - species_base: Option // NEW in v0.3.0 - Species base for field inheritance - strict: bool - includes: Vec - fields: Map -``` - -**Species Base (NEW in v0.3.0):** - -When `species_base` is `Some(ref)`, the template inherits fields from the referenced -species as its base layer. The override chain is: - -1. Species fields (base layer) -2. Included template fields (override species) -3. Template's own fields (override includes) -4. Character fields (override template) - -Last-one-wins semantics apply at each layer. Type invariance is enforced: a field's -type cannot change through the inheritance chain (e.g., a Number field in the species -cannot become a Text field in the template). - ---- - -## 8. Section 6: Species - -``` -Count: u32 -Species: [Species; Count] - -Species: - name: StringRef - includes: Vec - fields: Map -``` - ---- - -## 9. Section 7: Behaviors - -### 9.1 Structure - -``` -Count: u32 -Behaviors: [Behavior; Count] -``` - -### 9.2 Behavior Encoding - -``` -Behavior: - name: StringRef - root: BehaviorNode -``` - -### 9.3 BehaviorNode Encoding - -``` -BehaviorNode: - discriminant: u8 - data: -``` - -#### Node Type Discriminants - -``` -0x01 = Selector -0x02 = Sequence -0x03 = Condition -0x04 = Action -0x10 = DecoratorRepeat -0x11 = DecoratorRepeatN -0x12 = DecoratorRepeatRange -0x13 = DecoratorInvert -0x14 = DecoratorRetry -0x15 = DecoratorTimeout -0x16 = DecoratorCooldown -0x17 = DecoratorGuard -0x18 = DecoratorSucceedAlways -0x19 = DecoratorFailAlways -0x20 = SubTree -``` - -#### Selector Node (0x01) - -``` -label: Option // NEW in v0.2.0 -children: Vec -``` - -**Keyword Mapping:** `selector` or `choose` - -#### Sequence Node (0x02) - -``` -label: Option // NEW in v0.2.0 -children: Vec -``` - -**Keyword Mapping:** `sequence` or `then` - -#### Condition Node (0x03) - -``` -expression: Expression -``` - -**Keyword Mapping:** `if` or `when` - -#### Action Node (0x04) - -``` -name: StringRef -parameters: Vec -``` - -**Keyword Mapping:** No prefix (just action name) - -#### Decorator Nodes (0x10-0x19) - -**DecoratorRepeat (0x10):** -``` -child: Box -``` -Keyword: `repeat { ... }` - -**DecoratorRepeatN (0x11):** -``` -count: u32 -child: Box -``` -Keyword: `repeat(N) { ... }` - -**DecoratorRepeatRange (0x12):** -``` -min: u32 -max: u32 -child: Box -``` -Keyword: `repeat(min..max) { ... }` - -**DecoratorInvert (0x13):** -``` -child: Box -``` -Keyword: `invert { ... }` - -**DecoratorRetry (0x14):** -``` -max_attempts: u32 -child: Box -``` -Keyword: `retry(N) { ... }` - -**DecoratorTimeout (0x15):** -``` -milliseconds: u64 // Duration in milliseconds -child: Box -``` -Keyword: `timeout(duration) { ... }` -Example: `timeout(5s)`, `timeout(30m)`, `timeout(2h)` - -**DecoratorCooldown (0x16):** -``` -milliseconds: u64 // Cooldown period in milliseconds -child: Box -``` -Keyword: `cooldown(duration) { ... }` - -**DecoratorIf (0x17):** -``` -condition: Expression -child: Box -``` -Keyword: `if(condition) { ... }` - -**DecoratorSucceedAlways (0x18):** -``` -child: Box -``` -Keyword: `succeed_always { ... }` - -**DecoratorFailAlways (0x19):** -``` -child: Box -``` -Keyword: `fail_always { ... }` - -#### SubTree Node (0x20) - -``` -path: Vec // Qualified path to subtree -``` - -Keyword: `include path::to::subtree` - ---- - -## 10. Section 8: Schedules - -### 10.1 Structure - -``` -Count: u32 -Schedules: [Schedule; Count] -``` - -### 10.2 Schedule Encoding (REDESIGNED in v0.2.0) - -``` -Schedule: - name: StringRef - parent_schedule_id: Option // Index into SCHEDULES section (for inheritance) - blocks: Vec - patterns: Vec // Day-specific, seasonal, recurrence patterns -``` - -### 10.3 ScheduleBlock - -``` -ScheduleBlock: - name: StringRef // Required in v0.2.0 - start: u16 // Minutes since midnight (0-1439) - end: u16 // Minutes since midnight (0-1439) - behavior_ref: Option> // Reference to behavior (qualified path) - fields: Map -``` - -**Changes from v0.1.0:** -- `name` is now required (was optional) -- `behavior_ref` replaces `activity: String` -- Time is encoded as minutes since midnight - -### 10.4 SchedulePattern (NEW in v0.2.0) - -``` -SchedulePattern: - kind: u8 // Pattern discriminant - specification: Vec // Pattern-specific data - blocks: Vec // Blocks to apply when pattern matches -``` - -**Pattern Kind Discriminants:** -``` -0x01 = DayPattern -0x02 = SeasonPattern -0x03 = RecurrencePattern -``` - -#### DayPattern (0x01) - -``` -specification: - day_enum_value: StringRef // References user-defined DayOfWeek enum -``` - -Example: `on Fireday` → references "Fireday" from user's DayOfWeek enum - -#### SeasonPattern (0x02) - -``` -specification: - season_enum_values: Vec // Multiple seasons allowed -``` - -Example: `season (EarlySummer, LateSummer)` → references Season enum values - -#### RecurrencePattern (0x03) - -``` -specification: - name: StringRef // Recurrence name - spec: RecurrenceSpec -``` - -**RecurrenceSpec:** -``` -RecurrenceSpec: - discriminant: u8 - data: - -Discriminants: - 0x01 = Every(u32 days) // every N days - 0x02 = WeeklyOn(Vec) // weekly on [days] - 0x03 = MonthlyOnDay(u8 day) // monthly on day N - 0x04 = Annually(u8 month, u8 day) // annually on month/day -``` - -### 10.5 Runtime Schedule Evaluation - -**Algorithm:** -1. Resolve character's schedule via ScheduleLink (conditional selection) -2. Merge inherited schedules (parent → child, depth-first) -3. Evaluate patterns for current day/season -4. Overlay patterns on base blocks (later patterns override earlier ones) -5. Produce final 24-hour schedule -6. Return ordered list of (time, behavior_ref) pairs - ---- - -## 11. Section 9: Institutions - -### 11.1 Structure (EXTENDED in v0.2.0) - -``` -Count: u32 -Institutions: [Institution; Count] - -Institution: - name: StringRef - fields: Map - behavior_links: Vec // NEW in v0.2.0 - schedule_links: Vec // NEW in v0.2.0 -``` - -**Note:** BehaviorLink and ScheduleLink are identical to Character section (§6.3, §6.4) - ---- - -## 12. Section 10: Relationships - -``` -Count: u32 -Relationships: [Relationship; Count] - -Relationship: - name: StringRef - participants: Vec - fields: Map - -Participant: - role: Option - name: Vec // Qualified path - self_block: Option> - other_block: Option> -``` - ---- - -## 13. Section 11: Locations - -``` -Count: u32 -Locations: [Location; Count] - -Location: - name: StringRef - fields: Map -``` - ---- - -## 14. Section 12: Life Arcs - -``` -Count: u32 -LifeArcs: [LifeArc; Count] - -LifeArc: - name: StringRef - required_fields: Vec // NEW in v0.3.0 - states: Vec - -ArcState: - name: StringRef - on_enter: Option> - transitions: Vec - -Transition: - to: StringRef - condition: Expression -``` - -### 14.1 FieldRequirement (NEW in v0.3.0) - -``` -FieldRequirement: - name: StringRef // Field name - type_name: StringRef // Expected type (e.g., "Number", "Text") -``` - -**Purpose:** Life arcs can declare required fields that any character using the life arc -must have. This enables compile-time validation that characters provide the necessary -fields for state transitions and on_enter actions. - -**Example:** -```storybook -life_arc Career requires { skill_level: Number, title: Text } { - state Junior { ... } - state Senior { ... } -} -``` - -**Binary:** -``` -LifeArc: - name: StringRef("Career") - required_fields: [ - FieldRequirement { name: StringRef("skill_level"), type_name: StringRef("Number") }, - FieldRequirement { name: StringRef("title"), type_name: StringRef("Text") } - ] - states: [...] -``` - ---- - -## 15. Section 13: Enums - -### 15.1 Structure - -``` -Count: u32 -Enums: [EnumDecl; Count] -``` - -### 15.2 EnumDecl Encoding - -``` -EnumDecl: - name: StringRef // u32 index into string table - variants: Vec // Encoded as below -``` - -**Variants encoding (Vec):** -``` -u32 variant_count // Number of enum variants -[StringRef; variant_count] // Array of variant names (each is u32) -``` - -### 15.3 Binary Example - -**Source:** -```storybook -enum SkillLevel { - Novice, - Beginner, - Intermediate, - Advanced, - Expert, - Master -} -``` - -**Binary encoding:** -``` -EnumDecl: - name: StringRef = 42 // "SkillLevel" (4 bytes) - - u32 variant_count = 6 // 6 variants (4 bytes) - variants: - StringRef = 43 // "Novice" (4 bytes) - StringRef = 44 // "Beginner" (4 bytes) - StringRef = 45 // "Intermediate" (4 bytes) - StringRef = 46 // "Advanced" (4 bytes) - StringRef = 47 // "Expert" (4 bytes) - StringRef = 48 // "Master" (4 bytes) - -Total: 32 bytes (4 + 4 + 6*4) -``` - -### 15.4 Usage - -**Usage:** Enums are used for: -- Calendar definitions (DayOfWeek, Season, Month) -- Custom enumerated values -- Pattern matching in schedules - -**Note:** As of v0.3.0, enum-like types can also be defined via `sub_concept` with -enum kind (Section 5.3). The key distinction is that `sub_concept` enums are tied to a -parent concept and participate in the concept type system (concept comparisons, -exhaustiveness checking), while standalone enums in this section are untyped -enumerations used primarily for calendar patterns and simple value sets. - -**Standard Calendar Enums (optional):** -- `DayOfWeek`: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday -- `Season`: Spring, Summer, Fall, Winter -- `Month`: January, February, ..., December - ---- - -## 16. Changelog - -### v0.3.0 (February 2026) - -**Major Features:** -- Type system: concepts, sub-concepts (enum and record kinds), concept comparisons -- Species-based template inheritance with type invariance enforcement -- Life arc field requirements with type annotations -- Value/expression type renames aligned with Storybook language terminology - -**Breaking Changes:** -- TYPES section (Section 3) now populated with concept, sub_concept, and concept_comparison definitions -- Value discriminant names changed: Int→Number, Float→Decimal, String→Text, Bool→Boolean (wire format unchanged) -- Expression discriminant names changed: IntLit→NumberLit, FloatLit→DecimalLit, StringLit→TextLit, BoolLit→BooleanLit (wire format unchanged) -- TEMPLATES section: added `species_base: Option` field before `strict` -- LIFE ARCS section: added `required_fields: Vec` field after `name` - -**Note:** SBIR encoder/decoder implementation is deferred until SaberVM design is finalized. - -### v0.2.0 (February 2026) - -**Major Features:** -- Resource linking system for behaviors and schedules -- Year-long schedule patterns (day, season, recurrence) -- Schedule inheritance and composition -- Behavior tree keyword support (named nodes) -- Parameterized decorators (repeat, retry, timeout, cooldown, if) - -**Breaking Changes:** -- CHARACTERS section: added behavior_links, schedule_links -- INSTITUTIONS section: added behavior_links, schedule_links -- SCHEDULES section: complete redesign with patterns and inheritance -- BEHAVIORS section: added named node support - -**Deprecations:** -- None (first versioned release) - -**Bug Fixes:** -- N/A (first formal release) - -### v0.1.0 (Implicit, Pre-Release) - -**Initial format** (inferred from existing codebase): -- Basic entity storage (characters, templates, species) -- Simple schedules (time blocks with activities) -- Behavior trees (symbolic syntax) -- Relationships, locations, life arcs -- Enum support - ---- - -## Appendix A: Binary Encoding Examples - -### Example 1: Character with Resource Links - -**Source:** -```storybook -character Alice: Human { - age: 7 - - uses behavior: CuriousBehavior, when: self.location == Wonderland, priority: High - uses behavior: DefaultBehavior, default: true - - uses schedule: AdventureSchedule, when: self.in_wonderland - uses schedule: NormalSchedule, default: true -} -``` - -**Binary (conceptual):** -``` -Character: - name: StringRef(0) // "Alice" - species: Some(StringRef(1)) // "Human" - fields: [ - ("age", Number(7)) - ] - template_refs: [] - behavior_links: [ - BehaviorLink { - behavior_id: 3 - priority: 2 // High - condition: Some(Comparison(FieldAccess(...), Eq, Identifier(...))) - is_default: false - }, - BehaviorLink { - behavior_id: 5 - priority: 1 // Normal - condition: None - is_default: true - } - ] - schedule_links: [ - ScheduleLink { - schedule_id: 1 - condition: Some(FieldAccess(...)) - is_default: false - }, - ScheduleLink { - schedule_id: 2 - condition: None - is_default: true - } - ] -``` - -### Example 2: Schedule with Patterns - -**Source:** -```storybook -schedule WorkWeek extends BaseSchedule { - block morning { 08:00 - 12:00: WorkTasks } - block lunch { 12:00 - 13:00: EatLunch } - block afternoon { 13:00 - 17:00: WorkTasks } - - on Friday { - override afternoon { 13:00 - 15:00: FinishWeek } - } - - season (Summer) { - override morning { 07:00 - 11:00: WorkEarly } - } -} -``` - -**Binary (conceptual):** -``` -Schedule: - name: StringRef(10) // "WorkWeek" - parent_schedule_id: Some(0) // BaseSchedule index - blocks: [ - ScheduleBlock { - name: StringRef(11) // "morning" - start: 480 // 08:00 in minutes - end: 720 // 12:00 in minutes - behavior_ref: Some(["WorkTasks"]) - fields: [] - }, - ScheduleBlock { - name: StringRef(12) // "lunch" - start: 720 - end: 780 - behavior_ref: Some(["EatLunch"]) - fields: [] - }, - ScheduleBlock { - name: StringRef(13) // "afternoon" - start: 780 - end: 1020 - behavior_ref: Some(["WorkTasks"]) - fields: [] - } - ] - patterns: [ - SchedulePattern { - kind: 0x01 // DayPattern - specification: StringRef(14) // "Friday" - blocks: [ - ScheduleBlock { - name: StringRef(13) // "afternoon" (override) - start: 780 - end: 900 - behavior_ref: Some(["FinishWeek"]) - fields: [] - } - ] - }, - SchedulePattern { - kind: 0x02 // SeasonPattern - specification: [StringRef(15)] // ["Summer"] - blocks: [ - ScheduleBlock { - name: StringRef(11) // "morning" (override) - start: 420 - end: 660 - behavior_ref: Some(["WorkEarly"]) - fields: [] - } - ] - } - ] -``` - ---- - -## Appendix B: File Size Estimates - -**Assumptions:** -- Average character: 500 bytes -- Average behavior tree: 1 KB -- Average schedule: 800 bytes -- 1000 characters, 500 behaviors, 300 schedules - -**Estimated size:** -- Characters: 500 KB -- Behaviors: 500 KB -- Schedules: 240 KB -- Other sections: 100 KB -- **Total: ~1.34 MB** - -**Compression:** Typical compression (gzip/zstd) achieves 60-70% reduction → ~400-500 KB - ---- - -## Appendix C: Version History - -| Version | Date | Major Changes | -|---------|------|---------------| -| 0.1.0 | (Implicit) | Initial format | -| 0.2.0 | Feb 2026 | Resource linking, year-long schedules, behavior keywords | -| 0.3.0 | Feb 2026 | Type system, species inheritance, life arc requirements | - ---- - -**END OF SPECIFICATION** diff --git a/docs/TYPE-SYSTEM.md b/docs/TYPE-SYSTEM.md index 1b5169c..595182b 100644 --- a/docs/TYPE-SYSTEM.md +++ b/docs/TYPE-SYSTEM.md @@ -1643,7 +1643,7 @@ impl Runtime { **Subtyping (transitive):** ``` -T extends S +T modifies S ─────────────── (SUB-EXTEND) T <: S diff --git a/docs/advanced/20-patterns.md b/docs/advanced/20-patterns.md index e80c87a..84f5d66 100644 --- a/docs/advanced/20-patterns.md +++ b/docs/advanced/20-patterns.md @@ -277,12 +277,12 @@ schedule BaseWorker { block lunch { 12:00 - 13:00, action: social::lunch } } -schedule EarlyBird extends BaseWorker { +schedule EarlyBird modifies BaseWorker { block work { 05:00 - 13:00, action: work::early_shift } block lunch { 11:00 - 12:00, action: social::lunch } } -schedule NightOwl extends BaseWorker { +schedule NightOwl modifies BaseWorker { block work { 14:00 - 22:00, action: work::late_shift } block lunch { 18:00 - 19:00, action: social::dinner } } diff --git a/docs/advanced/23-best-practices.md b/docs/advanced/23-best-practices.md index d554376..29daaf7 100644 --- a/docs/advanced/23-best-practices.md +++ b/docs/advanced/23-best-practices.md @@ -269,7 +269,7 @@ schedule Base { block work { 09:00 - 17:00, action: standard_work } } -schedule Variant extends Base { +schedule Variant modifies Base { block work { 05:00 - 13:00, action: early_work } } ``` diff --git a/docs/book/.nojekyll b/docs/book/.nojekyll deleted file mode 100644 index f173110..0000000 --- a/docs/book/.nojekyll +++ /dev/null @@ -1 +0,0 @@ -This file makes sure that Github Pages doesn't process mdBook's output. diff --git a/docs/book/404.html b/docs/book/404.html deleted file mode 100644 index a3fc7ed..0000000 --- a/docs/book/404.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - Page not found - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Document not found (404)

-

This URL is invalid, sorry. Please use the navigation bar or search to continue.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/FontAwesome/css/font-awesome.css b/docs/book/FontAwesome/css/font-awesome.css deleted file mode 100644 index 540440c..0000000 --- a/docs/book/FontAwesome/css/font-awesome.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/docs/book/FontAwesome/fonts/FontAwesome.ttf b/docs/book/FontAwesome/fonts/FontAwesome.ttf deleted file mode 100644 index 35acda2..0000000 Binary files a/docs/book/FontAwesome/fonts/FontAwesome.ttf and /dev/null differ diff --git a/docs/book/FontAwesome/fonts/fontawesome-webfont.eot b/docs/book/FontAwesome/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca..0000000 Binary files a/docs/book/FontAwesome/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/docs/book/FontAwesome/fonts/fontawesome-webfont.svg b/docs/book/FontAwesome/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845..0000000 --- a/docs/book/FontAwesome/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/book/FontAwesome/fonts/fontawesome-webfont.ttf b/docs/book/FontAwesome/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2..0000000 Binary files a/docs/book/FontAwesome/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/docs/book/FontAwesome/fonts/fontawesome-webfont.woff b/docs/book/FontAwesome/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a..0000000 Binary files a/docs/book/FontAwesome/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/docs/book/FontAwesome/fonts/fontawesome-webfont.woff2 b/docs/book/FontAwesome/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc6..0000000 Binary files a/docs/book/FontAwesome/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/docs/book/_templates/lsp-keyword-template.toml b/docs/book/_templates/lsp-keyword-template.toml deleted file mode 100644 index 59c9691..0000000 --- a/docs/book/_templates/lsp-keyword-template.toml +++ /dev/null @@ -1,65 +0,0 @@ -# LSP Documentation Template for Keywords -# Copy this template for each keyword/declaration/type - -[keyword] -name = "keyword_name" -category = "behavior_tree | declaration | value_type | decorator" -short_description = "One-sentence description (used in completion list)" -web_url = "https://r3t-studios.github.io/storybook/reference/page.html#anchor" - -[syntax] -format = "keyword [optional] { required }" -example = """ -keyword example { - child_element -} -""" - -[hover] -markdown = """ -**`keyword` - Short Name** - -One-sentence description of purpose and behavior. - -**Key behaviors:** -- Behavior 1 -- Behavior 2 -- Behavior 3 - -**Example:** -```storybook -keyword realistic_label { - meaningful_child -} -``` - -**Optional features:** -- Optional labels for debugging -- Optional parameters - -[Learn more →](https://r3t-studios.github.io/storybook/reference/page.html#anchor) -""" - -[completion] -snippet = "keyword ${1:label} {\n\t$0\n}" -description = "Short description for completion dropdown" -sort_text = "01-keyword" # Optional: control sort order -filter_text = "keyword" # Optional: control filtering - -[signature] -# Optional: for keywords that take parameters -label = "keyword(param1: Type, param2: Type)" -parameters = [ - "param1: Type - Description", - "param2: Type - Description" -] - -[context] -# Optional: where this keyword is valid -valid_in = ["behavior_block", "life_arc_block"] -invalid_in = ["character_block"] - -[related] -# Optional: related keywords for cross-reference -keywords = ["related1", "related2"] -concepts = ["concept1", "concept2"] diff --git a/docs/book/advanced/20-patterns.html b/docs/book/advanced/20-patterns.html deleted file mode 100644 index ad0a3da..0000000 --- a/docs/book/advanced/20-patterns.html +++ /dev/null @@ -1,579 +0,0 @@ - - - - - - Design Patterns - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Design Patterns

-

This chapter presents proven patterns for structuring Storybook projects. These patterns have emerged from building complex narrative simulations and represent best practices for maintainability, reuse, and clarity.

-

Behavior Tree Patterns

-

Priority Fallback Chain

-

Use a selector to try increasingly desperate options:

-
behavior Survival {
-    choose survival_priority {
-        then optimal {
-            if(health > 70 and has_supplies)
-            ProceedNormally
-        }
-
-        then cautious {
-            if(health > 30)
-            ProceedCarefully
-        }
-
-        then desperate {
-            if(health > 10)
-            SeekHelp
-        }
-
-        LastResortPanic
-    }
-}
-
-

The tree naturally degrades: first tries the best option, then falls back through progressively worse alternatives.

-

Conditional Behavior Switching

-

Use guards at the top level to switch between behavioral modes:

-
behavior ModeSwitcher {
-    choose mode {
-        if(is_combat_mode) {
-            include CombatBehavior
-        }
-
-        if(is_exploration_mode) {
-            include ExplorationBehavior
-        }
-
-        if(is_social_mode) {
-            include SocialBehavior
-        }
-
-        include IdleBehavior
-    }
-}
-
-

Composite Subtree Pattern

-

Break complex behaviors into focused, reusable subtrees:

-
// Atomic subtrees
-behavior Navigate { then nav { PlanPath, FollowPath } }
-behavior Interact { then talk { Approach, Greet, Converse } }
-behavior Trade { then exchange { ShowGoods, Negotiate, Exchange } }
-
-// Composed behavior
-behavior Merchant_AI {
-    choose activity {
-        then serve_customer {
-            if(customer_present)
-            include Interact
-            include Trade
-        }
-
-        then travel_to_market {
-            if(is_market_day)
-            include Navigate
-        }
-
-        Idle
-    }
-}
-
-

Repeating Patrol with Interrupts

-

Use a repeating patrol that can be interrupted by higher-priority events:

-
character Guard {
-    uses behaviors: [
-        {
-            tree: GuardCombat
-            when: threat_detected
-            priority: high
-        },
-        {
-            tree: GuardPatrol
-            priority: normal
-        }
-    ]
-}
-
-behavior GuardPatrol {
-    repeat {
-        then patrol_loop {
-            MoveTo(destination: "Waypoint1")
-            WaitAndScan(duration: 5s)
-            MoveTo(destination: "Waypoint2")
-            WaitAndScan(duration: 5s)
-        }
-    }
-}
-
-

The combat behavior preempts patrol when threats appear, then patrol resumes.

-

Character Architecture Patterns

-

Species + Templates Composition

-

Use species for identity and templates for capabilities:

-
// Species: What they ARE
-species Human { lifespan: 70 }
-species Elf { lifespan: 1000 }
-
-// Templates: What they HAVE
-template Warrior { strength: 10..20, weapon_skill: 0.5..1.0 }
-template Scholar { intelligence: 15..20, books_read: 50..500 }
-template Leader { charisma: 12..18, followers: 5..50 }
-
-// Characters: Combine both
-character Aragorn: Human from Warrior, Leader {
-    strength: 18
-    charisma: 17
-}
-
-character Elrond: Elf from Scholar, Leader {
-    intelligence: 20
-    charisma: 18
-}
-
-

Strict Templates for Schema Enforcement

-

Use strict templates when you need controlled, uniform entities:

-
template RecipeCard strict {
-    recipe_name: string
-    difficulty: Difficulty
-    prep_time_minutes: 10..180
-}
-
-// This works:
-character SourdoughRecipe from RecipeCard {
-    recipe_name: "Classic Sourdough"
-    difficulty: intermediate
-    prep_time_minutes: 120
-}
-
-// This would error (extra field not allowed):
-// character BadRecipe from RecipeCard {
-//     recipe_name: "Mystery Bread"
-//     difficulty: easy
-//     favorite_color: "blue"  // Error!
-// }
-
-

Template Inheritance Chains

-

Build template hierarchies for progressive specialization:

-
template Worker {
-    skill_level: 0.0..1.0
-    wage: 10..50
-}
-
-template SkilledWorker {
-    include Worker
-    specialization: "general"
-    tool_proficiency: 0.5..1.0
-}
-
-template MasterCraftsman {
-    include SkilledWorker
-    can_teach: true
-    reputation: 0.7..1.0
-}
-
-

Relationship Patterns

-

Bidirectional Perspective

-

Model relationships where each side sees things differently:

-
relationship MentorApprentice {
-    Master as mentor self {
-        patience: 0.7
-        investment_in_student: 0.9
-    } other {
-        sees_potential: 0.8
-        frustration_level: 0.3
-    }
-
-    Student as apprentice self {
-        dedication: 0.8
-        overwhelmed: 0.4
-    } other {
-        respect: 0.95
-        desire_to_impress: 0.9
-    }
-
-    bond: 0.75
-    years_together: 3
-}
-
-

Power Dynamic Pattern

-

Model unequal power relationships explicitly:

-
relationship Vassalage {
-    King as lord self {
-        authority: 1.0
-        grants: "protection"
-    } other {
-        trusts_vassal: 0.6
-    }
-
-    Knight as vassal self {
-        loyalty: 0.9
-        ambition: 0.4
-    } other {
-        respects_lord: 0.8
-        fears_lord: 0.3
-    }
-
-    bond: 0.7
-}
-
-

Relationship Network

-

Build social graphs with multiple overlapping relationships:

-
// Family
-relationship BakerMarriage { Martha as spouse, David as spouse, bond: 0.9 }
-relationship BakerParenting { Martha as parent, Tommy as child, bond: 0.95 }
-
-// Professional
-relationship BakerEmployment { Martha as employer, Elena as employee, bond: 0.8 }
-relationship GuildMembership { Martha as member, BakersGuild as org }
-
-// Social
-relationship BakerFriendship { Martha, Neighbor, bond: 0.6 }
-
-

Schedule Patterns

-

Base Schedule with Specializations

-
schedule BaseWorker {
-    block work { 09:00 - 17:00, action: work::standard }
-    block lunch { 12:00 - 13:00, action: social::lunch }
-}
-
-schedule EarlyBird extends BaseWorker {
-    block work { 05:00 - 13:00, action: work::early_shift }
-    block lunch { 11:00 - 12:00, action: social::lunch }
-}
-
-schedule NightOwl extends BaseWorker {
-    block work { 14:00 - 22:00, action: work::late_shift }
-    block lunch { 18:00 - 19:00, action: social::dinner }
-}
-
-

Seasonal Variation

-
schedule FarmSchedule {
-    block spring_work {
-        06:00 - 18:00
-        action: farming::plant
-        on season spring
-    }
-
-    block summer_work {
-        05:00 - 20:00
-        action: farming::tend
-        on season summer
-    }
-
-    block fall_work {
-        06:00 - 20:00
-        action: farming::harvest
-        on season fall
-    }
-
-    block winter_work {
-        08:00 - 16:00
-        action: farming::maintain
-        on season winter
-    }
-}
-
-

Life Arc Patterns

-

Progressive Development

-
life_arc CareerProgression {
-    state novice {
-        on enter { Character.title: "Apprentice" }
-        on experience > 100 -> intermediate
-    }
-
-    state intermediate {
-        on enter { Character.title: "Journeyman" }
-        on experience > 500 -> expert
-    }
-
-    state expert {
-        on enter { Character.title: "Master", Character.can_teach: true }
-    }
-}
-
-

Emotional State Machine

-
life_arc MoodSystem {
-    state neutral {
-        on provoked -> angry
-        on complimented -> happy
-        on tired -> sleepy
-    }
-
-    state angry {
-        on enter { Character.aggression: 0.9 }
-        on calmed_down -> neutral
-        on escalated -> furious
-    }
-
-    state furious {
-        on enter { Character.aggression: 1.0 }
-        on timeout_elapsed -> angry
-    }
-
-    state happy {
-        on enter { Character.gives_discounts: true }
-        on insulted -> neutral
-    }
-
-    state sleepy {
-        on enter { Character.responsiveness: 0.2 }
-        on woke_up -> neutral
-    }
-}
-
-

Project Organization Patterns

-

Schema / World Separation

-

Keep type definitions separate from instance data:

-
my-project/
-  schema/           # Types and templates (reusable)
-    core_enums.sb
-    templates.sb
-    beings.sb
-  world/            # Instances (specific to this story)
-    characters/
-    behaviors/
-    relationships/
-    locations/
-
-

Module per Domain

-

Group related declarations together:

-
world/
-  characters/
-    heroes.sb       # All hero characters
-    villains.sb     # All villain characters
-    npcs.sb         # Background characters
-  behaviors/
-    combat.sb       # Combat behaviors
-    social.sb       # Social behaviors
-    exploration.sb  # Exploration behaviors
-
-

Anti-Patterns to Avoid

-

Deep nesting: More than 4-5 levels of behavior tree nesting is hard to read. Use include to flatten.

-

God behaviors: One massive behavior tree doing everything. Break it into focused subtrees.

-

Deep species hierarchies: More than 2-3 levels of species includes is rarely needed. Use templates for variation.

-

Duplicated logic: If two behaviors share logic, extract it into a shared subtree.

-

Unnamed nodes: Always label composite nodes in behavior trees for readability.

-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/advanced/21-sbir-format.html b/docs/book/advanced/21-sbir-format.html deleted file mode 100644 index a5f373a..0000000 --- a/docs/book/advanced/21-sbir-format.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - The SBIR Binary Format - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

The SBIR Binary Format

-

SBIR (Storybook Intermediate Representation) is the compiled binary format produced by the Storybook compiler. It transforms human-readable .sb files into an optimized, machine-consumable format for simulation runtimes.

-

Compilation Pipeline

-
.sb files → Lexer → Parser → AST → Resolver → SBIR Binary
-
-
    -
  1. Lexer: Tokenizes raw text into tokens
  2. -
  3. Parser: Builds an Abstract Syntax Tree (AST) from tokens
  4. -
  5. Resolver: Validates, resolves cross-references, merges templates, and produces SBIR
  6. -
-

What SBIR Contains

-

SBIR represents the fully resolved state of a Storybook project:

-
    -
  • Characters: All fields resolved (species + templates merged, overrides applied)
  • -
  • Behaviors: Behavior trees with all subtree references inlined
  • -
  • Life Arcs: State machines with validated transitions
  • -
  • Schedules: Time blocks with resolved action references
  • -
  • Relationships: Participants with resolved entity references
  • -
  • Institutions: Fully resolved field sets
  • -
  • Locations: Fully resolved field sets
  • -
  • Species: Fully resolved inheritance chains
  • -
  • Enums: Complete variant lists
  • -
-

Resolution Process

-

Template Merging

-

When a character uses templates, SBIR contains the fully merged result:

-

Source:

-
species Human { lifespan: 70, speed: 1.0 }
-template Warrior { speed: 1.5, strength: 10 }
-
-character Conan: Human from Warrior {
-    strength: 20
-}
-
-

In SBIR, Conan’s fields are:

-
    -
  • lifespan: 70 (from Human)
  • -
  • speed: 1.5 (Warrior overrides Human)
  • -
  • strength: 20 (Conan overrides Warrior)
  • -
-

Cross-File Reference Resolution

-

SBIR resolves all use statements and qualified paths. A relationship referencing Martha in a different file is resolved to the concrete character definition.

-

Validation

-

Before producing SBIR, the resolver validates all constraints documented in Validation Rules:

-
    -
  • All references resolve to defined declarations
  • -
  • No circular dependencies
  • -
  • Type consistency
  • -
  • Domain constraints (bond ranges, schedule validity)
  • -
-

Design Goals

-

Compact: SBIR strips comments, whitespace, and redundant structure.

-

Self-contained: No external references – everything is resolved and inlined.

-

Fast to load: Simulation runtimes can load SBIR without re-parsing or re-resolving.

-

Validated: If SBIR was produced, the source was valid. Runtimes do not need to re-validate.

-

Usage

-

SBIR is consumed by simulation runtimes that drive character behavior, schedule execution, life arc transitions, and relationship queries. The specific binary format is implementation-defined and may evolve between versions.

-

For the current SBIR specification, see the SBIR v0.2.0 Spec.

-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/advanced/22-integration.html b/docs/book/advanced/22-integration.html deleted file mode 100644 index 6e4966a..0000000 --- a/docs/book/advanced/22-integration.html +++ /dev/null @@ -1,361 +0,0 @@ - - - - - - Integration Guide - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Integration Guide

-

This chapter covers how to integrate Storybook into larger systems – game engines, simulation frameworks, and custom applications.

-

Architecture Overview

-

Storybook operates in two phases:

-
    -
  1. Compile time: .sb files are parsed, validated, and compiled into SBIR
  2. -
  3. Runtime: A simulation engine consumes SBIR and drives character behavior
  4. -
-
                    Compile Time                    Runtime
-.sb files → [Storybook Compiler] → SBIR → [Simulation Engine] → Character Actions
-
-

The Storybook Compiler

-

The compiler is a Rust library and CLI tool that processes .sb files.

-

CLI Usage

-
# Compile a directory of .sb files
-storybook compile path/to/project/
-
-# Compile with output path
-storybook compile path/to/project/ -o output.sbir
-
-# Validate without producing output
-storybook check path/to/project/
-
-

As a Library

-

The compiler can be embedded as a Rust dependency:

-
#![allow(unused)]
-fn main() {
-use storybook::syntax::parse_file;
-use storybook::resolve::resolve_files;
-
-// Parse .sb files into ASTs
-let ast = parse_file(source_code)?;
-
-// Resolve across multiple files
-let resolved = resolve_files(vec![ast1, ast2, ast3])?;
-
-// Access resolved data
-for character in resolved.characters() {
-    println!("{}: {:?}", character.name, character.fields);
-}
-}
-

Key Types

-

The resolved output provides these primary types:

-
- - - - - - - - - - -
TypeDescription
ResolvedFileContainer for all resolved declarations
ResolvedCharacterCharacter with merged species/template fields
ResolvedBehaviorBehavior tree with resolved subtree references
ResolvedLifeArcState machine with validated transitions
ResolvedScheduleSchedule with resolved time blocks
ResolvedRelationshipRelationship with resolved participant references
ResolvedInstitutionInstitution with resolved fields
ResolvedLocationLocation with resolved fields
ResolvedSpeciesSpecies with resolved includes chain
ResolvedEnumEnum with variant list
-
-

Runtime Integration

-

Behavior Tree Execution

-

Runtimes are responsible for:

-
    -
  1. Tick-based evaluation: Call the behavior tree root each frame/tick
  2. -
  3. Action execution: Interpret action nodes (e.g., MoveTo, Attack)
  4. -
  5. Condition evaluation: Evaluate expression nodes against current state
  6. -
  7. Decorator state: Maintain timer/counter state for stateful decorators
  8. -
-

Life Arc Execution

-
    -
  1. Track the current state for each life arc instance
  2. -
  3. Evaluate transition conditions each tick
  4. -
  5. Execute on-enter actions when transitioning
  6. -
  7. Maintain state persistence across ticks
  8. -
-

Schedule Execution

-
    -
  1. Get the current simulation time
  2. -
  3. Find the matching schedule block (considering temporal constraints and recurrences)
  4. -
  5. Execute the associated behavior tree action
  6. -
-

Relationship Queries

-

Provide APIs for querying the relationship graph:

-
    -
  • Find all relationships for a character
  • -
  • Get bond strength between two entities
  • -
  • Query perspective fields (self/other)
  • -
-

LSP Integration

-

Storybook includes a Language Server Protocol (LSP) implementation for editor support:

-
    -
  • Hover information: Documentation for keywords and declarations
  • -
  • Go to definition: Navigate to declaration sources
  • -
  • Diagnostics: Real-time error reporting
  • -
  • Completions: Context-aware suggestions
  • -
-

The LSP server reuses the compiler’s parser and resolver, providing the same validation as the CLI.

-

Editor Setup

-

The Storybook LSP works with any editor that supports LSP:

-
    -
  • VS Code: Via the Storybook extension
  • -
  • Zed: Via the zed-storybook extension
  • -
  • Other editors: Any LSP-compatible editor
  • -
-

Tree-sitter Grammar

-

A Tree-sitter grammar is provided for syntax highlighting and structural queries:

-
tree-sitter-storybook/
-  grammar.js          # Grammar definition
-  src/                # Generated parser
-
-

The Tree-sitter grammar supports:

-
    -
  • Syntax highlighting in editors
  • -
  • Structural code queries
  • -
  • Incremental parsing for large files
  • -
-

File Organization for Integration

-

Organize your project to support both authoring and runtime consumption:

-
my-game/
-  storybook/              # Storybook source files
-    schema/
-      core_enums.sb
-      templates.sb
-      beings.sb
-    world/
-      characters/
-      behaviors/
-      relationships/
-  assets/
-    narrative.sbir        # Compiled output for runtime
-  src/
-    narrative_engine.rs   # Runtime that consumes SBIR
-
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/advanced/23-best-practices.html b/docs/book/advanced/23-best-practices.html deleted file mode 100644 index 56c5a1d..0000000 --- a/docs/book/advanced/23-best-practices.html +++ /dev/null @@ -1,499 +0,0 @@ - - - - - - Best Practices - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Best Practices

-

This chapter compiles best practices for writing clear, maintainable, and effective Storybook code. These guidelines apply across all declaration types and project sizes.

-

Naming Conventions

-

Declarations

-

Use PascalCase for all declaration names:

-
character MasterBaker { }          // Good
-species DomesticCat { }            // Good
-behavior GuardPatrol { }           // Good
-
-character master_baker { }         // Avoid
-behavior guard-patrol { }         // Invalid (no hyphens)
-
-

Fields

-

Use snake_case for field names:

-
character Martha {
-    skill_level: 0.95            // Good
-    emotional_state: focused     // Good
-    years_experience: 22         // Good
-
-    skillLevel: 0.95             // Avoid (camelCase)
-}
-
-

Behavior Tree Labels

-

Use snake_case for node labels, with descriptive names:

-
choose survival_instinct {       // Good
-    then fight_response { }      // Good
-    then flight_response { }     // Good
-}
-
-choose s1 {                      // Avoid (meaningless)
-    then a { }                   // Avoid
-}
-
-

Enum Variants

-

Use PascalCase or snake_case consistently within an enum:

-
// PascalCase (good for short names)
-enum Size { Tiny, Small, Normal, Large, Huge }
-
-// snake_case (good for compound names)
-enum GovernmentStyle {
-    absolute_tyranny,
-    constitutional_monarchy,
-    direct_democracy
-}
-
-

File Organization

-

Separate Schema from World

-

Keep reusable type definitions separate from instance data:

-
project/
-  schema/           # Reusable across stories
-    core_enums.sb   # Enum definitions
-    templates.sb    # Template definitions
-    beings.sb       # Species definitions
-  world/            # Specific to this story
-    characters/     # Character instances
-    behaviors/      # Behavior trees
-    relationships/  # Relationship instances
-    locations/      # Location instances
-
-

One Concern per File

-

Group related declarations, but avoid putting unrelated things together:

-
// characters/bakery_staff.sb - Good: related characters together
-character Martha { }
-character Jane { }
-character Elena { }
-
-// everything.sb - Avoid: everything in one file
-character Martha { }
-behavior BakeRoutine { }
-schedule DailyRoutine { }
-relationship Partnership { }
-
-

Explicit Imports

-

Prefer explicit imports over wildcards:

-
// Good: clear what is being used
-use schema::core_enums::{SkillLevel, Specialty};
-use schema::beings::Human;
-
-// Avoid: unclear dependencies
-use schema::core_enums::*;
-use schema::beings::*;
-
-

Character Design

-

Use Species for Identity, Templates for Traits

-
// Species: ontological identity
-species Human { lifespan: 70 }
-
-// Templates: compositional traits
-template Warrior { strength: 10..20 }
-template Scholar { intelligence: 15..20 }
-
-// Character: combines identity and traits
-character Aragorn: Human from Warrior {
-    strength: 18
-}
-
-

Document with Prose Blocks

-
character Martha: Human {
-    age: 34
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at
-    age twelve. She now runs the most popular bakery in town.
-    ---
-
-    ---personality
-    Meticulous and patient, with an unwavering commitment to
-    quality. Tough but fair with her staff.
-    ---
-}
-
-

Prefer Flat Inheritance

-

Avoid deep species hierarchies. Two or three levels is usually enough:

-
// Good: shallow
-species Mammal { warm_blooded: true }
-species Human includes Mammal { sapient: true }
-
-// Avoid: too deep
-species Being { }
-species LivingBeing includes Being { }
-species Animal includes LivingBeing { }
-species Vertebrate includes Animal { }
-species Mammal includes Vertebrate { }
-species Human includes Mammal { }
-
-

Behavior Tree Design

-

Name Every Composite Node

-
// Good: self-documenting
-choose daily_priority {
-    then handle_emergency { }
-    then do_work { }
-    then relax { }
-}
-
-// Avoid: anonymous nodes
-choose {
-    then { }
-    then { }
-}
-
-

Keep Trees Shallow

-

Extract deep subtrees into separate behaviors:

-
// Good: flat with includes
-behavior Main {
-    choose mode {
-        include CombatBehavior
-        include ExplorationBehavior
-        include SocialBehavior
-    }
-}
-
-// Avoid: deeply nested
-behavior Main {
-    choose {
-        then { choose { then { choose { then { Action } } } } }
-    }
-}
-
-

Use Decorators for Control Flow

-
// Good: decorator handles timing
-cooldown(30s) { CastSpell }
-timeout(10s) { SolvePuzzle }
-retry(3) { PickLock }
-
-// Avoid: manual timing in actions
-CheckCooldownTimer
-IfCooldownReady { CastSpell }
-
-

Expression Writing

-

Use Parentheses for Clarity

-
// Good: explicit grouping
-on (health < 50 or is_poisoned) and has_antidote -> healing
-
-// Risky: relies on precedence knowledge
-on health < 50 or is_poisoned and has_antidote -> healing
-
-

Break Complex Conditions into Multiple Transitions

-
// Good: separate transitions, easy to read
-state combat {
-    on health < 20 and not has_potion -> desperate
-    on surrounded and not has_escape -> desperate
-    on enemy_count > 10 -> desperate
-}
-
-// Avoid: one massive condition
-state combat {
-    on (health < 20 and not has_potion) or (surrounded and not has_escape) or enemy_count > 10 -> desperate
-}
-
-

Use is for Enum Comparisons

-
// Good: reads naturally
-on status is active -> active_state
-on skill_level is master -> teach_others
-
-// Works but less readable
-on status == active -> active_state
-
-

Schedule Design

-

Use Named Blocks for Override Support

-
// Good: named blocks can be overridden
-schedule Base {
-    block work { 09:00 - 17:00, action: standard_work }
-}
-
-schedule Variant extends Base {
-    block work { 05:00 - 13:00, action: early_work }
-}
-
- -
schedule DailyRoutine {
-    // Morning
-    block wake { 06:00 - 07:00, action: morning_routine }
-    block breakfast { 07:00 - 08:00, action: eat }
-
-    // Work
-    block commute { 08:00 - 09:00, action: travel }
-    block work { 09:00 - 17:00, action: work }
-
-    // Evening
-    block leisure { 18:00 - 22:00, action: relax }
-    block sleep { 22:00 - 06:00, action: sleep }
-}
-
-

Relationship Design

-

Use Roles for Clarity

-
// Good: roles clarify the relationship
-relationship Marriage {
-    Martha as spouse
-    David as spouse
-    bond: 0.9
-}
-
-// Less clear without roles
-relationship Marriage {
-    Martha
-    David
-    bond: 0.9
-}
-
-

Use Perspectives for Asymmetry

-
// Good: captures different viewpoints
-relationship TeacherStudent {
-    Gandalf as teacher self { patience: 0.8 } other { potential: 0.9 }
-    Frodo as student self { motivation: 0.7 } other { admiration: 0.95 }
-    bond: 0.85
-}
-
-

General Principles

-
    -
  1. -

    Readability over brevity: Storybook code should read like a narrative, not a puzzle.

    -
  2. -
  3. -

    Explicit over implicit: Say what you mean. Use named nodes, explicit imports, and clear field names.

    -
  4. -
  5. -

    Flat over deep: Shallow hierarchies, short behavior trees, and focused files are easier to maintain.

    -
  6. -
  7. -

    Composition over inheritance: Prefer combining templates over building deep species hierarchies.

    -
  8. -
  9. -

    Document with prose: Prose blocks are a feature, not clutter. Use them to explain intent alongside data.

    -
  10. -
  11. -

    One concept per declaration: Each behavior tree, life arc, or schedule should have a single clear purpose.

    -
  12. -
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/ayu-highlight.css b/docs/book/ayu-highlight.css deleted file mode 100644 index 32c9432..0000000 --- a/docs/book/ayu-highlight.css +++ /dev/null @@ -1,78 +0,0 @@ -/* -Based off of the Ayu theme -Original by Dempfi (https://github.com/dempfi/ayu) -*/ - -.hljs { - display: block; - overflow-x: auto; - background: #191f26; - color: #e6e1cf; -} - -.hljs-comment, -.hljs-quote { - color: #5c6773; - font-style: italic; -} - -.hljs-variable, -.hljs-template-variable, -.hljs-attribute, -.hljs-attr, -.hljs-regexp, -.hljs-link, -.hljs-selector-id, -.hljs-selector-class { - color: #ff7733; -} - -.hljs-number, -.hljs-meta, -.hljs-builtin-name, -.hljs-literal, -.hljs-type, -.hljs-params { - color: #ffee99; -} - -.hljs-string, -.hljs-bullet { - color: #b8cc52; -} - -.hljs-title, -.hljs-built_in, -.hljs-section { - color: #ffb454; -} - -.hljs-keyword, -.hljs-selector-tag, -.hljs-symbol { - color: #ff7733; -} - -.hljs-name { - color: #36a3d9; -} - -.hljs-tag { - color: #00568d; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} - -.hljs-addition { - color: #91b362; -} - -.hljs-deletion { - color: #d96c75; -} diff --git a/docs/book/book.js b/docs/book/book.js deleted file mode 100644 index 178f1e9..0000000 --- a/docs/book/book.js +++ /dev/null @@ -1,690 +0,0 @@ -"use strict"; - -// Fix back button cache problem -window.onunload = function () { }; - -// Global variable, shared between modules -function playground_text(playground, hidden = true) { - let code_block = playground.querySelector("code"); - - if (window.ace && code_block.classList.contains("editable")) { - let editor = window.ace.edit(code_block); - return editor.getValue(); - } else if (hidden) { - return code_block.textContent; - } else { - return code_block.innerText; - } -} - -(function codeSnippets() { - function fetch_with_timeout(url, options, timeout = 6000) { - return Promise.race([ - fetch(url, options), - new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) - ]); - } - - var playgrounds = Array.from(document.querySelectorAll(".playground")); - if (playgrounds.length > 0) { - fetch_with_timeout("https://play.rust-lang.org/meta/crates", { - headers: { - 'Content-Type': "application/json", - }, - method: 'POST', - mode: 'cors', - }) - .then(response => response.json()) - .then(response => { - // get list of crates available in the rust playground - let playground_crates = response.crates.map(item => item["id"]); - playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); - }); - } - - function handle_crate_list_update(playground_block, playground_crates) { - // update the play buttons after receiving the response - update_play_button(playground_block, playground_crates); - - // and install on change listener to dynamically update ACE editors - if (window.ace) { - let code_block = playground_block.querySelector("code"); - if (code_block.classList.contains("editable")) { - let editor = window.ace.edit(code_block); - editor.addEventListener("change", function (e) { - update_play_button(playground_block, playground_crates); - }); - // add Ctrl-Enter command to execute rust code - editor.commands.addCommand({ - name: "run", - bindKey: { - win: "Ctrl-Enter", - mac: "Ctrl-Enter" - }, - exec: _editor => run_rust_code(playground_block) - }); - } - } - } - - // updates the visibility of play button based on `no_run` class and - // used crates vs ones available on https://play.rust-lang.org - function update_play_button(pre_block, playground_crates) { - var play_button = pre_block.querySelector(".play-button"); - - // skip if code is `no_run` - if (pre_block.querySelector('code').classList.contains("no_run")) { - play_button.classList.add("hidden"); - return; - } - - // get list of `extern crate`'s from snippet - var txt = playground_text(pre_block); - var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; - var snippet_crates = []; - var item; - while (item = re.exec(txt)) { - snippet_crates.push(item[1]); - } - - // check if all used crates are available on play.rust-lang.org - var all_available = snippet_crates.every(function (elem) { - return playground_crates.indexOf(elem) > -1; - }); - - if (all_available) { - play_button.classList.remove("hidden"); - } else { - play_button.classList.add("hidden"); - } - } - - function run_rust_code(code_block) { - var result_block = code_block.querySelector(".result"); - if (!result_block) { - result_block = document.createElement('code'); - result_block.className = 'result hljs language-bash'; - - code_block.append(result_block); - } - - let text = playground_text(code_block); - let classes = code_block.querySelector('code').classList; - let edition = "2015"; - if(classes.contains("edition2018")) { - edition = "2018"; - } else if(classes.contains("edition2021")) { - edition = "2021"; - } - var params = { - version: "stable", - optimize: "0", - code: text, - edition: edition - }; - - if (text.indexOf("#![feature") !== -1) { - params.version = "nightly"; - } - - result_block.innerText = "Running..."; - - fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { - headers: { - 'Content-Type': "application/json", - }, - method: 'POST', - mode: 'cors', - body: JSON.stringify(params) - }) - .then(response => response.json()) - .then(response => { - if (response.result.trim() === '') { - result_block.innerText = "No output"; - result_block.classList.add("result-no-output"); - } else { - result_block.innerText = response.result; - result_block.classList.remove("result-no-output"); - } - }) - .catch(error => result_block.innerText = "Playground Communication: " + error.message); - } - - // Syntax highlighting Configuration - hljs.configure({ - tabReplace: ' ', // 4 spaces - languages: [], // Languages used for auto-detection - }); - - let code_nodes = Array - .from(document.querySelectorAll('code')) - // Don't highlight `inline code` blocks in headers. - .filter(function (node) {return !node.parentElement.classList.contains("header"); }); - - if (window.ace) { - // language-rust class needs to be removed for editable - // blocks or highlightjs will capture events - code_nodes - .filter(function (node) {return node.classList.contains("editable"); }) - .forEach(function (block) { block.classList.remove('language-rust'); }); - - code_nodes - .filter(function (node) {return !node.classList.contains("editable"); }) - .forEach(function (block) { hljs.highlightBlock(block); }); - } else { - code_nodes.forEach(function (block) { hljs.highlightBlock(block); }); - } - - // Adding the hljs class gives code blocks the color css - // even if highlighting doesn't apply - code_nodes.forEach(function (block) { block.classList.add('hljs'); }); - - Array.from(document.querySelectorAll("code.hljs")).forEach(function (block) { - - var lines = Array.from(block.querySelectorAll('.boring')); - // If no lines were hidden, return - if (!lines.length) { return; } - block.classList.add("hide-boring"); - - var buttons = document.createElement('div'); - buttons.className = 'buttons'; - buttons.innerHTML = ""; - - // add expand button - var pre_block = block.parentNode; - pre_block.insertBefore(buttons, pre_block.firstChild); - - pre_block.querySelector('.buttons').addEventListener('click', function (e) { - if (e.target.classList.contains('fa-eye')) { - e.target.classList.remove('fa-eye'); - e.target.classList.add('fa-eye-slash'); - e.target.title = 'Hide lines'; - e.target.setAttribute('aria-label', e.target.title); - - block.classList.remove('hide-boring'); - } else if (e.target.classList.contains('fa-eye-slash')) { - e.target.classList.remove('fa-eye-slash'); - e.target.classList.add('fa-eye'); - e.target.title = 'Show hidden lines'; - e.target.setAttribute('aria-label', e.target.title); - - block.classList.add('hide-boring'); - } - }); - }); - - if (window.playground_copyable) { - Array.from(document.querySelectorAll('pre code')).forEach(function (block) { - var pre_block = block.parentNode; - if (!pre_block.classList.contains('playground')) { - var buttons = pre_block.querySelector(".buttons"); - if (!buttons) { - buttons = document.createElement('div'); - buttons.className = 'buttons'; - pre_block.insertBefore(buttons, pre_block.firstChild); - } - - var clipButton = document.createElement('button'); - clipButton.className = 'clip-button'; - clipButton.title = 'Copy to clipboard'; - clipButton.setAttribute('aria-label', clipButton.title); - clipButton.innerHTML = ''; - - buttons.insertBefore(clipButton, buttons.firstChild); - } - }); - } - - // Process playground code blocks - Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { - // Add play button - var buttons = pre_block.querySelector(".buttons"); - if (!buttons) { - buttons = document.createElement('div'); - buttons.className = 'buttons'; - pre_block.insertBefore(buttons, pre_block.firstChild); - } - - var runCodeButton = document.createElement('button'); - runCodeButton.className = 'fa fa-play play-button'; - runCodeButton.hidden = true; - runCodeButton.title = 'Run this code'; - runCodeButton.setAttribute('aria-label', runCodeButton.title); - - buttons.insertBefore(runCodeButton, buttons.firstChild); - runCodeButton.addEventListener('click', function (e) { - run_rust_code(pre_block); - }); - - if (window.playground_copyable) { - var copyCodeClipboardButton = document.createElement('button'); - copyCodeClipboardButton.className = 'clip-button'; - copyCodeClipboardButton.innerHTML = ''; - copyCodeClipboardButton.title = 'Copy to clipboard'; - copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title); - - buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild); - } - - let code_block = pre_block.querySelector("code"); - if (window.ace && code_block.classList.contains("editable")) { - var undoChangesButton = document.createElement('button'); - undoChangesButton.className = 'fa fa-history reset-button'; - undoChangesButton.title = 'Undo changes'; - undoChangesButton.setAttribute('aria-label', undoChangesButton.title); - - buttons.insertBefore(undoChangesButton, buttons.firstChild); - - undoChangesButton.addEventListener('click', function () { - let editor = window.ace.edit(code_block); - editor.setValue(editor.originalCode); - editor.clearSelection(); - }); - } - }); -})(); - -(function themes() { - var html = document.querySelector('html'); - var themeToggleButton = document.getElementById('theme-toggle'); - var themePopup = document.getElementById('theme-list'); - var themeColorMetaTag = document.querySelector('meta[name="theme-color"]'); - var themeIds = []; - themePopup.querySelectorAll('button.theme').forEach(function (el) { - themeIds.push(el.id); - }); - var stylesheets = { - ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"), - tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"), - highlight: document.querySelector("[href$='highlight.css']"), - }; - - function showThemes() { - themePopup.style.display = 'block'; - themeToggleButton.setAttribute('aria-expanded', true); - themePopup.querySelector("button#" + get_theme()).focus(); - } - - function updateThemeSelected() { - themePopup.querySelectorAll('.theme-selected').forEach(function (el) { - el.classList.remove('theme-selected'); - }); - themePopup.querySelector("button#" + get_theme()).classList.add('theme-selected'); - } - - function hideThemes() { - themePopup.style.display = 'none'; - themeToggleButton.setAttribute('aria-expanded', false); - themeToggleButton.focus(); - } - - function get_theme() { - var theme; - try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { } - if (theme === null || theme === undefined || !themeIds.includes(theme)) { - return default_theme; - } else { - return theme; - } - } - - function set_theme(theme, store = true) { - let ace_theme; - - if (theme == 'coal' || theme == 'navy') { - stylesheets.ayuHighlight.disabled = true; - stylesheets.tomorrowNight.disabled = false; - stylesheets.highlight.disabled = true; - - ace_theme = "ace/theme/tomorrow_night"; - } else if (theme == 'ayu') { - stylesheets.ayuHighlight.disabled = false; - stylesheets.tomorrowNight.disabled = true; - stylesheets.highlight.disabled = true; - ace_theme = "ace/theme/tomorrow_night"; - } else { - stylesheets.ayuHighlight.disabled = true; - stylesheets.tomorrowNight.disabled = true; - stylesheets.highlight.disabled = false; - ace_theme = "ace/theme/dawn"; - } - - setTimeout(function () { - themeColorMetaTag.content = getComputedStyle(document.documentElement).backgroundColor; - }, 1); - - if (window.ace && window.editors) { - window.editors.forEach(function (editor) { - editor.setTheme(ace_theme); - }); - } - - var previousTheme = get_theme(); - - if (store) { - try { localStorage.setItem('mdbook-theme', theme); } catch (e) { } - } - - html.classList.remove(previousTheme); - html.classList.add(theme); - updateThemeSelected(); - } - - // Set theme - var theme = get_theme(); - - set_theme(theme, false); - - themeToggleButton.addEventListener('click', function () { - if (themePopup.style.display === 'block') { - hideThemes(); - } else { - showThemes(); - } - }); - - themePopup.addEventListener('click', function (e) { - var theme; - if (e.target.className === "theme") { - theme = e.target.id; - } else if (e.target.parentElement.className === "theme") { - theme = e.target.parentElement.id; - } else { - return; - } - set_theme(theme); - }); - - themePopup.addEventListener('focusout', function(e) { - // e.relatedTarget is null in Safari and Firefox on macOS (see workaround below) - if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) { - hideThemes(); - } - }); - - // Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628 - document.addEventListener('click', function(e) { - if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) { - hideThemes(); - } - }); - - document.addEventListener('keydown', function (e) { - if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } - if (!themePopup.contains(e.target)) { return; } - - switch (e.key) { - case 'Escape': - e.preventDefault(); - hideThemes(); - break; - case 'ArrowUp': - e.preventDefault(); - var li = document.activeElement.parentElement; - if (li && li.previousElementSibling) { - li.previousElementSibling.querySelector('button').focus(); - } - break; - case 'ArrowDown': - e.preventDefault(); - var li = document.activeElement.parentElement; - if (li && li.nextElementSibling) { - li.nextElementSibling.querySelector('button').focus(); - } - break; - case 'Home': - e.preventDefault(); - themePopup.querySelector('li:first-child button').focus(); - break; - case 'End': - e.preventDefault(); - themePopup.querySelector('li:last-child button').focus(); - break; - } - }); -})(); - -(function sidebar() { - var body = document.querySelector("body"); - var sidebar = document.getElementById("sidebar"); - var sidebarLinks = document.querySelectorAll('#sidebar a'); - var sidebarToggleButton = document.getElementById("sidebar-toggle"); - var sidebarResizeHandle = document.getElementById("sidebar-resize-handle"); - var firstContact = null; - - function showSidebar() { - body.classList.remove('sidebar-hidden') - body.classList.add('sidebar-visible'); - Array.from(sidebarLinks).forEach(function (link) { - link.setAttribute('tabIndex', 0); - }); - sidebarToggleButton.setAttribute('aria-expanded', true); - sidebar.setAttribute('aria-hidden', false); - try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { } - } - - function hideSidebar() { - body.classList.remove('sidebar-visible') - body.classList.add('sidebar-hidden'); - Array.from(sidebarLinks).forEach(function (link) { - link.setAttribute('tabIndex', -1); - }); - sidebarToggleButton.setAttribute('aria-expanded', false); - sidebar.setAttribute('aria-hidden', true); - try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { } - } - - // Toggle sidebar - sidebarToggleButton.addEventListener('click', function sidebarToggle() { - if (body.classList.contains("sidebar-hidden")) { - var current_width = parseInt( - document.documentElement.style.getPropertyValue('--sidebar-width'), 10); - if (current_width < 150) { - document.documentElement.style.setProperty('--sidebar-width', '150px'); - } - showSidebar(); - } else if (body.classList.contains("sidebar-visible")) { - hideSidebar(); - } else { - if (getComputedStyle(sidebar)['transform'] === 'none') { - hideSidebar(); - } else { - showSidebar(); - } - } - }); - - sidebarResizeHandle.addEventListener('mousedown', initResize, false); - - function initResize(e) { - window.addEventListener('mousemove', resize, false); - window.addEventListener('mouseup', stopResize, false); - body.classList.add('sidebar-resizing'); - } - function resize(e) { - var pos = (e.clientX - sidebar.offsetLeft); - if (pos < 20) { - hideSidebar(); - } else { - if (body.classList.contains("sidebar-hidden")) { - showSidebar(); - } - pos = Math.min(pos, window.innerWidth - 100); - document.documentElement.style.setProperty('--sidebar-width', pos + 'px'); - } - } - //on mouseup remove windows functions mousemove & mouseup - function stopResize(e) { - body.classList.remove('sidebar-resizing'); - window.removeEventListener('mousemove', resize, false); - window.removeEventListener('mouseup', stopResize, false); - } - - document.addEventListener('touchstart', function (e) { - firstContact = { - x: e.touches[0].clientX, - time: Date.now() - }; - }, { passive: true }); - - document.addEventListener('touchmove', function (e) { - if (!firstContact) - return; - - var curX = e.touches[0].clientX; - var xDiff = curX - firstContact.x, - tDiff = Date.now() - firstContact.time; - - if (tDiff < 250 && Math.abs(xDiff) >= 150) { - if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) - showSidebar(); - else if (xDiff < 0 && curX < 300) - hideSidebar(); - - firstContact = null; - } - }, { passive: true }); -})(); - -(function chapterNavigation() { - document.addEventListener('keydown', function (e) { - if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; } - if (window.search && window.search.hasFocus()) { return; } - var html = document.querySelector('html'); - - function next() { - var nextButton = document.querySelector('.nav-chapters.next'); - if (nextButton) { - window.location.href = nextButton.href; - } - } - function prev() { - var previousButton = document.querySelector('.nav-chapters.previous'); - if (previousButton) { - window.location.href = previousButton.href; - } - } - switch (e.key) { - case 'ArrowRight': - e.preventDefault(); - if (html.dir == 'rtl') { - prev(); - } else { - next(); - } - break; - case 'ArrowLeft': - e.preventDefault(); - if (html.dir == 'rtl') { - next(); - } else { - prev(); - } - break; - } - }); -})(); - -(function clipboard() { - var clipButtons = document.querySelectorAll('.clip-button'); - - function hideTooltip(elem) { - elem.firstChild.innerText = ""; - elem.className = 'clip-button'; - } - - function showTooltip(elem, msg) { - elem.firstChild.innerText = msg; - elem.className = 'clip-button tooltipped'; - } - - var clipboardSnippets = new ClipboardJS('.clip-button', { - text: function (trigger) { - hideTooltip(trigger); - let playground = trigger.closest("pre"); - return playground_text(playground, false); - } - }); - - Array.from(clipButtons).forEach(function (clipButton) { - clipButton.addEventListener('mouseout', function (e) { - hideTooltip(e.currentTarget); - }); - }); - - clipboardSnippets.on('success', function (e) { - e.clearSelection(); - showTooltip(e.trigger, "Copied!"); - }); - - clipboardSnippets.on('error', function (e) { - showTooltip(e.trigger, "Clipboard error!"); - }); -})(); - -(function scrollToTop () { - var menuTitle = document.querySelector('.menu-title'); - - menuTitle.addEventListener('click', function () { - document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' }); - }); -})(); - -(function controllMenu() { - var menu = document.getElementById('menu-bar'); - - (function controllPosition() { - var scrollTop = document.scrollingElement.scrollTop; - var prevScrollTop = scrollTop; - var minMenuY = -menu.clientHeight - 50; - // When the script loads, the page can be at any scroll (e.g. if you reforesh it). - menu.style.top = scrollTop + 'px'; - // Same as parseInt(menu.style.top.slice(0, -2), but faster - var topCache = menu.style.top.slice(0, -2); - menu.classList.remove('sticky'); - var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster - document.addEventListener('scroll', function () { - scrollTop = Math.max(document.scrollingElement.scrollTop, 0); - // `null` means that it doesn't need to be updated - var nextSticky = null; - var nextTop = null; - var scrollDown = scrollTop > prevScrollTop; - var menuPosAbsoluteY = topCache - scrollTop; - if (scrollDown) { - nextSticky = false; - if (menuPosAbsoluteY > 0) { - nextTop = prevScrollTop; - } - } else { - if (menuPosAbsoluteY > 0) { - nextSticky = true; - } else if (menuPosAbsoluteY < minMenuY) { - nextTop = prevScrollTop + minMenuY; - } - } - if (nextSticky === true && stickyCache === false) { - menu.classList.add('sticky'); - stickyCache = true; - } else if (nextSticky === false && stickyCache === true) { - menu.classList.remove('sticky'); - stickyCache = false; - } - if (nextTop !== null) { - menu.style.top = nextTop + 'px'; - topCache = nextTop; - } - prevScrollTop = scrollTop; - }, { passive: true }); - })(); - (function controllBorder() { - function updateBorder() { - if (menu.offsetTop === 0) { - menu.classList.remove('bordered'); - } else { - menu.classList.add('bordered'); - } - } - updateBorder(); - document.addEventListener('scroll', updateBorder, { passive: true }); - })(); -})(); diff --git a/docs/book/book.toml b/docs/book/book.toml deleted file mode 100644 index e1f7246..0000000 --- a/docs/book/book.toml +++ /dev/null @@ -1,41 +0,0 @@ -[book] -title = "Storybook Language Guide" -authors = ["R3T Studios"] -description = "Comprehensive documentation for the Storybook narrative simulation language" -language = "en" -multilingual = false -src = "." - -[build] -build-dir = "book" -create-missing = false - -[output.html] -default-theme = "light" -preferred-dark-theme = "navy" -smart-punctuation = true -git-repository-url = "https://github.com/r3t-studios/storybook" -git-repository-icon = "fa-github" -site-url = "/storybook/" - -[output.html.playground] -editable = false -line-numbers = true - -[output.html.search] -enable = true -limit-results = 30 -use-boolean-and = true -boost-title = 2 -boost-hierarchy = 1 -boost-paragraph = 1 -expand = true -heading-split-level = 3 - -[output.html.fold] -enable = true -level = 1 - -# Custom theme and styling (to be added later) -# [output.html.additional-css] -# [output.html.additional-js] diff --git a/docs/book/clipboard.min.js b/docs/book/clipboard.min.js deleted file mode 100644 index 02c549e..0000000 --- a/docs/book/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.4 - * https://zenorocha.github.io/clipboard.js - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n .hljs { - color: var(--links); -} - -/* - body-container is necessary because mobile browsers don't seem to like - overflow-x on the body tag when there is a tag. -*/ -#body-container { - /* - This is used when the sidebar pushes the body content off the side of - the screen on small screens. Without it, dragging on mobile Safari - will want to reposition the viewport in a weird way. - */ - overflow-x: clip; -} - -/* Menu Bar */ - -#menu-bar, -#menu-bar-hover-placeholder { - z-index: 101; - margin: auto calc(0px - var(--page-padding)); -} -#menu-bar { - position: relative; - display: flex; - flex-wrap: wrap; - background-color: var(--bg); - border-block-end-color: var(--bg); - border-block-end-width: 1px; - border-block-end-style: solid; -} -#menu-bar.sticky, -#menu-bar-hover-placeholder:hover + #menu-bar, -#menu-bar:hover, -html.sidebar-visible #menu-bar { - position: -webkit-sticky; - position: sticky; - top: 0 !important; -} -#menu-bar-hover-placeholder { - position: sticky; - position: -webkit-sticky; - top: 0; - height: var(--menu-bar-height); -} -#menu-bar.bordered { - border-block-end-color: var(--table-border-color); -} -#menu-bar i, #menu-bar .icon-button { - position: relative; - padding: 0 8px; - z-index: 10; - line-height: var(--menu-bar-height); - cursor: pointer; - transition: color 0.5s; -} -@media only screen and (max-width: 420px) { - #menu-bar i, #menu-bar .icon-button { - padding: 0 5px; - } -} - -.icon-button { - border: none; - background: none; - padding: 0; - color: inherit; -} -.icon-button i { - margin: 0; -} - -.right-buttons { - margin: 0 15px; -} -.right-buttons a { - text-decoration: none; -} - -.left-buttons { - display: flex; - margin: 0 5px; -} -html:not(.js) .left-buttons button { - display: none; -} - -.menu-title { - display: inline-block; - font-weight: 200; - font-size: 2.4rem; - line-height: var(--menu-bar-height); - text-align: center; - margin: 0; - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.menu-title { - cursor: pointer; -} - -.menu-bar, -.menu-bar:visited, -.nav-chapters, -.nav-chapters:visited, -.mobile-nav-chapters, -.mobile-nav-chapters:visited, -.menu-bar .icon-button, -.menu-bar a i { - color: var(--icons); -} - -.menu-bar i:hover, -.menu-bar .icon-button:hover, -.nav-chapters:hover, -.mobile-nav-chapters i:hover { - color: var(--icons-hover); -} - -/* Nav Icons */ - -.nav-chapters { - font-size: 2.5em; - text-align: center; - text-decoration: none; - - position: fixed; - top: 0; - bottom: 0; - margin: 0; - max-width: 150px; - min-width: 90px; - - display: flex; - justify-content: center; - align-content: center; - flex-direction: column; - - transition: color 0.5s, background-color 0.5s; -} - -.nav-chapters:hover { - text-decoration: none; - background-color: var(--theme-hover); - transition: background-color 0.15s, color 0.15s; -} - -.nav-wrapper { - margin-block-start: 50px; - display: none; -} - -.mobile-nav-chapters { - font-size: 2.5em; - text-align: center; - text-decoration: none; - width: 90px; - border-radius: 5px; - background-color: var(--sidebar-bg); -} - -/* Only Firefox supports flow-relative values */ -.previous { float: left; } -[dir=rtl] .previous { float: right; } - -/* Only Firefox supports flow-relative values */ -.next { - float: right; - right: var(--page-padding); -} -[dir=rtl] .next { - float: left; - right: unset; - left: var(--page-padding); -} - -/* Use the correct buttons for RTL layouts*/ -[dir=rtl] .previous i.fa-angle-left:before {content:"\f105";} -[dir=rtl] .next i.fa-angle-right:before { content:"\f104"; } - -@media only screen and (max-width: 1080px) { - .nav-wide-wrapper { display: none; } - .nav-wrapper { display: block; } -} - -/* sidebar-visible */ -@media only screen and (max-width: 1380px) { - #sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wide-wrapper { display: none; } - #sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wrapper { display: block; } -} - -/* Inline code */ - -:not(pre) > .hljs { - display: inline; - padding: 0.1em 0.3em; - border-radius: 3px; -} - -:not(pre):not(a) > .hljs { - color: var(--inline-code-color); - overflow-x: initial; -} - -a:hover > .hljs { - text-decoration: underline; -} - -pre { - position: relative; -} -pre > .buttons { - position: absolute; - z-index: 100; - right: 0px; - top: 2px; - margin: 0px; - padding: 2px 0px; - - color: var(--sidebar-fg); - cursor: pointer; - visibility: hidden; - opacity: 0; - transition: visibility 0.1s linear, opacity 0.1s linear; -} -pre:hover > .buttons { - visibility: visible; - opacity: 1 -} -pre > .buttons :hover { - color: var(--sidebar-active); - border-color: var(--icons-hover); - background-color: var(--theme-hover); -} -pre > .buttons i { - margin-inline-start: 8px; -} -pre > .buttons button { - cursor: inherit; - margin: 0px 5px; - padding: 4px 4px 3px 5px; - font-size: 23px; - - border-style: solid; - border-width: 1px; - border-radius: 4px; - border-color: var(--icons); - background-color: var(--theme-popup-bg); - transition: 100ms; - transition-property: color,border-color,background-color; - color: var(--icons); -} - -pre > .buttons button.clip-button { - padding: 2px 4px 0px 6px; -} -pre > .buttons button.clip-button::before { - /* clipboard image from octicons (https://github.com/primer/octicons/tree/v2.0.0) MIT license - */ - content: url('data:image/svg+xml,\ -\ -\ -'); - filter: var(--copy-button-filter); -} -pre > .buttons button.clip-button:hover::before { - filter: var(--copy-button-filter-hover); -} - -@media (pointer: coarse) { - pre > .buttons button { - /* On mobile, make it easier to tap buttons. */ - padding: 0.3rem 1rem; - } - - .sidebar-resize-indicator { - /* Hide resize indicator on devices with limited accuracy */ - display: none; - } -} -pre > code { - display: block; - padding: 1rem; -} - -/* FIXME: ACE editors overlap their buttons because ACE does absolute - positioning within the code block which breaks padding. The only solution I - can think of is to move the padding to the outer pre tag (or insert a div - wrapper), but that would require fixing a whole bunch of CSS rules. -*/ -.hljs.ace_editor { - padding: 0rem 0rem; -} - -pre > .result { - margin-block-start: 10px; -} - -/* Search */ - -#searchresults a { - text-decoration: none; -} - -mark { - border-radius: 2px; - padding-block-start: 0; - padding-block-end: 1px; - padding-inline-start: 3px; - padding-inline-end: 3px; - margin-block-start: 0; - margin-block-end: -1px; - margin-inline-start: -3px; - margin-inline-end: -3px; - background-color: var(--search-mark-bg); - transition: background-color 300ms linear; - cursor: pointer; -} - -mark.fade-out { - background-color: rgba(0,0,0,0) !important; - cursor: auto; -} - -.searchbar-outer { - margin-inline-start: auto; - margin-inline-end: auto; - max-width: var(--content-max-width); -} - -#searchbar { - width: 100%; - margin-block-start: 5px; - margin-block-end: 0; - margin-inline-start: auto; - margin-inline-end: auto; - padding: 10px 16px; - transition: box-shadow 300ms ease-in-out; - border: 1px solid var(--searchbar-border-color); - border-radius: 3px; - background-color: var(--searchbar-bg); - color: var(--searchbar-fg); -} -#searchbar:focus, -#searchbar.active { - box-shadow: 0 0 3px var(--searchbar-shadow-color); -} - -.searchresults-header { - font-weight: bold; - font-size: 1em; - padding-block-start: 18px; - padding-block-end: 0; - padding-inline-start: 5px; - padding-inline-end: 0; - color: var(--searchresults-header-fg); -} - -.searchresults-outer { - margin-inline-start: auto; - margin-inline-end: auto; - max-width: var(--content-max-width); - border-block-end: 1px dashed var(--searchresults-border-color); -} - -ul#searchresults { - list-style: none; - padding-inline-start: 20px; -} -ul#searchresults li { - margin: 10px 0px; - padding: 2px; - border-radius: 2px; -} -ul#searchresults li.focus { - background-color: var(--searchresults-li-bg); -} -ul#searchresults span.teaser { - display: block; - clear: both; - margin-block-start: 5px; - margin-block-end: 0; - margin-inline-start: 20px; - margin-inline-end: 0; - font-size: 0.8em; -} -ul#searchresults span.teaser em { - font-weight: bold; - font-style: normal; -} - -/* Sidebar */ - -.sidebar { - position: fixed; - left: 0; - top: 0; - bottom: 0; - width: var(--sidebar-width); - font-size: 0.875em; - box-sizing: border-box; - -webkit-overflow-scrolling: touch; - overscroll-behavior-y: contain; - background-color: var(--sidebar-bg); - color: var(--sidebar-fg); -} -.sidebar-iframe-inner { - background-color: var(--sidebar-bg); - color: var(--sidebar-fg); - padding: 10px 10px; - margin: 0; - font-size: 1.4rem; -} -.sidebar-iframe-outer { - border: none; - height: 100%; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} -[dir=rtl] .sidebar { left: unset; right: 0; } -.sidebar-resizing { - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; -} -html:not(.sidebar-resizing) .sidebar { - transition: transform 0.3s; /* Animation: slide away */ -} -.sidebar code { - line-height: 2em; -} -.sidebar .sidebar-scrollbox { - overflow-y: auto; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - padding: 10px 10px; -} -.sidebar .sidebar-resize-handle { - position: absolute; - cursor: col-resize; - width: 0; - right: calc(var(--sidebar-resize-indicator-width) * -1); - top: 0; - bottom: 0; - display: flex; - align-items: center; -} - -.sidebar-resize-handle .sidebar-resize-indicator { - width: 100%; - height: 12px; - background-color: var(--icons); - margin-inline-start: var(--sidebar-resize-indicator-space); -} - -[dir=rtl] .sidebar .sidebar-resize-handle { - left: calc(var(--sidebar-resize-indicator-width) * -1); - right: unset; -} -.js .sidebar .sidebar-resize-handle { - cursor: col-resize; - width: calc(var(--sidebar-resize-indicator-width) - var(--sidebar-resize-indicator-space)); -} -/* sidebar-hidden */ -#sidebar-toggle-anchor:not(:checked) ~ .sidebar { - transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width))); - z-index: -1; -} -[dir=rtl] #sidebar-toggle-anchor:not(:checked) ~ .sidebar { - transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width))); -} -.sidebar::-webkit-scrollbar { - background: var(--sidebar-bg); -} -.sidebar::-webkit-scrollbar-thumb { - background: var(--scrollbar); -} - -/* sidebar-visible */ -#sidebar-toggle-anchor:checked ~ .page-wrapper { - transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width))); -} -[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper { - transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width))); -} -@media only screen and (min-width: 620px) { - #sidebar-toggle-anchor:checked ~ .page-wrapper { - transform: none; - margin-inline-start: calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)); - } - [dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper { - transform: none; - } -} - -.chapter { - list-style: none outside none; - padding-inline-start: 0; - line-height: 2.2em; -} - -.chapter ol { - width: 100%; -} - -.chapter li { - display: flex; - color: var(--sidebar-non-existant); -} -.chapter li a { - display: block; - padding: 0; - text-decoration: none; - color: var(--sidebar-fg); -} - -.chapter li a:hover { - color: var(--sidebar-active); -} - -.chapter li a.active { - color: var(--sidebar-active); -} - -.chapter li > a.toggle { - cursor: pointer; - display: block; - margin-inline-start: auto; - padding: 0 10px; - user-select: none; - opacity: 0.68; -} - -.chapter li > a.toggle div { - transition: transform 0.5s; -} - -/* collapse the section */ -.chapter li:not(.expanded) + li > ol { - display: none; -} - -.chapter li.chapter-item { - line-height: 1.5em; - margin-block-start: 0.6em; -} - -.chapter li.expanded > a.toggle div { - transform: rotate(90deg); -} - -.spacer { - width: 100%; - height: 3px; - margin: 5px 0px; -} -.chapter .spacer { - background-color: var(--sidebar-spacer); -} - -@media (-moz-touch-enabled: 1), (pointer: coarse) { - .chapter li a { padding: 5px 0; } - .spacer { margin: 10px 0; } -} - -.section { - list-style: none outside none; - padding-inline-start: 20px; - line-height: 1.9em; -} - -/* Theme Menu Popup */ - -.theme-popup { - position: absolute; - left: 10px; - top: var(--menu-bar-height); - z-index: 1000; - border-radius: 4px; - font-size: 0.7em; - color: var(--fg); - background: var(--theme-popup-bg); - border: 1px solid var(--theme-popup-border); - margin: 0; - padding: 0; - list-style: none; - display: none; - /* Don't let the children's background extend past the rounded corners. */ - overflow: hidden; -} -[dir=rtl] .theme-popup { left: unset; right: 10px; } -.theme-popup .default { - color: var(--icons); -} -.theme-popup .theme { - width: 100%; - border: 0; - margin: 0; - padding: 2px 20px; - line-height: 25px; - white-space: nowrap; - text-align: start; - cursor: pointer; - color: inherit; - background: inherit; - font-size: inherit; -} -.theme-popup .theme:hover { - background-color: var(--theme-hover); -} - -.theme-selected::before { - display: inline-block; - content: "✓"; - margin-inline-start: -14px; - width: 14px; -} diff --git a/docs/book/css/general.css b/docs/book/css/general.css deleted file mode 100644 index 0862b51..0000000 --- a/docs/book/css/general.css +++ /dev/null @@ -1,242 +0,0 @@ -/* Base styles and content styles */ - -:root { - /* Browser default font-size is 16px, this way 1 rem = 10px */ - font-size: 62.5%; - color-scheme: var(--color-scheme); -} - -html { - font-family: "Open Sans", sans-serif; - color: var(--fg); - background-color: var(--bg); - text-size-adjust: none; - -webkit-text-size-adjust: none; -} - -body { - margin: 0; - font-size: 1.6rem; - overflow-x: hidden; -} - -code { - font-family: var(--mono-font) !important; - font-size: var(--code-font-size); - direction: ltr !important; -} - -/* make long words/inline code not x overflow */ -main { - overflow-wrap: break-word; -} - -/* make wide tables scroll if they overflow */ -.table-wrapper { - overflow-x: auto; -} - -/* Don't change font size in headers. */ -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - font-size: unset; -} - -.left { float: left; } -.right { float: right; } -.boring { opacity: 0.6; } -.hide-boring .boring { display: none; } -.hidden { display: none !important; } - -h2, h3 { margin-block-start: 2.5em; } -h4, h5 { margin-block-start: 2em; } - -.header + .header h3, -.header + .header h4, -.header + .header h5 { - margin-block-start: 1em; -} - -h1:target::before, -h2:target::before, -h3:target::before, -h4:target::before, -h5:target::before, -h6:target::before { - display: inline-block; - content: "»"; - margin-inline-start: -30px; - width: 30px; -} - -/* This is broken on Safari as of version 14, but is fixed - in Safari Technology Preview 117 which I think will be Safari 14.2. - https://bugs.webkit.org/show_bug.cgi?id=218076 -*/ -:target { - /* Safari does not support logical properties */ - scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); -} - -.page { - outline: 0; - padding: 0 var(--page-padding); - margin-block-start: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ -} -.page-wrapper { - box-sizing: border-box; - background-color: var(--bg); -} -.no-js .page-wrapper, -.js:not(.sidebar-resizing) .page-wrapper { - transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ -} -[dir=rtl] .js:not(.sidebar-resizing) .page-wrapper { - transition: margin-right 0.3s ease, transform 0.3s ease; /* Animation: slide away */ -} - -.content { - overflow-y: auto; - padding: 0 5px 50px 5px; -} -.content main { - margin-inline-start: auto; - margin-inline-end: auto; - max-width: var(--content-max-width); -} -.content p { line-height: 1.45em; } -.content ol { line-height: 1.45em; } -.content ul { line-height: 1.45em; } -.content a { text-decoration: none; } -.content a:hover { text-decoration: underline; } -.content img, .content video { max-width: 100%; } -.content .header:link, -.content .header:visited { - color: var(--fg); -} -.content .header:link, -.content .header:visited:hover { - text-decoration: none; -} - -table { - margin: 0 auto; - border-collapse: collapse; -} -table td { - padding: 3px 20px; - border: 1px var(--table-border-color) solid; -} -table thead { - background: var(--table-header-bg); -} -table thead td { - font-weight: 700; - border: none; -} -table thead th { - padding: 3px 20px; -} -table thead tr { - border: 1px var(--table-header-bg) solid; -} -/* Alternate background colors for rows */ -table tbody tr:nth-child(2n) { - background: var(--table-alternate-bg); -} - - -blockquote { - margin: 20px 0; - padding: 0 20px; - color: var(--fg); - background-color: var(--quote-bg); - border-block-start: .1em solid var(--quote-border); - border-block-end: .1em solid var(--quote-border); -} - -.warning { - margin: 20px; - padding: 0 20px; - border-inline-start: 2px solid var(--warning-border); -} - -.warning:before { - position: absolute; - width: 3rem; - height: 3rem; - margin-inline-start: calc(-1.5rem - 21px); - content: "ⓘ"; - text-align: center; - background-color: var(--bg); - color: var(--warning-border); - font-weight: bold; - font-size: 2rem; -} - -blockquote .warning:before { - background-color: var(--quote-bg); -} - -kbd { - background-color: var(--table-border-color); - border-radius: 4px; - border: solid 1px var(--theme-popup-border); - box-shadow: inset 0 -1px 0 var(--theme-hover); - display: inline-block; - font-size: var(--code-font-size); - font-family: var(--mono-font); - line-height: 10px; - padding: 4px 5px; - vertical-align: middle; -} - -sup { - /* Set the line-height for superscript and footnote references so that there - isn't an awkward space appearing above lines that contain the footnote. - - See https://github.com/rust-lang/mdBook/pull/2443#discussion_r1813773583 - for an explanation. - */ - line-height: 0; -} - -:not(.footnote-definition) + .footnote-definition, -.footnote-definition + :not(.footnote-definition) { - margin-block-start: 2em; -} -.footnote-definition { - font-size: 0.9em; - margin: 0.5em 0; -} -.footnote-definition p { - display: inline; -} - -.tooltiptext { - position: absolute; - visibility: hidden; - color: #fff; - background-color: #333; - transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ - left: -8px; /* Half of the width of the icon */ - top: -35px; - font-size: 0.8em; - text-align: center; - border-radius: 6px; - padding: 5px 8px; - margin: 5px; - z-index: 1000; -} -.tooltipped .tooltiptext { - visibility: visible; -} - -.chapter li.part-title { - color: var(--sidebar-fg); - margin: 5px 0px; - font-weight: bold; -} - -.result-no-output { - font-style: italic; -} diff --git a/docs/book/css/print.css b/docs/book/css/print.css deleted file mode 100644 index 80ec3a5..0000000 --- a/docs/book/css/print.css +++ /dev/null @@ -1,50 +0,0 @@ - -#sidebar, -#menu-bar, -.nav-chapters, -.mobile-nav-chapters { - display: none; -} - -#page-wrapper.page-wrapper { - transform: none !important; - margin-inline-start: 0px; - overflow-y: initial; -} - -#content { - max-width: none; - margin: 0; - padding: 0; -} - -.page { - overflow-y: initial; -} - -code { - direction: ltr !important; -} - -pre > .buttons { - z-index: 2; -} - -a, a:visited, a:active, a:hover { - color: #4183c4; - text-decoration: none; -} - -h1, h2, h3, h4, h5, h6 { - page-break-inside: avoid; - page-break-after: avoid; -} - -pre, code { - page-break-inside: avoid; - white-space: pre-wrap; -} - -.fa { - display: none !important; -} diff --git a/docs/book/css/variables.css b/docs/book/css/variables.css deleted file mode 100644 index 12d1db7..0000000 --- a/docs/book/css/variables.css +++ /dev/null @@ -1,309 +0,0 @@ - -/* Globals */ - -:root { - --sidebar-width: 300px; - --sidebar-resize-indicator-width: 8px; - --sidebar-resize-indicator-space: 2px; - --page-padding: 15px; - --content-max-width: 750px; - --menu-bar-height: 50px; - --mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace; - --code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */ -} - -/* Themes */ - -.ayu { - --bg: hsl(210, 25%, 8%); - --fg: #c5c5c5; - - --sidebar-bg: #14191f; - --sidebar-fg: #c8c9db; - --sidebar-non-existant: #5c6773; - --sidebar-active: #ffb454; - --sidebar-spacer: #2d334f; - - --scrollbar: var(--sidebar-fg); - - --icons: #737480; - --icons-hover: #b7b9cc; - - --links: #0096cf; - - --inline-code-color: #ffb454; - - --theme-popup-bg: #14191f; - --theme-popup-border: #5c6773; - --theme-hover: #191f26; - - --quote-bg: hsl(226, 15%, 17%); - --quote-border: hsl(226, 15%, 22%); - - --warning-border: #ff8e00; - - --table-border-color: hsl(210, 25%, 13%); - --table-header-bg: hsl(210, 25%, 28%); - --table-alternate-bg: hsl(210, 25%, 11%); - - --searchbar-border-color: #848484; - --searchbar-bg: #424242; - --searchbar-fg: #fff; - --searchbar-shadow-color: #d4c89f; - --searchresults-header-fg: #666; - --searchresults-border-color: #888; - --searchresults-li-bg: #252932; - --search-mark-bg: #e3b171; - - --color-scheme: dark; - - /* Same as `--icons` */ - --copy-button-filter: invert(45%) sepia(6%) saturate(621%) hue-rotate(198deg) brightness(99%) contrast(85%); - /* Same as `--sidebar-active` */ - --copy-button-filter-hover: invert(68%) sepia(55%) saturate(531%) hue-rotate(341deg) brightness(104%) contrast(101%); -} - -.coal { - --bg: hsl(200, 7%, 8%); - --fg: #98a3ad; - - --sidebar-bg: #292c2f; - --sidebar-fg: #a1adb8; - --sidebar-non-existant: #505254; - --sidebar-active: #3473ad; - --sidebar-spacer: #393939; - - --scrollbar: var(--sidebar-fg); - - --icons: #43484d; - --icons-hover: #b3c0cc; - - --links: #2b79a2; - - --inline-code-color: #c5c8c6; - - --theme-popup-bg: #141617; - --theme-popup-border: #43484d; - --theme-hover: #1f2124; - - --quote-bg: hsl(234, 21%, 18%); - --quote-border: hsl(234, 21%, 23%); - - --warning-border: #ff8e00; - - --table-border-color: hsl(200, 7%, 13%); - --table-header-bg: hsl(200, 7%, 28%); - --table-alternate-bg: hsl(200, 7%, 11%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #b7b7b7; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #98a3ad; - --searchresults-li-bg: #2b2b2f; - --search-mark-bg: #355c7d; - - --color-scheme: dark; - - /* Same as `--icons` */ - --copy-button-filter: invert(26%) sepia(8%) saturate(575%) hue-rotate(169deg) brightness(87%) contrast(82%); - /* Same as `--sidebar-active` */ - --copy-button-filter-hover: invert(36%) sepia(70%) saturate(503%) hue-rotate(167deg) brightness(98%) contrast(89%); -} - -.light, html:not(.js) { - --bg: hsl(0, 0%, 100%); - --fg: hsl(0, 0%, 0%); - - --sidebar-bg: #fafafa; - --sidebar-fg: hsl(0, 0%, 0%); - --sidebar-non-existant: #aaaaaa; - --sidebar-active: #1f1fff; - --sidebar-spacer: #f4f4f4; - - --scrollbar: #8F8F8F; - - --icons: #747474; - --icons-hover: #000000; - - --links: #20609f; - - --inline-code-color: #301900; - - --theme-popup-bg: #fafafa; - --theme-popup-border: #cccccc; - --theme-hover: #e6e6e6; - - --quote-bg: hsl(197, 37%, 96%); - --quote-border: hsl(197, 37%, 91%); - - --warning-border: #ff8e00; - - --table-border-color: hsl(0, 0%, 95%); - --table-header-bg: hsl(0, 0%, 80%); - --table-alternate-bg: hsl(0, 0%, 97%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #fafafa; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #888; - --searchresults-li-bg: #e4f2fe; - --search-mark-bg: #a2cff5; - - --color-scheme: light; - - /* Same as `--icons` */ - --copy-button-filter: invert(45.49%); - /* Same as `--sidebar-active` */ - --copy-button-filter-hover: invert(14%) sepia(93%) saturate(4250%) hue-rotate(243deg) brightness(99%) contrast(130%); -} - -.navy { - --bg: hsl(226, 23%, 11%); - --fg: #bcbdd0; - - --sidebar-bg: #282d3f; - --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505274; - --sidebar-active: #2b79a2; - --sidebar-spacer: #2d334f; - - --scrollbar: var(--sidebar-fg); - - --icons: #737480; - --icons-hover: #b7b9cc; - - --links: #2b79a2; - - --inline-code-color: #c5c8c6; - - --theme-popup-bg: #161923; - --theme-popup-border: #737480; - --theme-hover: #282e40; - - --quote-bg: hsl(226, 15%, 17%); - --quote-border: hsl(226, 15%, 22%); - - --warning-border: #ff8e00; - - --table-border-color: hsl(226, 23%, 16%); - --table-header-bg: hsl(226, 23%, 31%); - --table-alternate-bg: hsl(226, 23%, 14%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #aeaec6; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #5f5f71; - --searchresults-border-color: #5c5c68; - --searchresults-li-bg: #242430; - --search-mark-bg: #a2cff5; - - --color-scheme: dark; - - /* Same as `--icons` */ - --copy-button-filter: invert(51%) sepia(10%) saturate(393%) hue-rotate(198deg) brightness(86%) contrast(87%); - /* Same as `--sidebar-active` */ - --copy-button-filter-hover: invert(46%) sepia(20%) saturate(1537%) hue-rotate(156deg) brightness(85%) contrast(90%); -} - -.rust { - --bg: hsl(60, 9%, 87%); - --fg: #262625; - - --sidebar-bg: #3b2e2a; - --sidebar-fg: #c8c9db; - --sidebar-non-existant: #505254; - --sidebar-active: #e69f67; - --sidebar-spacer: #45373a; - - --scrollbar: var(--sidebar-fg); - - --icons: #737480; - --icons-hover: #262625; - - --links: #2b79a2; - - --inline-code-color: #6e6b5e; - - --theme-popup-bg: #e1e1db; - --theme-popup-border: #b38f6b; - --theme-hover: #99908a; - - --quote-bg: hsl(60, 5%, 75%); - --quote-border: hsl(60, 5%, 70%); - - --warning-border: #ff8e00; - - --table-border-color: hsl(60, 9%, 82%); - --table-header-bg: #b3a497; - --table-alternate-bg: hsl(60, 9%, 84%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #fafafa; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #888; - --searchresults-li-bg: #dec2a2; - --search-mark-bg: #e69f67; - - /* Same as `--icons` */ - --copy-button-filter: invert(51%) sepia(10%) saturate(393%) hue-rotate(198deg) brightness(86%) contrast(87%); - /* Same as `--sidebar-active` */ - --copy-button-filter-hover: invert(77%) sepia(16%) saturate(1798%) hue-rotate(328deg) brightness(98%) contrast(83%); -} - -@media (prefers-color-scheme: dark) { - html:not(.js) { - --bg: hsl(200, 7%, 8%); - --fg: #98a3ad; - - --sidebar-bg: #292c2f; - --sidebar-fg: #a1adb8; - --sidebar-non-existant: #505254; - --sidebar-active: #3473ad; - --sidebar-spacer: #393939; - - --scrollbar: var(--sidebar-fg); - - --icons: #43484d; - --icons-hover: #b3c0cc; - - --links: #2b79a2; - - --inline-code-color: #c5c8c6; - - --theme-popup-bg: #141617; - --theme-popup-border: #43484d; - --theme-hover: #1f2124; - - --quote-bg: hsl(234, 21%, 18%); - --quote-border: hsl(234, 21%, 23%); - - --warning-border: #ff8e00; - - --table-border-color: hsl(200, 7%, 13%); - --table-header-bg: hsl(200, 7%, 28%); - --table-alternate-bg: hsl(200, 7%, 11%); - - --searchbar-border-color: #aaa; - --searchbar-bg: #b7b7b7; - --searchbar-fg: #000; - --searchbar-shadow-color: #aaa; - --searchresults-header-fg: #666; - --searchresults-border-color: #98a3ad; - --searchresults-li-bg: #2b2b2f; - --search-mark-bg: #355c7d; - - --color-scheme: dark; - - /* Same as `--icons` */ - --copy-button-filter: invert(26%) sepia(8%) saturate(575%) hue-rotate(169deg) brightness(87%) contrast(82%); - /* Same as `--sidebar-active` */ - --copy-button-filter-hover: invert(36%) sepia(70%) saturate(503%) hue-rotate(167deg) brightness(98%) contrast(89%); - } -} diff --git a/docs/book/elasticlunr.min.js b/docs/book/elasticlunr.min.js deleted file mode 100644 index 94b20dd..0000000 --- a/docs/book/elasticlunr.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * elasticlunr - http://weixsong.github.io - * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5 - * - * Copyright (C) 2017 Oliver Nightingale - * Copyright (C) 2017 Wei Song - * MIT Licensed - * @license - */ -!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o - - - - - Baker Family Complete - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Baker Family Complete

-

This example demonstrates a complete Storybook project modeling Martha’s bakery and the people around it. It showcases all major language features working together.

-

Project Structure

-
baker-family/
-  schema/
-    core_enums.sb       # Enum definitions
-    templates.sb        # Reusable templates
-    beings.sb           # Species definitions
-  world/
-    characters/
-      martha.sb         # Martha, master baker
-      jane.sb           # Jane, pastry specialist
-      elena.sb          # Elena, apprentice
-      gregory.sb        # Gregory, regular customer
-      family.sb         # David, Tommy, Emma
-    behaviors/
-      bakery_behaviors.sb
-    relationships/
-      bakery_relationships.sb
-    locations/
-      bakery_places.sb
-    institutions/
-      bakery_institutions.sb
-    schedules/
-      bakery_schedules.sb
-
-

Schema Layer

-

Enums

-
// schema/core_enums.sb
-
-enum SkillLevel {
-    novice,
-    beginner,
-    intermediate,
-    advanced,
-    expert,
-    master
-}
-
-enum Specialty {
-    sourdough,
-    pastries,
-    cakes,
-    general,
-    bread
-}
-
-enum Confidence {
-    timid,
-    uncertain,
-    growing,
-    steady,
-    confident,
-    commanding
-}
-
-enum DayPart {
-    early_morning,
-    morning,
-    midday,
-    afternoon,
-    evening,
-    night
-}
-
-

Species

-
// schema/beings.sb
-
-species Human {
-    lifespan: 80
-
-    ---description
-    Bipedal mammals with complex language and tool use.
-    ---
-}
-
-species Cat {
-    lifespan: 15
-
-    ---description
-    Domestic cats often found in bakeries for pest control
-    and companionship.
-    ---
-}
-
-

Templates

-
// schema/templates.sb
-
-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
-}
-
-template BusinessOwner {
-    include SkilledWorker
-    revenue_monthly: 0..100000
-    employees: 0..20
-    years_in_business: 0..50
-}
-
-template Apprentice {
-    include SkilledWorker
-    skill_level: novice
-    confidence: timid
-    mentor: string
-    dedication: 0.0..1.0
-}
-
-

Characters

-

Martha

-
// world/characters/martha.sb
-
-use schema::core_enums::{SkillLevel, Specialty, Confidence};
-use schema::templates::{Baker, BusinessOwner};
-use schema::beings::Human;
-
-character Martha: Human from Baker, BusinessOwner {
-    uses behaviors: [
-        { tree: BakerMorningRoutine },
-        { tree: HandleEmergency, when: emergency_detected, priority: critical }
-    ]
-
-    age: 34
-    specialty: sourdough
-    skill_level: master
-    confidence: commanding
-    recipes_mastered: 85
-    years_experience: 22
-    sourdough_starter_health: 0.95
-
-    revenue_monthly: 12000
-    employees: 3
-    years_in_business: 8
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age twelve.
-    By twenty she had won regional competitions. At twenty-six she opened
-    her own bakery, which quickly became the most popular in town. Her
-    sourdough is legendary -- she maintains a starter that is fifteen
-    years old.
-    ---
-}
-
-life_arc MarthaCareerArc {
-    ---description
-    Tracks Martha's evolution from established baker to community leader.
-    ---
-
-    state running_bakery {
-        on enter {
-            Martha.confidence: commanding
-            Martha.skill_level: master
-        }
-        on employees > 5 -> expanding
-    }
-
-    state expanding {
-        on enter {
-            Martha.revenue_monthly: 20000
-        }
-        on second_location_opened -> community_leader
-    }
-
-    state community_leader {
-        on enter {
-            Martha.can_teach: true
-            Martha.mentors_count: 3
-        }
-
-        ---narrative
-        Martha's bakery has become a training ground for the next
-        generation of bakers. She sits on the guild board and her
-        sourdough recipe is studied at culinary schools.
-        ---
-    }
-}
-
-

Jane

-
// world/characters/jane.sb
-
-use schema::core_enums::{SkillLevel, Specialty, Confidence};
-use schema::templates::Baker;
-use schema::beings::Human;
-
-character Jane: Human from Baker {
-    age: 36
-    specialty: pastries
-    skill_level: expert
-    confidence: confident
-    recipes_mastered: 120
-    years_experience: 18
-    can_work_independently: true
-
-    ---backstory
-    Jane trained at a prestigious culinary school before joining
-    Martha's bakery as co-owner. Where Martha excels at bread, Jane
-    is a pastry artist. Her croissants draw customers from three
-    towns over.
-    ---
-
-    ---appearance
-    A focused woman with flour-dusted apron and steady hands.
-    Known for her intricate pastry decorations and precise
-    temperature control.
-    ---
-}
-
-

Elena

-
// world/characters/elena.sb
-
-use schema::core_enums::{SkillLevel, Confidence};
-use schema::templates::Apprentice;
-use schema::beings::Human;
-
-character Elena: Human from Apprentice {
-    age: 16
-    skill_level: novice
-    confidence: timid
-    mentor: "Martha"
-    dedication: 0.9
-    natural_talent: 0.8
-    recipes_mastered: 2
-
-    ---backstory
-    Elena comes from a family of farmers who could never afford to
-    buy bread from the bakery. When Martha offered her an apprenticeship,
-    she jumped at the chance to learn a trade.
-    ---
-}
-
-life_arc ElenaCareer {
-    ---description
-    Tracks Elena's progression from nervous apprentice to confident
-    master baker. Each state represents a key phase of her career.
-    ---
-
-    state early_apprentice {
-        on enter {
-            Elena.skill_level: novice
-            Elena.confidence: timid
-        }
-
-        on recipes_mastered > 5 -> growing_apprentice
-
-        ---narrative
-        Elena's hands shake as she measures flour. She checks the
-        recipe three times before adding each ingredient. Martha
-        patiently corrects her technique.
-        ---
-    }
-
-    state growing_apprentice {
-        on enter {
-            Elena.skill_level: beginner
-            Elena.confidence: uncertain
-        }
-
-        on recipes_mastered > 15 -> journeyman
-
-        ---narrative
-        The shaking stops. Elena can make basic breads without
-        looking at the recipe. She still doubts herself but
-        Martha's encouragement is taking root.
-        ---
-    }
-
-    state journeyman {
-        on enter {
-            Elena.skill_level: intermediate
-            Elena.confidence: growing
-            Elena.can_work_independently: true
-        }
-
-        on recipes_mastered > 30 -> senior_journeyman
-
-        ---narrative
-        Elena runs the morning shift alone while Martha handles
-        special orders. Customers start asking for "Elena's rolls."
-        She begins experimenting with her own recipes.
-        ---
-    }
-
-    state senior_journeyman {
-        on enter {
-            Elena.skill_level: advanced
-            Elena.confidence: steady
-        }
-
-        on recipes_mastered > 50 -> master
-
-        ---narrative
-        Elena develops her signature recipe: rosemary olive bread
-        that becomes the bakery's bestseller. She handles difficult
-        customers with grace and trains new helpers.
-        ---
-    }
-
-    state master {
-        on enter {
-            Elena.skill_level: master
-            Elena.confidence: commanding
-            Elena.can_teach: true
-        }
-
-        ---narrative
-        Master Baker Elena. She has earned it. The guild acknowledges
-        her mastery, and Martha beams with pride. Elena begins
-        mentoring her own apprentice.
-        ---
-    }
-}
-
-

Gregory

-
// world/characters/gregory.sb
-
-use schema::beings::Human;
-
-character Gregory: Human {
-    age: 68
-    occupation: "retired_teacher"
-    always_orders: "sourdough_loaf"
-    visits_daily: true
-    years_as_customer: 15
-    knows_everyone: true
-
-    ---backstory
-    Gregory has been buying Martha's bread every morning for
-    fifteen years. Their brief daily exchanges about the weather
-    and local gossip are a comforting routine for both of them.
-    ---
-}
-
-

Behaviors

-
// world/behaviors/bakery_behaviors.sb
-
-behavior BakerMorningRoutine {
-    ---description
-    Martha's morning routine: prepare dough step by step,
-    from mixing to shaping to baking.
-    ---
-
-    then morning_baking {
-        // Start with sourdough
-        then prepare_starter {
-            CheckStarter
-            FeedStarter
-            WaitForActivity
-        }
-
-        // Mix the dough
-        then mix_dough {
-            MeasureFlour
-            AddWater
-            IncorporateStarter
-        }
-
-        // Knead and shape
-        then shape_loaves {
-            KneadDough
-            FirstRise
-            ShapeLoaves
-        }
-
-        // Bake
-        then bake {
-            PreHeatOven
-            LoadLoaves
-            MonitorBaking
-        }
-    }
-}
-
-behavior CustomerServiceLoop {
-    ---description
-    The bakery's continuous customer service loop. Uses infinite
-    repeat decorator to serve customers throughout the day.
-    ---
-
-    repeat {
-        then service_cycle {
-            // Check for customers
-            choose service_mode {
-                then serve_waiting {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                }
-
-                then restock_display {
-                    if(display_low)
-                    FetchFromKitchen
-                    ArrangeOnShelves
-                }
-            }
-
-            // Process payment
-            CollectPayment
-            ThankCustomer
-
-            // Brief pause between customers
-            timeout(5s) {
-                CleanCounter
-            }
-
-            PrepareForNextCustomer
-        }
-    }
-}
-
-

Relationships

-
// world/relationships/bakery_relationships.sb
-
-relationship MarthaAndGregory {
-    Martha {
-        role: shopkeeper
-        values_loyalty: 0.9
-
-        ---perspective
-        Martha appreciates Gregory's unwavering loyalty. He has
-        been buying her sourdough loaf every morning for fifteen
-        years. Their brief daily exchanges about the weather and
-        local gossip are a comforting routine.
-        ---
-    }
-
-    Gregory {
-        role: regular_customer
-        always_orders: "sourdough_loaf"
-
-        ---perspective
-        Gregory considers Martha's bakery a cornerstone of his
-        daily routine. The bread is excellent, but it is the brief
-        human connection that keeps him coming back.
-        ---
-    }
-}
-
-relationship MentorApprentice {
-    Martha {
-        role: mentor
-        teaching_style: "patient"
-        investment: 0.9
-
-        ---perspective
-        Martha sees Elena as the daughter she might have had in
-        the trade. She recognizes the same passion she felt at
-        that age and pushes Elena harder because she knows the
-        talent is there. Every correction comes from love.
-        ---
-    }
-
-    Elena {
-        role: apprentice
-        dedication: 0.9
-        anxiety: 0.4
-
-        ---perspective
-        Elena idolizes Martha's skill but fears disappointing
-        her. Every morning she arrives thirty minutes early to
-        practice techniques before Martha gets in. She keeps a
-        notebook of every correction, reviewing them each night.
-        ---
-    }
-
-    bond: 0.85
-}
-
-relationship BakeryPartnership {
-    Martha {
-        role: co_owner
-        specialty: "bread"
-        handles_finances: true
-
-        ---perspective
-        Martha and Jane complement each other perfectly. Martha
-        handles the bread and business side while Jane creates
-        the pastries that draw customers in. Together they have
-        built something neither could alone.
-        ---
-    }
-
-    Jane {
-        role: co_owner
-        specialty: "pastries"
-        handles_creativity: true
-
-        ---perspective
-        Jane considers Martha the steady foundation of their
-        partnership. While Jane experiments and creates, Martha
-        ensures the bakery runs like clockwork. Their different
-        strengths make the bakery stronger.
-        ---
-    }
-
-    bond: 0.9
-}
-
-

Locations

-
// world/locations/bakery_places.sb
-
-location MarthasBakery {
-    type: "commercial"
-    established: "2018"
-    square_feet: 1200
-    has_kitchen: true
-    has_storefront: true
-    seating_capacity: 12
-
-    ---description
-    A warm, inviting bakery on Main Street. The aroma of fresh
-    bread wafts out the door every morning at 4 AM. Exposed brick
-    walls, a glass display case, and a view into the kitchen where
-    customers can watch the bakers at work.
-    ---
-}
-
-location FarmersMarket {
-    type: "outdoor_market"
-    operates_on: "saturday"
-    stalls: 30
-    foot_traffic: "high"
-
-    ---description
-    The weekly Saturday market where Martha sells her bread directly
-    to the community. Her stall is always the first to sell out.
-    ---
-}
-
-location BakeryKitchen {
-    type: "commercial_kitchen"
-    ovens: 3
-    prep_stations: 4
-    walk_in_cooler: true
-
-    ---description
-    The heart of the bakery. Three professional ovens line the back
-    wall, each at a different temperature for different breads. The
-    sourdough starter sits on a shelf near the warmest oven, bubbling
-    contentedly in its ceramic crock.
-    ---
-}
-
-

Institutions

-
// world/institutions/bakery_institutions.sb
-
-institution BakersGuild {
-    type: professional_guild
-    members: 45
-    founded: "1952"
-    meets_monthly: true
-
-    ---description
-    The local bakers' guild that sets quality standards, organizes
-    competitions, and mentors apprentices. Martha has been a board
-    member for three years.
-    ---
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Layered architecture: Schema (types) separated from world (instances)
  2. -
  3. Species + Templates: Human species combined with Baker and BusinessOwner templates
  4. -
  5. Rich behavior trees: Morning routine and customer service with choose, then, and repeat
  6. -
  7. Asymmetric relationships: Martha and Elena see their mentorship differently
  8. -
  9. Life arcs: Elena’s career journey modeled as a state machine
  10. -
  11. Prose everywhere: Every declaration includes narrative context
  12. -
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/examples/25-day-in-life.html b/docs/book/examples/25-day-in-life.html deleted file mode 100644 index b19aa9c..0000000 --- a/docs/book/examples/25-day-in-life.html +++ /dev/null @@ -1,537 +0,0 @@ - - - - - - Day in the Life - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Day in the Life

-

This example models a complete day for a baker character, showing how schedules, behaviors, and life arcs work together to create a rich daily simulation.

-

The Baker

-
use schema::core_enums::{Season, DayOfWeek};
-use schema::beings::Human;
-use schema::templates::SkilledWorker;
-
-character Martha: Human from SkilledWorker {
-    age: 42
-    occupation: "Master Baker"
-    skill_level: 0.95
-    energy: 1.0
-    mood: 0.8
-
-    uses schedule: MarthaDailySchedule
-    uses behaviors: [
-        { tree: BakerRoutine, priority: normal },
-        { tree: HandleEmergency, when: emergency_detected, priority: critical }
-    ]
-
-    ---backstory
-    Martha has been baking since she was twelve, learning from her
-    grandmother. She now runs the most popular bakery in town and
-    is known for her sourdough bread and apple pastries.
-    ---
-}
-
-

The Schedule

-
schedule MarthaDailySchedule {
-    block wake_up {
-        04:00 - 04:30
-        action: routines::morning_wake
-    }
-
-    block early_baking {
-        04:30 - 07:00
-        action: baking::prepare_morning_goods
-    }
-
-    block open_shop {
-        07:00 - 07:15
-        action: shop::open_for_business
-    }
-
-    block morning_rush {
-        07:15 - 10:00
-        action: shop::serve_morning_customers
-    }
-
-    block midday_baking {
-        10:00 - 12:00
-        action: baking::prepare_afternoon_goods
-    }
-
-    block lunch_break {
-        12:00 - 13:00
-        action: social::lunch_with_family
-    }
-
-    block afternoon_sales {
-        13:00 - 16:00
-        action: shop::serve_afternoon_customers
-    }
-
-    block close_shop {
-        16:00 - 16:30
-        action: shop::close_for_day
-    }
-
-    block evening_prep {
-        16:30 - 17:30
-        action: baking::prepare_dough_for_tomorrow
-    }
-
-    block family_time {
-        18:00 - 21:00
-        action: social::family_evening
-    }
-
-    block sleep {
-        21:00 - 04:00
-        action: routines::sleep
-    }
-
-    // Saturday: Market day
-    recurs MarketDay on day saturday {
-        block market_prep {
-            03:00 - 05:00
-            action: baking::market_batch
-        }
-
-        block market_sales {
-            06:00 - 14:00
-            action: market::sell_at_stall
-        }
-
-        block market_cleanup {
-            14:00 - 15:00
-            action: market::pack_up
-        }
-    }
-
-    // Summer: Extended hours
-    block summer_afternoon {
-        13:00 - 18:00
-        action: shop::extended_summer_hours
-        on season summer
-    }
-}
-
-

Behaviors

-

Morning Routine

-
behavior BakerMorningRoutine {
-    then morning_sequence {
-        WakeUp
-        WashFace
-        DressInWorkClothes
-
-        // Check the sourdough starter
-        then check_starter {
-            ExamineStarter
-            if(starter_healthy) {
-                FeedStarter
-            }
-        }
-
-        WalkToKitchen
-        LightOven
-    }
-}
-
-

Baking Behavior

-
behavior BakerRoutine {
-    choose baking_priority {
-        // Handle special orders first
-        then special_orders {
-            if(has_special_orders)
-            then fill_order {
-                ReviewOrderDetails
-                GatherSpecialIngredients
-                PrepareSpecialItem
-                PackageForCustomer
-            }
-        }
-
-        // Regular daily baking
-        then daily_bread {
-            then sourdough {
-                MixDough(recipe: "sourdough", quantity: 10)
-                KneadDough(duration: 15m)
-                FirstRise(duration: 2h)
-                ShapLoaves
-                SecondRise(duration: 1h)
-                BakeLoaves(temperature: 230, duration: 35m)
-            }
-        }
-
-        // Pastries if time permits
-        then pastries {
-            succeed_always {
-                then apple_pastries {
-                    PrepareFillingApple
-                    RollPastryDough
-                    AssemblePastries
-                    BakePastries(temperature: 200, duration: 25m)
-                }
-            }
-        }
-    }
-}
-
-

Customer Service

-
behavior ServeCustomer {
-    then service_sequence {
-        GreetCustomer
-        if(customer_is_regular) {
-            RecallPreferences
-        }
-
-        choose service_type {
-            then take_order {
-                if(customer_knows_what_they_want)
-                AcceptOrder
-                PackageItem
-            }
-
-            then help_decide {
-                if(not customer_knows_what_they_want)
-                OfferRecommendation
-                ProvidesSample
-                AcceptOrder
-                PackageItem
-            }
-        }
-
-        CollectPayment
-        ThankCustomer
-    }
-}
-
-

Emergency Handling

-
behavior HandleEmergency {
-    choose emergency_type {
-        then oven_fire {
-            if(oven_overheating)
-            TurnOffOven
-            GrabFireExtinguisher
-            ExtinguishFire
-            AssessDamage
-        }
-
-        then ingredient_shortage {
-            if(critical_ingredient_missing)
-            CheckBackupSupply
-            choose procurement {
-                SendApprenticeToMarket
-                SubstituteIngredient
-                AdjustMenu
-            }
-        }
-
-        then equipment_failure {
-            if(equipment_broken)
-            StopProduction
-            AttemptQuickFix
-            choose fallback {
-                UseBackupEquipment
-                CallRepairPerson
-            }
-        }
-    }
-}
-
-

Life Arc: Career and Energy

-
life_arc MarthaEnergyLevel {
-    state rested {
-        on enter {
-            Martha.energy: 1.0
-            Martha.mood: 0.8
-        }
-        on energy < 0.5 -> tired
-    }
-
-    state tired {
-        on enter {
-            Martha.mood: 0.6
-        }
-        on energy < 0.2 -> exhausted
-        on energy > 0.7 -> rested
-    }
-
-    state exhausted {
-        on enter {
-            Martha.mood: 0.3
-            Martha.quality_output: 0.7
-        }
-        on energy > 0.5 -> tired
-    }
-}
-
-

Relationships

-
relationship MarthaAndApprentice {
-    Martha as mentor self {
-        patience: 0.8
-        investment: 0.9
-    } other {
-        sees_potential: 0.85
-    }
-
-    Elena as apprentice self {
-        dedication: 0.9
-        learning_rate: 0.7
-    } other {
-        respect: 0.95
-        admiration: 0.8
-    }
-
-    bond: 0.85
-    years_together: 2
-}
-
-relationship MarthaAndRegularCustomer {
-    Martha as shopkeeper
-    OldManGregory as regular_customer
-
-    bond: 0.7
-    years_known: 15
-    always_orders: "sourdough_loaf"
-
-    ---dynamics
-    Gregory has been buying Martha's bread every morning for
-    fifteen years. They exchange brief pleasantries about the
-    weather and local gossip. He is her most reliable customer.
-    ---
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Schedule-driven daily flow: Precise time blocks govern Martha’s entire day
  2. -
  3. Seasonal and weekly variations: Summer hours and Saturday market
  4. -
  5. Layered behaviors: Emergency behavior preempts normal routine via priority
  6. -
  7. Realistic action sequences: Baking modeled step by step with parameters
  8. -
  9. Energy management: Life arc tracks fatigue affecting mood and output quality
  10. -
  11. Social connections: Relationships with apprentice and customers add depth
  12. -
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/examples/26-character-evolution.html b/docs/book/examples/26-character-evolution.html deleted file mode 100644 index b67c244..0000000 --- a/docs/book/examples/26-character-evolution.html +++ /dev/null @@ -1,552 +0,0 @@ - - - - - - Character Evolution - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Character Evolution

-

This example models a character who evolves through multiple life stages, demonstrating how life arcs, behavior trees, and templates work together to represent growth over time.

-

The Apprentice’s Journey

-

Elena starts as a nervous apprentice and grows into a confident master baker. Her evolution touches every aspect of her character: skills, personality, relationships, and daily routine.

-

Schema

-
enum SkillLevel { novice, beginner, intermediate, advanced, expert, master }
-
-enum Confidence { timid, uncertain, growing, steady, confident, commanding }
-
-template Apprentice {
-    skill_level: novice
-    confidence: timid
-    can_work_independently: false
-    recipes_mastered: 0..5
-}
-
-template Journeyman {
-    skill_level: intermediate
-    confidence: growing
-    can_work_independently: true
-    recipes_mastered: 10..30
-}
-
-template MasterBaker {
-    skill_level: master
-    confidence: commanding
-    can_work_independently: true
-    can_teach: true
-    recipes_mastered: 50..200
-}
-
-

The Character at Different Stages

-
// Elena starts as an apprentice
-character Elena: Human from Apprentice {
-    age: 16
-    natural_talent: 0.8
-    dedication: 0.9
-    recipes_mastered: 2
-    confidence: timid
-    mentor: Martha
-
-    ---backstory
-    Elena comes from a family of farmers who could never afford to
-    buy bread from the bakery. When Martha offered her an apprenticeship,
-    she jumped at the chance to learn a trade.
-    ---
-}
-
-

The Evolution Life Arc

-
life_arc ElenaCareer {
-    ---description
-    Tracks Elena's progression from nervous apprentice to
-    confident master baker over several years.
-    ---
-
-    state apprentice_early {
-        on enter {
-            Elena.skill_level: novice
-            Elena.confidence: timid
-            Elena.can_work_independently: false
-        }
-
-        on recipes_mastered > 5 -> apprentice_growing
-
-        ---narrative
-        Elena's hands shake as she measures flour. She checks the
-        recipe three times before adding each ingredient. Martha
-        patiently corrects her technique.
-        ---
-    }
-
-    state apprentice_growing {
-        on enter {
-            Elena.skill_level: beginner
-            Elena.confidence: uncertain
-        }
-
-        on recipes_mastered > 15 -> journeyman
-
-        ---narrative
-        The shaking stops. Elena can make basic breads without
-        looking at the recipe. She still doubts herself but
-        Martha's encouragement is taking root.
-        ---
-    }
-
-    state journeyman {
-        on enter {
-            Elena.skill_level: intermediate
-            Elena.confidence: growing
-            Elena.can_work_independently: true
-        }
-
-        on recipes_mastered > 30 and confidence is steady -> senior_journeyman
-
-        ---narrative
-        Elena runs the morning shift alone while Martha handles
-        special orders. Customers start asking for "Elena's rolls."
-        She begins experimenting with her own recipes.
-        ---
-    }
-
-    state senior_journeyman {
-        on enter {
-            Elena.skill_level: advanced
-            Elena.confidence: steady
-        }
-
-        on recipes_mastered > 50 and passed_master_trial -> master
-
-        ---narrative
-        Elena develops her signature recipe: rosemary olive bread
-        that becomes the bakery's bestseller. She handles difficult
-        customers with grace and trains new helpers.
-        ---
-    }
-
-    state master {
-        on enter {
-            Elena.skill_level: master
-            Elena.confidence: commanding
-            Elena.can_teach: true
-        }
-
-        ---narrative
-        Master Baker Elena. She has earned it. The guild acknowledges
-        her mastery, and Martha beams with pride. Elena begins
-        mentoring her own apprentice.
-        ---
-    }
-}
-
-

Evolving Behaviors

-

Elena’s behavior changes as she progresses:

-
// Early apprentice: hesitant, checks everything
-behavior Elena_ApprenticeEarly {
-    then cautious_baking {
-        CheckRecipeThreeTimes
-        MeasureCarefully
-        AskMarthaForConfirmation
-        ProceedSlowly
-        CheckResultAnxiously
-    }
-}
-
-// Growing apprentice: more confident
-behavior Elena_ApprenticeGrowing {
-    then competent_baking {
-        ReviewRecipe
-        MeasureIngredients
-        MixWithConfidence
-        choose problem_handling {
-            then handle_alone {
-                if(confidence > 0.4)
-                AssessSituation
-                ApplyLearning
-            }
-            AskMarthaForHelp
-        }
-    }
-}
-
-// Journeyman: independent and creative
-behavior Elena_Journeyman {
-    choose work_mode {
-        then creative_mode {
-            if(inspiration_high)
-            ExperimentWithRecipe
-            TasteTest
-            if(result_good) {
-                RecordNewRecipe
-            }
-        }
-
-        then production_mode {
-            ExecuteRecipeFromMemory
-            MonitorOvenTimings
-            ManageMultipleBatches
-        }
-
-        then teaching_mode {
-            if(helper_present)
-            DemonstrateTeechnique
-            ObserveHelper
-            ProvideGentleFeedback
-        }
-    }
-}
-
-// Master: leadership and mentoring
-behavior Elena_Master {
-    choose master_activity {
-        then mentor_apprentice {
-            if(apprentice_needs_guidance)
-            AssessApprenticeProgress
-            DesignLearningChallenge
-            ObserveAndFeedback
-        }
-
-        then innovate {
-            if(creative_energy_high)
-            ResearchNewTechniques
-            ExperimentWithIngredients
-            DocumentFindings
-        }
-
-        then lead_production {
-            PlanDailyProduction
-            DelegateToTeam
-            QualityCheckResults
-        }
-    }
-}
-
-

Evolving Relationships

-

The mentor relationship changes as Elena grows:

-
// Early apprenticeship
-relationship EarlyMentorship {
-    Martha as mentor self {
-        patience: 0.9
-        teaching_intensity: 0.8
-    } other {
-        sees_potential: 0.8
-        reminds_her_of_herself: true
-    }
-
-    Elena as apprentice self {
-        gratitude: 1.0
-        anxiety: 0.7
-    } other {
-        admiration: 0.95
-        intimidated: 0.5
-    }
-
-    bond: 0.6
-}
-
-// Later: colleagues and friends
-relationship MaturePartnership {
-    Martha as senior_partner self {
-        pride_in_elena: 0.95
-        ready_to_step_back: 0.6
-    } other {
-        sees_equal: 0.8
-        trusts_judgment: 0.9
-    }
-
-    Elena as junior_partner self {
-        confidence: 0.85
-        gratitude: 0.9
-    } other {
-        respect: 0.95
-        sees_as_mother_figure: 0.7
-    }
-
-    bond: 0.95
-}
-
-

Evolving Schedules

-

Elena’s schedule changes as she takes on more responsibility:

-
// Apprentice schedule: supervised hours
-schedule ElenaApprentice {
-    block arrive {
-        06:00 - 06:15
-        action: routines::arrive_early
-    }
-
-    block learn_and_assist {
-        06:15 - 14:00
-        action: baking::assist_martha
-    }
-
-    block cleanup_duty {
-        14:00 - 15:00
-        action: shop::cleanup
-    }
-
-    block study {
-        15:00 - 16:00
-        action: learning::study_recipes
-    }
-}
-
-// Master schedule: leadership hours
-schedule ElenaMaster extends ElenaApprentice {
-    block arrive {
-        04:00 - 04:15
-        action: routines::open_bakery
-    }
-
-    block learn_and_assist {
-        04:15 - 12:00
-        action: baking::lead_production
-    }
-
-    block cleanup_duty {
-        12:00 - 13:00
-        action: social::lunch_with_team
-    }
-
-    block study {
-        13:00 - 15:00
-        action: baking::mentor_apprentice
-    }
-
-    block business {
-        15:00 - 17:00
-        action: management::business_planning
-    }
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Life arcs as character development: Elena’s career progression modeled as states
  2. -
  3. Evolving behaviors: Different behavior trees for each stage of growth
  4. -
  5. Changing relationships: The mentor dynamic shifts from dependency to partnership
  6. -
  7. Schedule evolution: Responsibilities grow with skill level
  8. -
  9. Narrative prose: Each life arc state tells a story about who Elena is becoming
  10. -
  11. Template progression: Templates define the capability profile at each stage
  12. -
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/examples/27-multi-character.html b/docs/book/examples/27-multi-character.html deleted file mode 100644 index 4c68c64..0000000 --- a/docs/book/examples/27-multi-character.html +++ /dev/null @@ -1,737 +0,0 @@ - - - - - - Multi-Character Interactions - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Multi-Character Interactions

-

This example models a complex social scene: a busy Saturday morning at Martha’s bakery. Multiple characters interact simultaneously with interlocking behaviors, relationships, and a shared location buzzing with activity.

-

The Setting

-
enum RushLevel { calm, busy, hectic, overwhelming }
-enum ServiceMode { normal, rush, emergency }
-
-location BakeryStorefront {
-    rush_level: busy
-    current_time: 07:30
-    customers_waiting: 8
-    display_items_remaining: 45
-    oven_batches_in_progress: 3
-    coffee_machine_running: true
-
-    ---description
-    Saturday morning at Martha's bakery. The line stretches out
-    the door. The display case gleams with fresh bread, pastries,
-    and Elena's famous rosemary olive rolls. The air is warm with
-    the smell of baking and the hum of conversation.
-    ---
-
-    ---atmosphere
-    This is the bakery at its best and most stressful. Every
-    Saturday brings the regulars, the farmers' market overflow,
-    and tourists who heard about Martha's sourdough. The whole
-    team works in concert to keep up.
-    ---
-}
-
-institution SaturdayMorningCrew {
-    type: work_team
-    purpose: serve_customers_and_bake
-    members: 4
-    coordination_level: 0.9
-
-    ---description
-    The Saturday crew operates like a well-oiled machine. Martha
-    runs the kitchen, Jane handles pastries, Elena manages the
-    front counter, and Gregory -- the loyal regular -- unofficially
-    helps direct the line.
-    ---
-}
-
-

The Characters

-
use schema::core_enums::{SkillLevel, Confidence, Specialty};
-use schema::templates::{Baker, BusinessOwner, Apprentice};
-use schema::beings::Human;
-
-character Martha: Human from Baker, BusinessOwner {
-    age: 34
-    specialty: sourdough
-    skill_level: master
-    confidence: commanding
-    energy: 0.8
-    stress_level: 0.4
-    loaves_baked_today: 24
-    orders_pending: 6
-
-    ---personality
-    Calm under pressure. Martha thrives on Saturday mornings --
-    the rush brings out her best. She coordinates the team with
-    quiet efficiency, stepping in wherever needed while keeping
-    the ovens running on schedule.
-    ---
-}
-
-character Jane: Human from Baker {
-    age: 36
-    specialty: pastries
-    skill_level: expert
-    confidence: confident
-    energy: 0.9
-    creative_mode: true
-    pastries_decorated_today: 18
-
-    ---personality
-    Jane works in focused silence during the rush. Her hands
-    move with precision, piping decorations and assembling
-    layered pastries. She communicates with Martha through
-    glances and nods -- years of partnership have made words
-    unnecessary.
-    ---
-}
-
-character Elena: Human from Apprentice {
-    age: 17
-    skill_level: intermediate
-    confidence: growing
-    energy: 1.0
-    customers_served_today: 32
-    mistakes_today: 1
-
-    ---personality
-    Elena has grown into the front-counter role. She remembers
-    regulars' names and orders, handles complaints with grace,
-    and only calls Martha when truly stuck. The nervous girl
-    who started a year ago is barely recognizable.
-    ---
-}
-
-character Gregory: Human {
-    age: 68
-    role: "regular_customer"
-    visits_today: 1
-    helping_with_line: true
-    knows_everyone: true
-
-    ---personality
-    Gregory arrives at exactly 7:15 every Saturday. He buys
-    his sourdough loaf, then lingers near the door, chatting
-    with other customers and unofficially managing the line.
-    He considers this his contribution to the bakery.
-    ---
-}
-
-

Interlocking Behaviors

-

Martha’s Behavior

-
behavior Martha_SaturdayMorning {
-    ---description
-    Martha's Saturday morning routine: managing the kitchen,
-    coordinating the team, and keeping the ovens running.
-    ---
-
-    repeat {
-        choose saturday_priority {
-            // Check ovens first (highest priority)
-            then oven_management {
-                if(oven_timer_near_done)
-                CheckOvenTemperature
-                RemoveFinishedBatch
-                LoadNextBatch
-                SetTimer
-            }
-
-            // Handle special orders
-            then special_orders {
-                if(has_special_orders)
-                choose order_type {
-                    PrepareWeddingCake
-                    BoxCustomOrder
-                    DecorateSpecialLoaf
-                }
-            }
-
-            // Support Elena at counter
-            then help_counter {
-                if(elena_needs_help)
-                choose counter_support {
-                    AnswerCustomerQuestion
-                    HandleComplaint
-                    ProcessLargeOrder
-                }
-            }
-
-            // Coordinate with Jane
-            then coordinate_pastries {
-                if(display_items_remaining < 10)
-                SignalJaneToRestockPastries
-                RearrangeDisplay
-            }
-
-            // Default: knead next batch
-            then prep_dough {
-                MixNextBatch
-                KneadDough
-                ShapeLoaves
-            }
-        }
-    }
-}
-
-

Jane’s Behavior

-
behavior Jane_SaturdayMorning {
-    repeat {
-        choose jane_priority {
-            // Restock display when signaled
-            then restock_pastries {
-                if(martha_signaled_restock)
-                PlateFinishedPastries
-                CarryToDisplay
-                ArrangeAttractively
-            }
-
-            // Decorate current batch
-            then decorating {
-                if(has_undecorated_pastries)
-                PipeIcing
-                AddGarnish
-                InspectQuality
-            }
-
-            // Start new pastry batch
-            then new_batch {
-                if(pastry_dough_ready)
-                RollPastryDough
-                CutShapes
-                AddFilling
-                PlaceOnBakingSheet
-            }
-
-            // Prepare specialty items
-            then specialty_items {
-                if(specialty_order_pending)
-                ReviewOrderNotes
-                SelectPremiumIngredients
-                CraftSpecialtyItem
-            }
-        }
-    }
-}
-
-

Elena’s Behavior

-
behavior Elena_SaturdayCounter {
-    choose counter_state {
-        // Serve waiting customers
-        then serve_customer {
-            if(customer_waiting)
-            then service_sequence {
-                GreetCustomer
-                if(customer_is_regular) {
-                    RecallPreferences
-                }
-
-                choose order_handling {
-                    then quick_order {
-                        if(customer_knows_what_they_want)
-                        AcceptOrder
-                        PackageItem
-                    }
-
-                    then help_decide {
-                        if(not customer_knows_what_they_want)
-                        OfferRecommendation
-                        OfferSample
-                        AcceptOrder
-                        PackageItem
-                    }
-                }
-
-                CollectPayment
-                ThankCustomer
-            }
-        }
-
-        // Handle problems
-        then handle_issue {
-            if(customer_has_complaint)
-            choose resolution {
-                then resolve_alone {
-                    if(confidence > 0.5)
-                    ListenCarefully
-                    OfferSolution
-                    ApplyResolution
-                }
-
-                then escalate {
-                    if(confidence <= 0.5)
-                    AcknowledgeProblem
-                    CallMarthaForHelp
-                }
-            }
-        }
-
-        // Manage the line
-        then manage_queue {
-            if(line_length > 5)
-            AnnounceWaitTime
-            SuggestPopularItems
-        }
-    }
-}
-
-

Gregory’s Behavior

-
behavior Gregory_SaturdayVisit {
-    then saturday_routine {
-        // Arrive and order
-        then arrival {
-            EnterBakery
-            GreetElena
-            OrderSourdoughLoaf
-            PayExactChange
-        }
-
-        // Linger and help
-        choose lingering_activity {
-            then manage_line {
-                if(line_is_long)
-                DirectNewCustomersToEndOfLine
-                ChatWithWaitingCustomers
-                RecommendPopularItems
-            }
-
-            then catch_up {
-                if(sees_familiar_face)
-                GreetNeighbor
-                ExchangeLocalNews
-                DiscussWeather
-            }
-
-            then observe_elena {
-                if(elena_handling_difficult_customer)
-                StandNearbyForMoralSupport
-                NodEncouragingly
-            }
-        }
-
-        // Eventually leave
-        then departure {
-            WaveToMartha
-            SayGoodbyeToElena
-            ExitWithBread
-        }
-    }
-}
-
-

Relationships

-
relationship BakeryPartnership {
-    Martha {
-        role: co_owner
-        coordination: 1.0
-        handles_bread: true
-
-        ---perspective
-        Martha and Jane communicate without words during the rush.
-        A glance toward the display case means "we're running low."
-        A nod means "I'll handle it." Years of working side by side
-        have created an effortless rhythm.
-        ---
-    }
-
-    Jane {
-        role: co_owner
-        coordination: 1.0
-        handles_pastries: true
-
-        ---perspective
-        Jane trusts Martha's judgment completely during the Saturday
-        rush. If Martha signals, Jane reprioritizes. If Jane needs
-        oven time, Martha adjusts. They are two halves of a single
-        well-run kitchen.
-        ---
-    }
-
-    bond: 0.95
-}
-
-relationship TeamAndApprentice {
-    Martha as mentor
-    Jane as senior_colleague
-    Elena as apprentice
-
-    bond: 0.8
-
-    ---dynamics
-    Elena looks up to both Martha and Jane, but in different ways.
-    Martha teaches her the fundamentals -- technique, discipline,
-    consistency. Jane shows her the creative side -- decoration,
-    presentation, flavor combinations. Together they are shaping
-    Elena into a complete baker.
-    ---
-}
-
-relationship GregoryAtTheBakery {
-    Gregory {
-        role: loyal_customer
-        attachment: 0.9
-        unofficial_helper: true
-
-        ---perspective
-        The bakery is Gregory's third place -- not home, not the
-        library where he used to teach, but the warm space where
-        he belongs. He has watched Elena grow from a nervous girl
-        to a confident young woman. He is proud, though he would
-        never say so directly.
-        ---
-    }
-
-    Elena {
-        role: counter_staff
-        fondness: 0.8
-        sees_as: "grandfather_figure"
-
-        ---perspective
-        Elena looks forward to Gregory's arrival every morning.
-        His exact-change payment and dry humor are a reliable
-        anchor in the chaos of the morning rush.
-        ---
-    }
-
-    bond: 0.7
-}
-
-

The Saturday Schedule

-
schedule SaturdayRush {
-    block early_prep {
-        03:00 - 06:00
-        action: baking::saturday_batch
-    }
-
-    block opening {
-        06:00 - 06:15
-        action: shop::open_doors
-    }
-
-    block morning_rush {
-        06:15 - 11:00
-        action: shop::saturday_rush_service
-    }
-
-    block midday_restock {
-        11:00 - 12:00
-        action: baking::midday_supplemental
-    }
-
-    block afternoon_wind_down {
-        12:00 - 14:00
-        action: shop::afternoon_sales
-    }
-
-    block close_and_clean {
-        14:00 - 15:00
-        action: shop::saturday_cleanup
-    }
-}
-
-

Life Arc: Elena’s Saturday Confidence

-
life_arc ElenaSaturdayGrowth {
-    state nervous_start {
-        on enter {
-            Elena.confidence: uncertain
-            Elena.energy: 1.0
-        }
-        on customers_served_today > 5 -> finding_rhythm
-
-        ---narrative
-        The first few customers are always the hardest. Elena
-        fumbles with the register, second-guesses prices, and
-        looks to Martha for confirmation. But each successful
-        transaction builds her up.
-        ---
-    }
-
-    state finding_rhythm {
-        on enter {
-            Elena.confidence: growing
-        }
-        on customers_served_today > 15 -> in_the_zone
-
-        ---narrative
-        Something clicks. Elena stops thinking about each step
-        and starts flowing. She remembers Mrs. Patterson's usual
-        order before she says it. She bags the croissants without
-        looking.
-        ---
-    }
-
-    state in_the_zone {
-        on enter {
-            Elena.confidence: confident
-        }
-        on handled_complaint_alone -> proud_moment
-        on energy < 0.3 -> running_on_fumes
-
-        ---narrative
-        Elena is running the counter like she was born to it.
-        Gregory gives her a quiet nod of approval from his spot
-        by the door. She barely notices -- she is too busy being
-        competent.
-        ---
-    }
-
-    state proud_moment {
-        on enter {
-            Elena.confidence: confident
-            Elena.self_respect: 0.9
-        }
-
-        ---narrative
-        A customer complained about a stale roll. Elena apologized,
-        replaced it with a fresh one, and offered a free cookie.
-        The customer left smiling. Elena handled it alone, without
-        calling Martha. She stands a little taller afterward.
-        ---
-    }
-
-    state running_on_fumes {
-        on enter {
-            Elena.energy: 0.2
-            Elena.confidence: uncertain
-        }
-        on break_taken -> finding_rhythm
-
-        ---narrative
-        The rush has been going for four hours. Elena's smile
-        is getting harder to maintain. Martha notices and sends
-        her to the back for a five-minute break and a pastry.
-        ---
-    }
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Multiple characters with interlocking behaviors: Martha, Jane, Elena, and Gregory react to each other
  2. -
  3. Character coordination: Martha and Jane operate as a seamless team
  4. -
  5. Asymmetric group dynamics: Gregory is an unofficial helper, Elena is growing into her role
  6. -
  7. Location as context: The busy bakery storefront defines the scene
  8. -
  9. Institution modeling: The Saturday crew as a coordinated work team
  10. -
  11. Visitor arc: Elena’s confidence through the Saturday rush modeled as a life arc
  12. -
  13. Rich prose: Every character and relationship includes narrative perspective
  14. -
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/favicon.png b/docs/book/favicon.png deleted file mode 100644 index a5b1aa1..0000000 Binary files a/docs/book/favicon.png and /dev/null differ diff --git a/docs/book/favicon.svg b/docs/book/favicon.svg deleted file mode 100644 index 90e0ea5..0000000 --- a/docs/book/favicon.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/docs/book/fonts/OPEN-SANS-LICENSE.txt b/docs/book/fonts/OPEN-SANS-LICENSE.txt deleted file mode 100644 index d645695..0000000 --- a/docs/book/fonts/OPEN-SANS-LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/docs/book/fonts/SOURCE-CODE-PRO-LICENSE.txt b/docs/book/fonts/SOURCE-CODE-PRO-LICENSE.txt deleted file mode 100644 index 366206f..0000000 --- a/docs/book/fonts/SOURCE-CODE-PRO-LICENSE.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/book/fonts/fonts.css b/docs/book/fonts/fonts.css deleted file mode 100644 index 858efa5..0000000 --- a/docs/book/fonts/fonts.css +++ /dev/null @@ -1,100 +0,0 @@ -/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */ -/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */ - -/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 300; - src: local('Open Sans Light'), local('OpenSans-Light'), - url('open-sans-v17-all-charsets-300.woff2') format('woff2'); -} - -/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 300; - src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'), - url('open-sans-v17-all-charsets-300italic.woff2') format('woff2'); -} - -/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 400; - src: local('Open Sans Regular'), local('OpenSans-Regular'), - url('open-sans-v17-all-charsets-regular.woff2') format('woff2'); -} - -/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 400; - src: local('Open Sans Italic'), local('OpenSans-Italic'), - url('open-sans-v17-all-charsets-italic.woff2') format('woff2'); -} - -/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 600; - src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), - url('open-sans-v17-all-charsets-600.woff2') format('woff2'); -} - -/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 600; - src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'), - url('open-sans-v17-all-charsets-600italic.woff2') format('woff2'); -} - -/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 700; - src: local('Open Sans Bold'), local('OpenSans-Bold'), - url('open-sans-v17-all-charsets-700.woff2') format('woff2'); -} - -/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 700; - src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), - url('open-sans-v17-all-charsets-700italic.woff2') format('woff2'); -} - -/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: normal; - font-weight: 800; - src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), - url('open-sans-v17-all-charsets-800.woff2') format('woff2'); -} - -/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Open Sans'; - font-style: italic; - font-weight: 800; - src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'), - url('open-sans-v17-all-charsets-800italic.woff2') format('woff2'); -} - -/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */ -@font-face { - font-family: 'Source Code Pro'; - font-style: normal; - font-weight: 500; - src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2'); -} diff --git a/docs/book/fonts/open-sans-v17-all-charsets-300.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-300.woff2 deleted file mode 100644 index 9f51be3..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-300.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-300italic.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-300italic.woff2 deleted file mode 100644 index 2f54544..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-300italic.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-600.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-600.woff2 deleted file mode 100644 index f503d55..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-600.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-600italic.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-600italic.woff2 deleted file mode 100644 index c99aabe..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-600italic.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-700.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-700.woff2 deleted file mode 100644 index 421a1ab..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-700.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-700italic.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-700italic.woff2 deleted file mode 100644 index 12ce3d2..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-700italic.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-800.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-800.woff2 deleted file mode 100644 index c94a223..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-800.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-800italic.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-800italic.woff2 deleted file mode 100644 index eed7d3c..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-800italic.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-italic.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-italic.woff2 deleted file mode 100644 index 398b68a..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-italic.woff2 and /dev/null differ diff --git a/docs/book/fonts/open-sans-v17-all-charsets-regular.woff2 b/docs/book/fonts/open-sans-v17-all-charsets-regular.woff2 deleted file mode 100644 index 8383e94..0000000 Binary files a/docs/book/fonts/open-sans-v17-all-charsets-regular.woff2 and /dev/null differ diff --git a/docs/book/fonts/source-code-pro-v11-all-charsets-500.woff2 b/docs/book/fonts/source-code-pro-v11-all-charsets-500.woff2 deleted file mode 100644 index 7222456..0000000 Binary files a/docs/book/fonts/source-code-pro-v11-all-charsets-500.woff2 and /dev/null differ diff --git a/docs/book/highlight.css b/docs/book/highlight.css deleted file mode 100644 index 352c79b..0000000 --- a/docs/book/highlight.css +++ /dev/null @@ -1,83 +0,0 @@ -/* - * An increased contrast highlighting scheme loosely based on the - * "Base16 Atelier Dune Light" theme by Bram de Haan - * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) - * Original Base16 color scheme by Chris Kempson - * (https://github.com/chriskempson/base16) - */ - -/* Comment */ -.hljs-comment, -.hljs-quote { - color: #575757; -} - -/* Red */ -.hljs-variable, -.hljs-template-variable, -.hljs-attribute, -.hljs-attr, -.hljs-tag, -.hljs-name, -.hljs-regexp, -.hljs-link, -.hljs-name, -.hljs-selector-id, -.hljs-selector-class { - color: #d70025; -} - -/* Orange */ -.hljs-number, -.hljs-meta, -.hljs-built_in, -.hljs-builtin-name, -.hljs-literal, -.hljs-type, -.hljs-params { - color: #b21e00; -} - -/* Green */ -.hljs-string, -.hljs-symbol, -.hljs-bullet { - color: #008200; -} - -/* Blue */ -.hljs-title, -.hljs-section { - color: #0030f2; -} - -/* Purple */ -.hljs-keyword, -.hljs-selector-tag { - color: #9d00ec; -} - -.hljs { - display: block; - overflow-x: auto; - background: #f6f7f6; - color: #000; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} - -.hljs-addition { - color: #22863a; - background-color: #f0fff4; -} - -.hljs-deletion { - color: #b31d28; - background-color: #ffeef0; -} diff --git a/docs/book/highlight.js b/docs/book/highlight.js deleted file mode 100644 index 18d2434..0000000 --- a/docs/book/highlight.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - Highlight.js 10.1.1 (93fd0d73) - License: BSD-3-Clause - Copyright (c) 2006-2020, Ivan Sagalaev -*/ -var hljs=function(){"use strict";function e(n){Object.freeze(n);var t="function"==typeof n;return Object.getOwnPropertyNames(n).forEach((function(r){!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r])})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data}ignoreMatch(){this.ignore=!0}}function t(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function r(e,...n){var t={};for(const n in e)t[n]=e[n];return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null,escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){var i=0,s="",o=[];function l(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){s+=""}function d(e){("start"===e.event?c:u)(e.node)}for(;e.length||n.length;){var g=l();if(s+=t(r.substring(i,g[0].offset)),i=g[0].offset,g===e){o.reverse().forEach(u);do{d(g.splice(0,1)[0]),g=l()}while(g===e&&g.length&&g[0].offset===i);o.reverse().forEach(c)}else"start"===g[0].event?o.push(g[0].node):o.pop(),d(g.splice(0,1)[0])}return s+t(r.substr(i))}});const s="",o=e=>!!e.kind;class l{constructor(e,n){this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){this.buffer+=t(e)}openNode(e){if(!o(e))return;let n=e.kind;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){o(e)&&(this.buffer+=s)}value(){return this.buffer}span(e){this.buffer+=``}}class c{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){this.top.children.push(e)}openNode(e){const n={kind:e,children:[]};this.add(n),this.stack.push(n)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n),n.children.forEach(n=>this._walk(e,n)),e.closeNode(n)),e}static _collapse(e){"string"!=typeof e&&e.children&&(e.children.every(e=>"string"==typeof e)?e.children=[e.children.join("")]:e.children.forEach(e=>{c._collapse(e)}))}}class u extends c{constructor(e){super(),this.options=e}addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())}addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){return new l(this,this.options).value()}finalize(){return!0}}function d(e){return e?"string"==typeof e?e:e.source:null}const g="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",h={begin:"\\\\[\\s\\S]",relevance:0},f={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[h]},p={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[h]},b={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},m=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[]},t);return a.contains.push(b),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a},v=m("//","$"),x=m("/\\*","\\*/"),E=m("#","$");var _=Object.freeze({__proto__:null,IDENT_RE:"[a-zA-Z]\\w*",UNDERSCORE_IDENT_RE:"[a-zA-Z_]\\w*",NUMBER_RE:"\\b\\d+(\\.\\d+)?",C_NUMBER_RE:g,BINARY_NUMBER_RE:"\\b(0b[01]+)",RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){return e.map(e=>d(e)).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:h,APOS_STRING_MODE:f,QUOTE_STRING_MODE:p,PHRASAL_WORDS_MODE:b,COMMENT:m,C_LINE_COMMENT_MODE:v,C_BLOCK_COMMENT_MODE:x,HASH_COMMENT_MODE:E,NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?",relevance:0},C_NUMBER_MODE:{className:"number",begin:g,relevance:0},BINARY_NUMBER_MODE:{className:"number",begin:"\\b(0b[01]+)",relevance:0},CSS_NUMBER_MODE:{className:"number",begin:"\\b\\d+(\\.\\d+)?(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[h,{begin:/\[/,end:/\]/,relevance:0,contains:[h]}]}]},TITLE_MODE:{className:"title",begin:"[a-zA-Z]\\w*",relevance:0},UNDERSCORE_TITLE_MODE:{className:"title",begin:"[a-zA-Z_]\\w*",relevance:0},METHOD_GUARD:{begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})}}),N="of and for in not or if then".split(" ");function w(e,n){return n?+n:function(e){return N.includes(e.toLowerCase())}(e)?0:1}const R=t,y=r,{nodeStream:k,mergeStreams:O}=i,M=Symbol("nomatch");return function(t){var a=[],i={},s={},o=[],l=!0,c=/(^(<[^>]+>|\t|)+|\n)/gm,g="Could not find the language '{}', did you forget to load/include a language module?";const h={disableAutodetect:!0,name:"Plain text",contains:[]};var f={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:u};function p(e){return f.noHighlightRe.test(e)}function b(e,n,t,r){var a={code:n,language:e};S("before:highlight",a);var i=a.result?a.result:m(a.language,a.code,t,r);return i.code=a.code,S("after:highlight",i),i}function m(e,t,a,s){var o=t;function c(e,n){var t=E.case_insensitive?n[0].toLowerCase():n[0];return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]}function u(){null!=y.subLanguage?function(){if(""!==A){var e=null;if("string"==typeof y.subLanguage){if(!i[y.subLanguage])return void O.addText(A);e=m(y.subLanguage,A,!0,k[y.subLanguage]),k[y.subLanguage]=e.top}else e=v(A,y.subLanguage.length?y.subLanguage:null);y.relevance>0&&(I+=e.relevance),O.addSublanguage(e.emitter,e.language)}}():function(){if(!y.keywords)return void O.addText(A);let e=0;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(A),t="";for(;n;){t+=A.substring(e,n.index);const r=c(y,n);if(r){const[e,a]=r;O.addText(t),t="",I+=a,O.addKeyword(n[0],e)}else t+=n[0];e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(A)}t+=A.substr(e),O.addText(t)}(),A=""}function h(e){return e.className&&O.openNode(e.className),y=Object.create(e,{parent:{value:y}})}function p(e){return 0===y.matcher.regexIndex?(A+=e[0],1):(L=!0,0)}var b={};function x(t,r){var i=r&&r[0];if(A+=t,null==i)return u(),0;if("begin"===b.type&&"end"===r.type&&b.index===r.index&&""===i){if(A+=o.slice(r.index,r.index+1),!l){const n=Error("0 width match regex");throw n.languageName=e,n.badRule=b.rule,n}return 1}if(b=r,"begin"===r.type)return function(e){var t=e[0],r=e.rule;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]];for(const n of i)if(n&&(n(e,a),a.ignore))return p(t);return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")),r.skip?A+=t:(r.excludeBegin&&(A+=t),u(),r.returnBegin||r.excludeBegin||(A=t)),h(r),r.returnBegin?0:t.length}(r);if("illegal"===r.type&&!a){const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"');throw e.mode=y,e}if("end"===r.type){var s=function(e){var t=e[0],r=o.substr(e.index),a=function e(t,r,a){let i=function(e,n){var t=e&&e.exec(n);return t&&0===t.index}(t.endRe,a);if(i){if(t["on:end"]){const e=new n(t);t["on:end"](r,e),e.ignore&&(i=!1)}if(i){for(;t.endsParent&&t.parent;)t=t.parent;return t}}if(t.endsWithParent)return e(t.parent,r,a)}(y,e,r);if(!a)return M;var i=y;i.skip?A+=t:(i.returnEnd||i.excludeEnd||(A+=t),u(),i.excludeEnd&&(A=t));do{y.className&&O.closeNode(),y.skip||y.subLanguage||(I+=y.relevance),y=y.parent}while(y!==a.parent);return a.starts&&(a.endSameAsBegin&&(a.starts.endRe=a.endRe),h(a.starts)),i.returnEnd?0:t.length}(r);if(s!==M)return s}if("illegal"===r.type&&""===i)return 1;if(B>1e5&&B>3*r.index)throw Error("potential infinite loop, way more iterations than matches");return A+=i,i.length}var E=T(e);if(!E)throw console.error(g.replace("{}",e)),Error('Unknown language: "'+e+'"');var _=function(e){function n(n,t){return RegExp(d(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(e,n){n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]),this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const e=this.regexes.map(e=>e[1]);this.matcherRe=n(function(e,n="|"){for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o);if(null==l){a+=o;break}a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length),"\\"===l[0][0]&&l[1]?a+="\\"+(+l[1]+s):(a+=l[0],"("===l[0]&&r++)}a+=")"}return a}(e),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e);if(!n)return null;const t=n.findIndex((e,n)=>n>0&&void 0!==e),r=this.matchIndexes[t];return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t;return this.rules.slice(e).forEach(([e,t])=>n.addRule(e,t)),n.compile(),this.multiRegexes[e]=n,n}considerAll(){this.regexIndex=0}addRule(e,n){this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex;const t=n.exec(e);return t&&(this.regexIndex+=t.position+1,this.regexIndex===this.count&&(this.regexIndex=0)),t}}function i(e,n){const t=e.input[e.index-1],r=e.input[e.index+e[0].length];"."!==t&&"."!==r||n.ignoreMatch()}if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return function t(s,o){const l=s;if(s.compiled)return l;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords;let c=null;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=function(e,n){var t={};return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){r(n,e[n])})),t;function r(e,r){n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|");t[r[0]]=[e,w(r[0],r[1])]}))}}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0),o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)",s.__beforeBegin=i),s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(l.endRe=n(s.end)),l.terminator_end=d(s.end)||"",s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)),s.illegal&&(l.illegalRe=n(s.illegal)),void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(e){return function(e){return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:function e(n){return!!n&&(n.endsWithParent||e(n.starts))}(e)?r(e,{starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e)}))),s.contains.forEach((function(e){t(e,l)})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a;return e.contains.forEach(e=>n.addRule(e.begin,{rule:e,type:"begin"})),e.terminator_end&&n.addRule(e.terminator_end,{type:"end"}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}(E),N="",y=s||_,k={},O=new f.__emitter(f);!function(){for(var e=[],n=y;n!==E;n=n.parent)n.className&&e.unshift(n.className);e.forEach(e=>O.openNode(e))}();var A="",I=0,S=0,B=0,L=!1;try{for(y.matcher.considerAll();;){B++,L?L=!1:(y.matcher.lastIndex=S,y.matcher.considerAll());const e=y.matcher.exec(o);if(!e)break;const n=x(o.substring(S,e.index),e);S=e.index+n}return x(o.substr(S)),O.closeAllNodes(),O.finalize(),N=O.toHTML(),{relevance:I,value:N,language:e,illegal:!1,emitter:O,top:y}}catch(n){if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:n.message,context:o.slice(S-100,S+100),mode:n.mode},sofar:N,relevance:0,value:R(o),emitter:O};if(l)return{illegal:!1,relevance:0,value:R(o),emitter:O,language:e,top:y,errorRaised:n};throw n}}function v(e,n){n=n||f.languages||Object.keys(i);var t=function(e){const n={relevance:0,emitter:new f.__emitter(f),value:R(e),illegal:!1,top:h};return n.emitter.addText(e),n}(e),r=t;return n.filter(T).filter(I).forEach((function(n){var a=m(n,e,!1);a.language=n,a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a)})),r.language&&(t.second_best=r),t}function x(e){return f.tabReplace||f.useBR?e.replace(c,e=>"\n"===e?f.useBR?"
":e:f.tabReplace?e.replace(/\t/g,f.tabReplace):e):e}function E(e){let n=null;const t=function(e){var n=e.className+" ";n+=e.parentNode?e.parentNode.className:"";const t=f.languageDetectRe.exec(n);if(t){var r=T(t[1]);return r||(console.warn(g.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)),r?t[1]:"no-highlight"}return n.split(/\s+/).find(e=>p(e)||T(e))}(e);if(p(t))return;S("before:highlightBlock",{block:e,language:t}),f.useBR?(n=document.createElement("div")).innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n"):n=e;const r=n.textContent,a=t?b(t,r,!0):v(r),i=k(n);if(i.length){const e=document.createElement("div");e.innerHTML=a.value,a.value=O(i,k(e),r)}a.value=x(a.value),S("after:highlightBlock",{block:e,result:a}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?s[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),e.includes(r)||a.push(r),a.join(" ").trim()}(e.className,t,a.language),e.result={language:a.language,re:a.relevance,relavance:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance,relavance:a.second_best.relevance})}const N=()=>{if(!N.called){N.called=!0;var e=document.querySelectorAll("pre code");a.forEach.call(e,E)}};function T(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}function A(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach(e=>{s[e]=n})}function I(e){var n=T(e);return n&&!n.disableAutodetect}function S(e,n){var t=e;o.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:b,highlightAuto:v,fixMarkup:x,highlightBlock:E,configure:function(e){f=y(f,e)},initHighlighting:N,initHighlightingOnLoad:function(){window.addEventListener("DOMContentLoaded",N,!1)},registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)),!l)throw n;console.error(n),r=h}r.name||(r.name=e),i[e]=r,r.rawDefinition=n.bind(null,t),r.aliases&&A(r.aliases,{languageName:e})},listLanguages:function(){return Object.keys(i)},getLanguage:T,registerAliases:A,requireLanguage:function(e){var n=T(e);if(n)return n;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))},autoDetection:I,inherit:y,addPlugin:function(e){o.push(e)}}),t.debugMode=function(){l=!1},t.safeMode=function(){l=!0},t.versionString="10.1.1";for(const n in _)"object"==typeof _[n]&&e(_[n]);return Object.assign(t,_),t}({})}();"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); -hljs.registerLanguage("apache",function(){"use strict";return function(e){var n={className:"number",begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{name:"Apache config",aliases:["apacheconf"],case_insensitive:!0,contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"",contains:[n,{className:"number",begin:":\\d{1,5}"},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute",begin:/\w+/,relevance:0,keywords:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"},contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable",begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number",begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]}}],illegal:/\S/}}}()); -hljs.registerLanguage("bash",function(){"use strict";return function(e){const s={};Object.assign(s,{className:"variable",variants:[{begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:[{begin:/:-/,contains:[s]}]}]});const t={className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},n={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,t]};t.contains.push(n);const a={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},i=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b-?[a-z\._]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},contains:[i,e.SHEBANG(),c,a,e.HASH_COMMENT_MODE,n,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}}()); -hljs.registerLanguage("c-like",function(){"use strict";return function(e){function t(e){return"(?:"+e+")?"}var n="(decltype\\(auto\\)|"+t("[a-zA-Z_]\\w*::")+"[a-zA-Z_]\\w*"+t("<.*?>")+")",r={className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},a={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",end:"'",illegal:"."},e.END_SAME_AS_BEGIN({begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},i={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"},contains:[{begin:/\\\n/,relevance:0},e.inherit(a,{className:"meta-string"}),{className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},o={className:"title",begin:t("[a-zA-Z_]\\w*::")+e.IDENT_RE,relevance:0},c=t("[a-zA-Z_]\\w*::")+e.IDENT_RE+"\\s*\\(",l={keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq",built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary",literal:"true false nullptr NULL"},d=[r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,i,a],_={variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],keywords:l,contains:d.concat([{begin:/\(/,end:/\)/,keywords:l,contains:d.concat(["self"]),relevance:0}]),relevance:0},u={className:"function",begin:"("+n+"[\\*&\\s]+)+"+c,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:l,illegal:/[^\w\s\*&:<>]/,contains:[{begin:"decltype\\(auto\\)",keywords:l,relevance:0},{begin:c,returnBegin:!0,contains:[o],relevance:0},{className:"params",begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r,{begin:/\(/,end:/\)/,keywords:l,relevance:0,contains:["self",e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,i,r]}]},r,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s]};return{aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:l,disableAutodetect:!0,illegal:"",keywords:l,contains:["self",r]},{begin:e.IDENT_RE+"::",keywords:l},{className:"class",beginKeywords:"class struct",end:/[{;:]/,contains:[{begin://,contains:["self"]},e.TITLE_MODE]}]),exports:{preprocessor:s,strings:a,keywords:l}}}}()); -hljs.registerLanguage("c",function(){"use strict";return function(e){var n=e.getLanguage("c-like").rawDefinition();return n.name="C",n.aliases=["c","h"],n}}()); -hljs.registerLanguage("coffeescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((e=>n=>!e.includes(n))(["var","const","let","function","static"])).join(" "),literal:n.concat(["yes","no","on","off"]).join(" "),built_in:a.concat(["npm","print"]).join(" ")},i="[A-Za-z$_][0-9A-Za-z$_]*",s={className:"subst",begin:/#\{/,end:/}/,keywords:t},o=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?",relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/,contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE]},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,s]},{begin:/"/,end:/"/,contains:[r.BACKSLASH_ESCAPE,s]}]},{className:"regexp",variants:[{begin:"///",end:"///",contains:[s,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)",relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+i},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{begin:"```",end:"```"},{begin:"`",end:"`"}]}];s.contains=o;var c=r.inherit(r.TITLE_MODE,{begin:i}),l={className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/,end:/\)/,keywords:t,contains:["self"].concat(o)}]};return{name:"CoffeeScript",aliases:["coffee","cson","iced"],keywords:t,illegal:/\/\*/,contains:o.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{className:"function",begin:"^\\s*"+i+"\\s*=\\s*(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[c,l]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function",begin:"(\\(.*\\))?\\s*\\B[-=]>",end:"[-=]>",returnBegin:!0,contains:[l]}]},{className:"class",beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[c]},c]},{begin:i+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}()); -hljs.registerLanguage("cpp",function(){"use strict";return function(e){var t=e.getLanguage("c-like").rawDefinition();return t.disableAutodetect=!1,t.name="C++",t.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],t}}()); -hljs.registerLanguage("csharp",function(){"use strict";return function(e){var n={keyword:"abstract as base bool break byte case catch char checked const continue decimal default delegate do double enum event explicit extern finally fixed float for foreach goto if implicit in int interface internal is lock long object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this try typeof uint ulong unchecked unsafe ushort using virtual void volatile while add alias ascending async await by descending dynamic equals from get global group into join let nameof on orderby partial remove select set value var when where yield",literal:"null false true"},i=e.inherit(e.TITLE_MODE,{begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{begin:"\\b(0b[01']+)"},{begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)"}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]},t=e.inherit(s,{illegal:/\n/}),l={className:"subst",begin:"{",end:"}",keywords:n},r=e.inherit(l,{illegal:/\n/}),c={className:"string",begin:/\$"/,end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,r]},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},l]},g=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},{begin:'""'},r]});l.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE],r.contains=[g,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{illegal:/\n/})];var d={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i]},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{begin:"\x3c!--|--\x3e"},{begin:""}]}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",end:"$",keywords:{"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum"}},d,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",end:/[{;=]/,illegal:/[^\s:]/,contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{className:"meta-string",begin:/"/,end:/"/}]},{beginKeywords:"new return throw await else",relevance:0},{className:"function",begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0,contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,contains:[d,a,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}()); -hljs.registerLanguage("css",function(){"use strict";return function(e){var n={begin:/(?:[A-Z\_\.\-]+|--[a-zA-Z0-9_-]+)\s*:/,returnBegin:!0,end:";",endsWithParent:!0,contains:[{className:"attribute",begin:/\S/,end:":",excludeEnd:!0,starts:{endsWithParent:!0,excludeEnd:!0,contains:[{begin:/[\w-]+\(/,returnBegin:!0,contains:[{className:"built_in",begin:/[\w-]+/},{begin:/\(/,end:/\)/,contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{className:"number",begin:"#[0-9A-Fa-f]+"},{className:"meta",begin:"!important"}]}}]};return{name:"CSS",case_insensitive:!0,illegal:/[=\/|'\$]/,contains:[e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/},{className:"selector-class",begin:/\.[A-Za-z0-9_-]+/},{className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",illegal:/:/,returnBegin:!0,contains:[{className:"keyword",begin:/@\-?\w[\w]*(\-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:"and or not only",contains:[{begin:/[a-z-]+:/,className:"attribute"},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}]},{className:"selector-tag",begin:"[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},{begin:"{",end:"}",illegal:/\S/,contains:[e.C_BLOCK_COMMENT_MODE,n]}]}}}()); -hljs.registerLanguage("diff",function(){"use strict";return function(e){return{name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,variants:[{begin:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{begin:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{begin:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{className:"comment",variants:[{begin:/Index: /,end:/$/},{begin:/={3,}/,end:/$/},{begin:/^\-{3}/,end:/$/},{begin:/^\*{3} /,end:/$/},{begin:/^\+{3}/,end:/$/},{begin:/^\*{15}$/}]},{className:"addition",begin:"^\\+",end:"$"},{className:"deletion",begin:"^\\-",end:"$"},{className:"addition",begin:"^\\!",end:"$"}]}}}()); -hljs.registerLanguage("go",function(){"use strict";return function(e){var n={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",literal:"true false iota nil",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{name:"Go",aliases:["golang"],keywords:n,illegal:"e(n)).join("")}return function(a){var s={className:"number",relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}]},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}]},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"],relevance:0},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map(n=>e(n)).join("|")+")";return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/,contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr",starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}()); -hljs.registerLanguage("java",function(){"use strict";function e(e){return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")}function a(...n){return n.map(n=>e(n)).join("")}function s(...n){return"("+n.map(n=>e(n)).join("|")+")"}return function(e){var t="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={className:"meta",begin:"@[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*",contains:[{begin:/\(/,end:/\)/,contains:["self"]}]},r=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{begin:`\\b(0[bB]${r("01")})[lL]?`},{begin:`\\b(0${r("0-7")})[dDfFlL]?`},{begin:a(/\b0[xX]/,s(a(r("a-fA-F0-9"),/\./,r("a-fA-F0-9")),a(r("a-fA-F0-9"),/\.?/),a(/\./,r("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/)},{begin:a(/\b/,s(a(/\d*\./,r("\\d")),r("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{begin:a(/\b/,r(/\d/),n(/\.?/),n(r(/\d/)),/[dDfFlL]?/)}],relevance:0};return{name:"Java",aliases:["jsp"],keywords:t,illegal:/<\/|#/,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/,relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"class",beginKeywords:"class interface",end:/[{;=]/,excludeEnd:!0,keywords:"class interface",illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"new throw return else",relevance:0},{className:"function",begin:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:t,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/,keywords:t,relevance:0,contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE]},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}()); -hljs.registerLanguage("javascript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function s(e){return r("(?=",e,")")}function r(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(t){var i="[A-Za-z$_][0-9A-Za-z$_]*",c={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/},o={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.join(" "),literal:n.join(" "),built_in:a.join(" ")},l={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:t.C_NUMBER_RE+"n?"}],relevance:0},E={className:"subst",begin:"\\$\\{",end:"\\}",keywords:o,contains:[]},d={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"xml"}},g={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[t.BACKSLASH_ESCAPE,E],subLanguage:"css"}},u={className:"string",begin:"`",end:"`",contains:[t.BACKSLASH_ESCAPE,E]};E.contains=[t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,l,t.REGEXP_MODE];var b=E.contains.concat([{begin:/\(/,end:/\)/,contains:["self"].concat(E.contains,[t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE])},t.C_BLOCK_COMMENT_MODE,t.C_LINE_COMMENT_MODE]),_={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:b};return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:o,contains:[t.SHEBANG({binary:"node",relevance:5}),{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},t.APOS_STRING_MODE,t.QUOTE_STRING_MODE,d,g,u,t.C_LINE_COMMENT_MODE,t.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type",begin:"\\{",end:"\\}",relevance:0},{className:"variable",begin:i+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}]}),t.C_BLOCK_COMMENT_MODE,l,{begin:r(/[{,\n]\s*/,s(r(/(((\/\/.*)|(\/\*(.|\n)*\*\/))\s*)*/,i+"\\s*:"))),relevance:0,contains:[{className:"attr",begin:i+s("\\s*:"),relevance:0}]},{begin:"("+t.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[t.C_LINE_COMMENT_MODE,t.C_BLOCK_COMMENT_MODE,t.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+t.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:t.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:o,contains:b}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:"<>",end:""},{begin:c.begin,end:c.end}],subLanguage:"xml",contains:[{begin:c.begin,end:c.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[t.inherit(t.TITLE_MODE,{begin:i}),_],illegal:/\[|%/},{begin:/\$[(.]/},t.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},t.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0},{begin:"(get|set)\\s+(?="+i+"\\()",end:/{/,keywords:"get set",contains:[t.inherit(t.TITLE_MODE,{begin:i}),{begin:/\(\)/},_]}],illegal:/#(?!!)/}}}()); -hljs.registerLanguage("json",function(){"use strict";return function(n){var e={literal:"true false null"},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{",end:"}",contains:[{className:"attr",begin:/"/,end:/"/,contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)],illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}()); -hljs.registerLanguage("kotlin",function(){"use strict";return function(e){var n={keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual trait volatile transient native default",built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing",literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@"},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string",variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'",illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/,contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta",begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?"},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/,end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}]},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}]},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword",begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol",begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$",returnBegin:!0,excludeEnd:!0,keywords:n,illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0,contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://,keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/,endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class",beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0,illegal:"extends implements",contains:[{beginKeywords:"public protected internal private constructor"},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/,excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env",end:"$",illegal:"\n"},{className:"number",begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0}]}}}()); -hljs.registerLanguage("less",function(){"use strict";return function(e){var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string",begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a}},i={begin:"\\(",end:"\\)",contains:s,relevance:0};s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]",excludeEnd:!0}},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}",contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0,end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":",excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}]},g={className:"keyword",begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0,returnEnd:!0,illegal:"[<='$\"]",relevance:0,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo",begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{begin:"!important"}]};return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}()); -hljs.registerLanguage("lua",function(){"use strict";return function(e){var t={begin:"\\[=*\\[",end:"\\]=*\\]",contains:["self"]},a=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[","\\]=*\\]",{contains:[t],relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE,literal:"true false nil",keyword:"and break do else elseif end for goto if in local not or repeat return then until while",built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove"},contains:a.concat([{className:"function",beginKeywords:"function",end:"\\)",contains:[e.inherit(e.TITLE_MODE,{begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params",begin:"\\(",endsWithParent:!0,contains:a}].concat(a)},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string",begin:"\\[=*\\[",end:"\\]=*\\]",contains:[t],relevance:5}])}}}()); -hljs.registerLanguage("makefile",function(){"use strict";return function(e){var i={className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{className:"meta",begin:"",contains:[a,s,i,t]}]}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:")",end:">",keywords:{name:"style"},contains:[c],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">",keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}}}()); -hljs.registerLanguage("markdown",function(){"use strict";return function(n){const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0,relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0,excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis",contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/,relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a];return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n",contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)",end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c,end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}()); -hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{$pattern:"[a-z/_]+",literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n]},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^",end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number",begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}],illegal:"[^\\s\\}]"}}}()); -hljs.registerLanguage("objectivec",function(){"use strict";return function(e){var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n,keyword:"@interface @class @protocol @implementation"};return{name:"Objective-C",aliases:["mm","objc","obj-c"],keywords:{$pattern:n,keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},illegal:"/,end:/$/,illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)",excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}()); -hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={$pattern:/[\w.]+/,keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when"},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{",end:"}"},r={variants:[{begin:/\$\d/},{begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/,relevance:0}]},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{endsWithParent:!0}),s,{className:"string",contains:i,variants:[{begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[",end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<",end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'",contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*",keywords:"split return print reverse grep",relevance:0,contains:[e.HASH_COMMENT_MODE,{className:"regexp",begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE],relevance:0}]},{className:"function",beginKeywords:"sub",end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$",subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}]}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n,contains:a}}}()); -hljs.registerLanguage("php",function(){"use strict";return function(e){var r={begin:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},t={className:"meta",variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:'b"',end:'"'},{begin:"b'",end:"'"},e.inherit(e.APOS_STRING_MODE,{illegal:null}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null})]},n={variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},i={keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list new object or private protected public real return string switch throw trait try unset use var void while xor yield",literal:"false null true",built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass"};return{aliases:["php","php3","php4","php5","php6","php7"],case_insensitive:!0,keywords:i,contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t]}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}]}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0,keywords:"__halt_compiler"}),{className:"string",begin:/<<<['"]?\w+['"]?$/,end:/^\w+;?$/,contains:[e.BACKSLASH_ESCAPE,{className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}]}]},t,{className:"keyword",begin:/\$this\b/},r,{begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function",beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]",contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:i,contains:["self",r,e.C_BLOCK_COMMENT_MODE,a,n]}]},{className:"class",beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/,contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"namespace",end:";",illegal:/[\.']/,contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";",contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},a,n]}}}()); -hljs.registerLanguage("php-template",function(){"use strict";return function(n){return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]}]}}}()); -hljs.registerLanguage("plaintext",function(){"use strict";return function(t){return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}()); -hljs.registerLanguage("properties",function(){"use strict";return function(e){var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\:= \\t\\f\\n]|\\\\.)+",s={end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/,contains:[e.COMMENT("^\\s*[!#]","$"),{begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+"+t,returnBegin:!0,contains:[{className:"attr",begin:"([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",endsParent:!0,relevance:0}],starts:s},{begin:a+t,returnBegin:!0,relevance:0,contains:[{className:"meta",begin:a,endsParent:!0,relevance:0}],starts:s},{className:"attr",relevance:0,begin:a+n+"$"}]}}}()); -hljs.registerLanguage("python",function(){"use strict";return function(e){var n={keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10",built_in:"Ellipsis NotImplemented",literal:"False None True"},a={className:"meta",begin:/^(>>>|\.\.\.) /},i={className:"subst",begin:/\{/,end:/\}/,keywords:n,illegal:/#/},s={begin:/\{\{/,relevance:0},r={className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:/(u|b)?r?'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(u|b)?r?"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{begin:/(fr|rf|f)'''/,end:/'''/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(fr|rf|f)"""/,end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,s,i]},{begin:/(u|r|ur)'/,end:/'/,relevance:10},{begin:/(u|r|ur)"/,end:/"/,relevance:10},{begin:/(b|br)'/,end:/'/},{begin:/(b|br)"/,end:/"/},{begin:/(fr|rf|f)'/,end:/'/,contains:[e.BACKSLASH_ESCAPE,s,i]},{begin:/(fr|rf|f)"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,i]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},l={className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},t={className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:["self",a,l,r,e.HASH_COMMENT_MODE]}]};return i.contains=[r,l,a],{name:"Python",aliases:["py","gyp","ipython"],keywords:n,illegal:/(<\/|->|\?)|=>/,contains:[a,l,{beginKeywords:"if",relevance:0},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/,contains:[e.UNDERSCORE_TITLE_MODE,t,{begin:/->/,endsWithParent:!0,keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{begin:/\b(print|exec)\(/}]}}}()); -hljs.registerLanguage("python-repl",function(){"use strict";return function(n){return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}}}()); -hljs.registerLanguage("ruby",function(){"use strict";return function(e){var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s]}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}",keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/",end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{begin:"%[qQwWx]?\\|",end:"\\|"},{begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(",end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class",beginKeywords:"class module",end:"$|;",illegal:/=/,contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{className:"function",beginKeywords:"def",end:"$|;",contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::"},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{className:"number",begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params",begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*",keywords:"unless",contains:[i,{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$",contains:d}},{className:"meta",begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)",starts:{end:"$",contains:d}}];return{name:"Ruby",aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/,contains:r.concat(g).concat(d)}}}()); -hljs.registerLanguage("rust",function(){"use strict";return function(e){var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!";return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield",literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}()); -hljs.registerLanguage("scss",function(){"use strict";return function(e){var t={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b"},i={className:"number",begin:"#[0-9A-Fa-f]+"};return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0,illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{className:"selector-tag",begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",relevance:0},{className:"selector-pseudo",begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{className:"selector-pseudo",begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},t,{className:"attribute",begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",illegal:"[^\\s]"},{begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{begin:":",end:";",contains:[t,i,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0,keywords:"and or not only",contains:[{begin:"@[a-z-]+",className:"keyword"},t,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,i,e.CSS_NUMBER_MODE]}]}}}()); -hljs.registerLanguage("shell",function(){"use strict";return function(s){return{name:"Shell Session",aliases:["console"],contains:[{className:"meta",begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"}}]}}}()); -hljs.registerLanguage("sql",function(){"use strict";return function(e){var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0,illegal:/[<>{}*]/,contains:[{beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with",end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/,keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null unknown",built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void"},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{className:"string",begin:"`",end:"`"},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}()); -hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip"},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst",begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string",contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/,end:/"/}]},r={className:"number",begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",relevance:0};return t.contains=[r],{name:"Swift",keywords:i,contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*[!?]"},{className:"type",begin:"\\b[A-Z][\\wÀ-ʸ']*",relevance:0},r,{className:"function",beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params",begin:/\(/,end:/\)/,endsParent:!0,keywords:i,contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}],illegal:/\[|%/},{className:"class",beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta",begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b"},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}()); -hljs.registerLanguage("typescript",function(){"use strict";const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);return function(r){var t={$pattern:"[A-Za-z$_][0-9A-Za-z$_]*",keyword:e.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "),literal:n.join(" "),built_in:a.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ")},s={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},i={className:"number",variants:[{begin:"\\b(0[bB][01]+)n?"},{begin:"\\b(0[oO][0-7]+)n?"},{begin:r.C_NUMBER_RE+"n?"}],relevance:0},o={className:"subst",begin:"\\$\\{",end:"\\}",keywords:t,contains:[]},c={begin:"html`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"xml"}},l={begin:"css`",end:"",starts:{end:"`",returnEnd:!1,contains:[r.BACKSLASH_ESCAPE,o],subLanguage:"css"}},E={className:"string",begin:"`",end:"`",contains:[r.BACKSLASH_ESCAPE,o]};o.contains=[r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,i,r.REGEXP_MODE];var d={begin:"\\(",end:/\)/,keywords:t,contains:["self",r.QUOTE_STRING_MODE,r.APOS_STRING_MODE,r.NUMBER_MODE]},u={className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,s,d]};return{name:"TypeScript",aliases:["ts"],keywords:t,contains:[r.SHEBANG(),{className:"meta",begin:/^\s*['"]use strict['"]/},r.APOS_STRING_MODE,r.QUOTE_STRING_MODE,c,l,E,r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,i,{begin:"("+r.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[r.C_LINE_COMMENT_MODE,r.C_BLOCK_COMMENT_MODE,r.REGEXP_MODE,{className:"function",begin:"(\\([^(]*(\\([^(]*(\\([^(]*\\))?\\))?\\)|"+r.UNDERSCORE_IDENT_RE+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:r.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:t,contains:d.contains}]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[\{;]/,excludeEnd:!0,keywords:t,contains:["self",r.inherit(r.TITLE_MODE,{begin:"[A-Za-z$_][0-9A-Za-z$_]*"}),u],illegal:/%/,relevance:0},{beginKeywords:"constructor",end:/[\{;]/,excludeEnd:!0,contains:["self",u]},{begin:/module\./,keywords:{built_in:"module"},relevance:0},{beginKeywords:"module",end:/\{/,excludeEnd:!0},{beginKeywords:"interface",end:/\{/,excludeEnd:!0,keywords:"interface extends"},{begin:/\$[(.]/},{begin:"\\."+r.IDENT_RE,relevance:0},s,d]}}}()); -hljs.registerLanguage("yaml",function(){"use strict";return function(e){var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[",end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string",begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type",begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)",relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(),c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"],contains:b}}}()); -hljs.registerLanguage("armasm",function(){"use strict";return function(s){const e={variants:[s.COMMENT("^[ \\t]*(?=#)","$",{relevance:0,excludeBegin:!0}),s.COMMENT("[;@]","$",{relevance:0}),s.C_LINE_COMMENT_MODE,s.C_BLOCK_COMMENT_MODE]};return{name:"ARM Assembly",case_insensitive:!0,aliases:["arm"],keywords:{$pattern:"\\.?"+s.IDENT_RE,meta:".2byte .4byte .align .ascii .asciz .balign .byte .code .data .else .end .endif .endm .endr .equ .err .exitm .extern .global .hword .if .ifdef .ifndef .include .irp .long .macro .rept .req .section .set .skip .space .text .word .arm .thumb .code16 .code32 .force_thumb .thumb_func .ltorg ALIAS ALIGN ARM AREA ASSERT ATTR CN CODE CODE16 CODE32 COMMON CP DATA DCB DCD DCDU DCDO DCFD DCFDU DCI DCQ DCQU DCW DCWU DN ELIF ELSE END ENDFUNC ENDIF ENDP ENTRY EQU EXPORT EXPORTAS EXTERN FIELD FILL FUNCTION GBLA GBLL GBLS GET GLOBAL IF IMPORT INCBIN INCLUDE INFO KEEP LCLA LCLL LCLS LTORG MACRO MAP MEND MEXIT NOFP OPT PRESERVE8 PROC QN READONLY RELOC REQUIRE REQUIRE8 RLIST FN ROUT SETA SETL SETS SN SPACE SUBT THUMB THUMBX TTL WHILE WEND ",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 pc lr sp ip sl sb fp a1 a2 a3 a4 v1 v2 v3 v4 v5 v6 v7 v8 f0 f1 f2 f3 f4 f5 f6 f7 p0 p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 q0 q1 q2 q3 q4 q5 q6 q7 q8 q9 q10 q11 q12 q13 q14 q15 cpsr_c cpsr_x cpsr_s cpsr_f cpsr_cx cpsr_cxs cpsr_xs cpsr_xsf cpsr_sf cpsr_cxsf spsr_c spsr_x spsr_s spsr_f spsr_cx spsr_cxs spsr_xs spsr_xsf spsr_sf spsr_cxsf s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 d10 d11 d12 d13 d14 d15 d16 d17 d18 d19 d20 d21 d22 d23 d24 d25 d26 d27 d28 d29 d30 d31 {PC} {VAR} {TRUE} {FALSE} {OPT} {CONFIG} {ENDIAN} {CODESIZE} {CPU} {FPU} {ARCHITECTURE} {PCSTOREOFFSET} {ARMASM_VERSION} {INTER} {ROPI} {RWPI} {SWST} {NOSWST} . @"},contains:[{className:"keyword",begin:"\\b(adc|(qd?|sh?|u[qh]?)?add(8|16)?|usada?8|(q|sh?|u[qh]?)?(as|sa)x|and|adrl?|sbc|rs[bc]|asr|b[lx]?|blx|bxj|cbn?z|tb[bh]|bic|bfc|bfi|[su]bfx|bkpt|cdp2?|clz|clrex|cmp|cmn|cpsi[ed]|cps|setend|dbg|dmb|dsb|eor|isb|it[te]{0,3}|lsl|lsr|ror|rrx|ldm(([id][ab])|f[ds])?|ldr((s|ex)?[bhd])?|movt?|mvn|mra|mar|mul|[us]mull|smul[bwt][bt]|smu[as]d|smmul|smmla|mla|umlaal|smlal?([wbt][bt]|d)|mls|smlsl?[ds]|smc|svc|sev|mia([bt]{2}|ph)?|mrr?c2?|mcrr2?|mrs|msr|orr|orn|pkh(tb|bt)|rbit|rev(16|sh)?|sel|[su]sat(16)?|nop|pop|push|rfe([id][ab])?|stm([id][ab])?|str(ex)?[bhd]?|(qd?)?sub|(sh?|q|u[qh]?)?sub(8|16)|[su]xt(a?h|a?b(16)?)|srs([id][ab])?|swpb?|swi|smi|tst|teq|wfe|wfi|yield)(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo)?[sptrx]?(?=\\s)"},e,s.QUOTE_STRING_MODE,{className:"string",begin:"'",end:"[^\\\\]'",relevance:0},{className:"title",begin:"\\|",end:"\\|",illegal:"\\n",relevance:0},{className:"number",variants:[{begin:"[#$=]?0x[0-9a-f]+"},{begin:"[#$=]?0b[01]+"},{begin:"[#$=]\\d+"},{begin:"\\b\\d+"}],relevance:0},{className:"symbol",variants:[{begin:"^[ \\t]*[a-z_\\.\\$][a-z0-9_\\.\\$]+:"},{begin:"^[a-z_\\.\\$][a-z0-9_\\.\\$]+"},{begin:"[=#]\\w+"}],relevance:0}]}}}()); -hljs.registerLanguage("d",function(){"use strict";return function(e){var a={$pattern:e.UNDERSCORE_IDENT_RE,keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},d="((0|[1-9][\\d_]*)|0[bB][01_]+|0[xX]([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))",n="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",t={className:"number",begin:"\\b"+d+"(L|u|U|Lu|LU|uL|UL)?",relevance:0},_={className:"number",begin:"\\b(((0[xX](([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)\\.([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)|\\.?([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*))[pP][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))|((0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(\\.\\d*|([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)))|\\d+\\.(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)|\\.(0|[1-9][\\d_]*)([eE][+-]?(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d))?))([fF]|L|i|[fF]i|Li)?|"+d+"(i|[fF]i|Li))",relevance:0},r={className:"string",begin:"'("+n+"|.)",end:"'",illegal:"."},i={className:"string",begin:'"',contains:[{begin:n,relevance:0}],end:'"[cwd]?'},s=e.COMMENT("\\/\\+","\\+\\/",{contains:["self"],relevance:10});return{name:"D",keywords:a,contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,s,{className:"string",begin:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',relevance:10},i,{className:"string",begin:'[rq]"',end:'"[cwd]?',relevance:5},{className:"string",begin:"`",end:"`[cwd]?"},{className:"string",begin:'q"\\{',end:'\\}"'},_,t,r,{className:"meta",begin:"^#!",end:"$",relevance:5},{className:"meta",begin:"#(line)",end:"$",relevance:5},{className:"keyword",begin:"@[a-zA-Z_][a-zA-Z_\\d]*"}]}}}()); -hljs.registerLanguage("handlebars",function(){"use strict";function e(...e){return e.map(e=>(function(e){return e?"string"==typeof e?e:e.source:null})(e)).join("")}return function(n){const a={"builtin-name":"action bindattr collection component concat debugger each each-in get hash if in input link-to loc log lookup mut outlet partial query-params render template textarea unbound unless view with yield"},t=/\[.*?\]/,s=/[^\s!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/,i=e("(",/'.*?'/,"|",/".*?"/,"|",t,"|",s,"|",/\.|\//,")+"),r=e("(",t,"|",s,")(?==)"),l={begin:i,lexemes:/[\w.\/]+/},c=n.inherit(l,{keywords:{literal:"true false undefined null"}}),o={begin:/\(/,end:/\)/},m={className:"attr",begin:r,relevance:0,starts:{begin:/=/,end:/=/,starts:{contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,c,o]}}},d={contains:[n.NUMBER_MODE,n.QUOTE_STRING_MODE,n.APOS_STRING_MODE,{begin:/as\s+\|/,keywords:{keyword:"as"},end:/\|/,contains:[{begin:/\w+/}]},m,c,o],returnEnd:!0},g=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/\)/})});o.contains=[g];const u=n.inherit(l,{keywords:a,className:"name",starts:n.inherit(d,{end:/}}/})}),b=n.inherit(l,{keywords:a,className:"name"}),h=n.inherit(l,{className:"name",keywords:a,starts:n.inherit(d,{end:/}}/})});return{name:"Handlebars",aliases:["hbs","html.hbs","html.handlebars","htmlbars"],case_insensitive:!0,subLanguage:"xml",contains:[{begin:/\\\{\{/,skip:!0},{begin:/\\\\(?=\{\{)/,skip:!0},n.COMMENT(/\{\{!--/,/--\}\}/),n.COMMENT(/\{\{!/,/\}\}/),{className:"template-tag",begin:/\{\{\{\{(?!\/)/,end:/\}\}\}\}/,contains:[u],starts:{end:/\{\{\{\{\//,returnEnd:!0,subLanguage:"xml"}},{className:"template-tag",begin:/\{\{\{\{\//,end:/\}\}\}\}/,contains:[b]},{className:"template-tag",begin:/\{\{#/,end:/\}\}/,contains:[u]},{className:"template-tag",begin:/\{\{(?=else\}\})/,end:/\}\}/,keywords:"else"},{className:"template-tag",begin:/\{\{\//,end:/\}\}/,contains:[b]},{className:"template-variable",begin:/\{\{\{/,end:/\}\}\}/,contains:[h]},{className:"template-variable",begin:/\{\{/,end:/\}\}/,contains:[h]}]}}}()); -hljs.registerLanguage("haskell",function(){"use strict";return function(e){var n={variants:[e.COMMENT("--","$"),e.COMMENT("{-","-}",{contains:["self"]})]},i={className:"meta",begin:"{-#",end:"#-}"},a={className:"meta",begin:"^#",end:"$"},s={className:"type",begin:"\\b[A-Z][\\w']*",relevance:0},l={begin:"\\(",end:"\\)",illegal:'"',contains:[i,a,{className:"type",begin:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TITLE_MODE,{begin:"[_a-z][\\w']*"}),n]};return{name:"Haskell",aliases:["hs"],keywords:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",contains:[{beginKeywords:"module",end:"where",keywords:"module where",contains:[l,n],illegal:"\\W\\.|;"},{begin:"\\bimport\\b",end:"$",keywords:"import qualified as hiding",contains:[l,n],illegal:"\\W\\.|;"},{className:"class",begin:"^(\\s*)?(class|instance)\\b",end:"where",keywords:"class family instance where",contains:[s,l,n]},{className:"class",begin:"\\b(data|(new)?type)\\b",end:"$",keywords:"data family type newtype deriving",contains:[i,s,l,{begin:"{",end:"}",contains:l.contains},n]},{beginKeywords:"default",end:"$",contains:[s,l,n]},{beginKeywords:"infix infixl infixr",end:"$",contains:[e.C_NUMBER_MODE,n]},{begin:"\\bforeign\\b",end:"$",keywords:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",contains:[s,e.QUOTE_STRING_MODE,n]},{className:"meta",begin:"#!\\/usr\\/bin\\/env runhaskell",end:"$"},i,a,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,s,e.inherit(e.TITLE_MODE,{begin:"^[_a-z][\\w']*"}),n,{begin:"->|<-"}]}}}()); -hljs.registerLanguage("julia",function(){"use strict";return function(e){var r="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",t={$pattern:r,keyword:"in isa where baremodule begin break catch ccall const continue do else elseif end export false finally for function global if import importall let local macro module quote return true try using while type immutable abstract bitstype typealias ",literal:"true false ARGS C_NULL DevNull ENDIAN_BOM ENV I Inf Inf16 Inf32 Inf64 InsertionSort JULIA_HOME LOAD_PATH MergeSort NaN NaN16 NaN32 NaN64 PROGRAM_FILE QuickSort RoundDown RoundFromZero RoundNearest RoundNearestTiesAway RoundNearestTiesUp RoundToZero RoundUp STDERR STDIN STDOUT VERSION catalan e|0 eu|0 eulergamma golden im nothing pi γ π φ ",built_in:"ANY AbstractArray AbstractChannel AbstractFloat AbstractMatrix AbstractRNG AbstractSerializer AbstractSet AbstractSparseArray AbstractSparseMatrix AbstractSparseVector AbstractString AbstractUnitRange AbstractVecOrMat AbstractVector Any ArgumentError Array AssertionError Associative Base64DecodePipe Base64EncodePipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError BufferStream CachingPool CapturedException CartesianIndex CartesianRange Cchar Cdouble Cfloat Channel Char Cint Cintmax_t Clong Clonglong ClusterManager Cmd CodeInfo Colon Complex Complex128 Complex32 Complex64 CompositeException Condition ConjArray ConjMatrix ConjVector Cptrdiff_t Cshort Csize_t Cssize_t Cstring Cuchar Cuint Cuintmax_t Culong Culonglong Cushort Cwchar_t Cwstring DataType Date DateFormat DateTime DenseArray DenseMatrix DenseVecOrMat DenseVector Diagonal Dict DimensionMismatch Dims DirectIndexString Display DivideError DomainError EOFError EachLine Enum Enumerate ErrorException Exception ExponentialBackOff Expr Factorization FileMonitor Float16 Float32 Float64 Function Future GlobalRef GotoNode HTML Hermitian IO IOBuffer IOContext IOStream IPAddr IPv4 IPv6 IndexCartesian IndexLinear IndexStyle InexactError InitError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException InvalidStateException Irrational KeyError LabelNode LinSpace LineNumberNode LoadError LowerTriangular MIME Matrix MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode NullException Nullable Number ObjectIdDict OrdinalRange OutOfMemoryError OverflowError Pair ParseError PartialQuickSort PermutedDimsArray Pipe PollingFileWatcher ProcessExitedException Ptr QuoteNode RandomDevice Range RangeIndex Rational RawFD ReadOnlyMemoryError Real ReentrantLock Ref Regex RegexMatch RemoteChannel RemoteException RevString RoundingMode RowVector SSAValue SegmentationFault SerializationState Set SharedArray SharedMatrix SharedVector Signed SimpleVector Slot SlotNumber SparseMatrixCSC SparseVector StackFrame StackOverflowError StackTrace StepRange StepRangeLen StridedArray StridedMatrix StridedVecOrMat StridedVector String SubArray SubString SymTridiagonal Symbol Symmetric SystemError TCPSocket Task Text TextDisplay Timer Tridiagonal Tuple Type TypeError TypeMapEntry TypeMapLevel TypeName TypeVar TypedSlot UDPSocket UInt UInt128 UInt16 UInt32 UInt64 UInt8 UndefRefError UndefVarError UnicodeError UniformScaling Union UnionAll UnitRange Unsigned UpperTriangular Val Vararg VecElement VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef WorkerConfig WorkerPool "},a={keywords:t,illegal:/<\//},n={className:"subst",begin:/\$\(/,end:/\)/,keywords:t},o={className:"variable",begin:"\\$"+r},i={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],variants:[{begin:/\w*"""/,end:/"""\w*/,relevance:10},{begin:/\w*"/,end:/"\w*/}]},l={className:"string",contains:[e.BACKSLASH_ESCAPE,n,o],begin:"`",end:"`"},s={className:"meta",begin:"@"+r};return a.name="Julia",a.contains=[{className:"number",begin:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,relevance:0},{className:"string",begin:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},i,l,s,{className:"comment",variants:[{begin:"#=",end:"=#",relevance:10},{begin:"#",end:"$"}]},e.HASH_COMMENT_MODE,{className:"keyword",begin:"\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b"},{begin:/<:/}],n.contains=a.contains,a}}()); -hljs.registerLanguage("nim",function(){"use strict";return function(e){return{name:"Nim",aliases:["nim"],keywords:{keyword:"addr and as asm bind block break case cast const continue converter discard distinct div do elif else end enum except export finally for from func generic if import in include interface is isnot iterator let macro method mixin mod nil not notin object of or out proc ptr raise ref return shl shr static template try tuple type using var when while with without xor yield",literal:"shared guarded stdin stdout stderr result true false",built_in:"int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 bool char string cstring pointer expr stmt void auto any range array openarray varargs seq set clong culong cchar cschar cshort cint csize clonglong cfloat cdouble clongdouble cuchar cushort cuint culonglong cstringarray semistatic"},contains:[{className:"meta",begin:/{\./,end:/\.}/,relevance:10},{className:"string",begin:/[a-zA-Z]\w*"/,end:/"/,contains:[{begin:/""/}]},{className:"string",begin:/([a-zA-Z]\w*)?"""/,end:/"""/},e.QUOTE_STRING_MODE,{className:"type",begin:/\b[A-Z]\w+\b/,relevance:0},{className:"number",relevance:0,variants:[{begin:/\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/},{begin:/\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/},{begin:/\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/},{begin:/\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/}]},e.HASH_COMMENT_MODE]}}}()); -hljs.registerLanguage("nix",function(){"use strict";return function(e){var n={keyword:"rec with let in inherit assert if else then",literal:"true false or and null",built_in:"import abort baseNameOf dirOf isNull builtins map removeAttrs throw toString derivation"},i={className:"subst",begin:/\$\{/,end:/}/,keywords:n},t={className:"string",contains:[i],variants:[{begin:"''",end:"''"},{begin:'"',end:'"'}]},s=[e.NUMBER_MODE,e.HASH_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t,{begin:/[a-zA-Z0-9-_]+(\s*=)/,returnBegin:!0,relevance:0,contains:[{className:"attr",begin:/\S+/}]}];return i.contains=s,{name:"Nix",aliases:["nixos"],keywords:n,contains:s}}}()); -hljs.registerLanguage("r",function(){"use strict";return function(e){var n="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{name:"R",contains:[e.HASH_COMMENT_MODE,{begin:n,keywords:{$pattern:n,keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},relevance:0},{className:"number",begin:"0[xX][0-9a-fA-F]+[Li]?\\b",relevance:0},{className:"number",begin:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",relevance:0},{className:"number",begin:"\\d+\\.(?!\\d)(?:i\\b)?",relevance:0},{className:"number",begin:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{className:"number",begin:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",relevance:0},{begin:"`",end:"`",relevance:0},{className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{begin:'"',end:'"'},{begin:"'",end:"'"}]}]}}}()); -hljs.registerLanguage("scala",function(){"use strict";return function(e){var n={className:"subst",variants:[{begin:"\\$[A-Za-z0-9_]+"},{begin:"\\${",end:"}"}]},a={className:"string",variants:[{begin:'"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{begin:'"""',end:'"""',relevance:10},{begin:'[a-z]+"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE,n]},{className:"string",begin:'[a-z]+"""',end:'"""',contains:[n],relevance:10}]},s={className:"type",begin:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},t={className:"title",begin:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},i={className:"class",beginKeywords:"class object trait type",end:/[:={\[\n;]/,excludeEnd:!0,contains:[{beginKeywords:"extends with",relevance:10},{begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[s]},t]},l={className:"function",beginKeywords:"def",end:/[:={\[(\n;]/,excludeEnd:!0,contains:[t]};return{name:"Scala",keywords:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,a,{className:"symbol",begin:"'\\w[\\w\\d_]*(?!')"},s,l,i,e.C_NUMBER_MODE,{className:"meta",begin:"@[A-Za-z]+"}]}}}()); -hljs.registerLanguage("x86asm",function(){"use strict";return function(s){return{name:"Intel x86 Assembly",case_insensitive:!0,keywords:{$pattern:"[.%]?"+s.IDENT_RE,keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",built_in:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr",meta:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %if %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},contains:[s.COMMENT(";","$",{relevance:0}),{className:"number",variants:[{begin:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",relevance:0},{begin:"\\$[0-9][0-9A-Fa-f]*",relevance:0},{begin:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[Hh]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{begin:"\\b(?:0[Xx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"}]},s.QUOTE_STRING_MODE,{className:"string",variants:[{begin:"'",end:"[^\\\\]'"},{begin:"`",end:"[^\\\\]`"}],relevance:0},{className:"symbol",variants:[{begin:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)"},{begin:"^\\s*%%[A-Za-z0-9_$#@~.?]*:"}],relevance:0},{className:"subst",begin:"%[0-9]+",relevance:0},{className:"subst",begin:"%!S+",relevance:0},{className:"meta",begin:/^\s*\.[\w_-]+/}]}}}()); \ No newline at end of file diff --git a/docs/book/index.html b/docs/book/index.html deleted file mode 100644 index fb41796..0000000 --- a/docs/book/index.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - Introduction - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Storybook Language Guide

-
-

Create rich narrative simulations through code that reads like stories.

-
-

Welcome to the complete guide for the Storybook narrative simulation language! Whether you’re a creative writer bringing characters to life or a developer building simulation systems, this documentation will help you master Storybook.

-
-

⚠️ Alpha Software Notice

-

Storybook is currently in alpha and under active development at r3t Studios. While the core language features are stable and ready to use, you should expect:

-
    -
  • New features to be added as we expand the language capabilities
  • -
  • Minor syntax adjustments as we refine the design based on real-world usage
  • -
  • API changes in the compiled output format as we optimize for game engine integration
  • -
-

We’re committed to a thoughtful path toward version 1.0. Breaking changes will be clearly documented, and we’ll provide migration guides when syntax evolves. Your feedback during this alpha period is invaluable in shaping the language’s future!

-
-

What is Storybook?

-

Storybook is a compiled simulation language designed for open-world, autonomous game simulations. While it includes a basic embedded virtual machine for terminal-based debugging, it’s built to be integrated into game engines and developed hand-in-hand with technical game developers.

-

Storybook defines characters, behaviors, relationships, and narrative events for autonomous agents in dynamic worlds. It bridges the gap between storytelling and technical simulation through:

-
    -
  • Readable syntax - Code that looks like natural descriptions, but compiles to efficient bytecode
  • -
  • Named nodes - Behavior trees you can read as stories, that drive AI decision-making
  • -
  • Prose blocks - Embed narrative directly in definitions for context-aware storytelling
  • -
  • Rich semantics - From simple traits to complex state machines and schedules
  • -
  • Game engine integration - Designed to power autonomous NPCs in Unity, Unreal, Godot, and custom engines
  • -
-

Choose Your Path

-

🎨 For Storytellers

-

New to programming? Start with the Tutorial Track for a gentle, example-driven introduction. Learn by building a bakery simulation!

-

💻 For Developers

-

Need technical precision? Jump to the Reference Guide for complete syntax specifications and semantic details.

-

✨ For Everyone

-

Want inspiration? Browse the Examples Gallery to see what’s possible!

-

Quick Start

-
character Martha {
-    age: 34
-    skill_level: 0.95
-
-    ---description
-    A master baker who learned from her grandmother
-    and now runs the most popular bakery in town.
-    ---
-}
-
-behavior Baker_MorningRoutine {
-    choose daily_priority {
-        then prepare_sourdough { ... }
-        then serve_customers { ... }
-        then restock_display { ... }
-    }
-}
-
-

Continue to Tutorial →

-

Documentation Structure

-
    -
  • Part I: Getting Started - Tutorials for learning Storybook
  • -
  • Part II: Complete Reference - Technical specifications
  • -
  • Part III: Advanced Topics - Patterns and integration
  • -
  • Part IV: Examples Gallery - Complete working examples
  • -
-

Getting Help

-
    -
  • In-Editor: Hover over keywords for quick help
  • -
  • Search: Use the search box (top right) to find anything
  • -
  • Examples: Working code is the best teacher!
  • -
-
-

Ready to begin? Start with the Tutorial →

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/lsp/keywords/choose.toml b/docs/book/lsp/keywords/choose.toml deleted file mode 100644 index 7f564e7..0000000 --- a/docs/book/lsp/keywords/choose.toml +++ /dev/null @@ -1,61 +0,0 @@ -# LSP Documentation for 'choose' keyword - -[keyword] -name = "choose" -category = "behavior_tree" -short_description = "Selector node that tries children in order until one succeeds" -web_url = "https://r3t-studios.github.io/storybook/reference/behavior-trees.html#choose" - -[syntax] -format = "choose [label] { children... }" -example = """ -choose panic_response { - then time_panic { ... } - then obstacle_panic { ... } - then default_panic { ... } -} -""" - -[hover] -markdown = """ -**`choose` - Selector Node** - -Tries each child behavior in order until one succeeds. - -**Behavior:** -- Evaluates children left-to-right -- Returns **success** on first successful child -- Skips remaining children after first success -- Returns **failure** only if all children fail - -**Named nodes (optional):** -```storybook -choose state_dependent_action { - then appear { ... } - then confuse_alice { ... } - then fade_away { ... } -} -``` - -Labels make intent clear and aid debugging! - -**Use cases:** -- Decision-making between alternatives -- Fallback chains (try A, if fails try B) -- Priority ordering (prefer A, accept B) - -[Learn more →](https://r3t-studios.github.io/storybook/reference/behavior-trees.html#choose) -""" - -[completion] -snippet = "choose ${1:label} {\n\t$0\n}" -description = "Selector node (tries children until one succeeds)" -sort_text = "01-choose" - -[context] -valid_in = ["behavior_block", "choose_block", "then_block", "decorator_block"] -invalid_in = ["character_block", "life_arc_block", "schedule_block"] - -[related] -keywords = ["then", "if", "when"] -concepts = ["behavior_trees", "named_nodes", "selectors"] diff --git a/docs/book/mark.min.js b/docs/book/mark.min.js deleted file mode 100644 index 1636231..0000000 --- a/docs/book/mark.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*!*************************************************** -* mark.js v8.11.1 -* https://markjs.io/ -* Copyright (c) 2014–2018, Julian Kühnel -* Released under the MIT license https://git.io/vwTVl -*****************************************************/ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function e(n){t(this,e),this.opt=r({},{diacritics:!0,synonyms:{},accuracy:"partially",caseSensitive:!1,ignoreJoiners:!1,ignorePunctuation:[],wildcards:"disabled"},n)}return n(e,[{key:"create",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e),new RegExp(e,"gm"+(this.opt.caseSensitive?"":"i"))}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynonyms(a)+"|"+this.processSynonyms(s)+")"+r))}return e}},{key:"processSynonyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}}]),e}(),a=function(){function a(e){t(this,a),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(a,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapGroups",value:function(e,t,n,r){return r((e=this.wrapRangeInTextNode(e,t,t+n)).previousSibling),e}},{key:"separateGroups",value:function(e,t,n,r,i){for(var o=t.length,a=1;a-1&&r(t[a],e)&&(e=this.wrapGroups(e,s,t[a].length,i))}return e}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];){if(o.opt.separateGroups)t=o.separateGroups(t,i,a,n,r);else{if(!n(i[a],t))continue;var s=i.index;if(0!==a)for(var c=1;c - - - - - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Storybook Language Guide

-
-

Create rich narrative simulations through code that reads like stories.

-
-

Welcome to the complete guide for the Storybook narrative simulation language! Whether you’re a creative writer bringing characters to life or a developer building simulation systems, this documentation will help you master Storybook.

-
-

⚠️ Alpha Software Notice

-

Storybook is currently in alpha and under active development at r3t Studios. While the core language features are stable and ready to use, you should expect:

-
    -
  • New features to be added as we expand the language capabilities
  • -
  • Minor syntax adjustments as we refine the design based on real-world usage
  • -
  • API changes in the compiled output format as we optimize for game engine integration
  • -
-

We’re committed to a thoughtful path toward version 1.0. Breaking changes will be clearly documented, and we’ll provide migration guides when syntax evolves. Your feedback during this alpha period is invaluable in shaping the language’s future!

-
-

What is Storybook?

-

Storybook is a compiled simulation language designed for open-world, autonomous game simulations. While it includes a basic embedded virtual machine for terminal-based debugging, it’s built to be integrated into game engines and developed hand-in-hand with technical game developers.

-

Storybook defines characters, behaviors, relationships, and narrative events for autonomous agents in dynamic worlds. It bridges the gap between storytelling and technical simulation through:

-
    -
  • Readable syntax - Code that looks like natural descriptions, but compiles to efficient bytecode
  • -
  • Named nodes - Behavior trees you can read as stories, that drive AI decision-making
  • -
  • Prose blocks - Embed narrative directly in definitions for context-aware storytelling
  • -
  • Rich semantics - From simple traits to complex state machines and schedules
  • -
  • Game engine integration - Designed to power autonomous NPCs in Unity, Unreal, Godot, and custom engines
  • -
-

Choose Your Path

-

🎨 For Storytellers

-

New to programming? Start with the Tutorial Track for a gentle, example-driven introduction. Learn by building a bakery simulation!

-

💻 For Developers

-

Need technical precision? Jump to the Reference Guide for complete syntax specifications and semantic details.

-

✨ For Everyone

-

Want inspiration? Browse the Examples Gallery to see what’s possible!

-

Quick Start

-
character Martha {
-    age: 34
-    skill_level: 0.95
-
-    ---description
-    A master baker who learned from her grandmother
-    and now runs the most popular bakery in town.
-    ---
-}
-
-behavior Baker_MorningRoutine {
-    choose daily_priority {
-        then prepare_sourdough { ... }
-        then serve_customers { ... }
-        then restock_display { ... }
-    }
-}
-
-

Continue to Tutorial →

-

Documentation Structure

-
    -
  • Part I: Getting Started - Tutorials for learning Storybook
  • -
  • Part II: Complete Reference - Technical specifications
  • -
  • Part III: Advanced Topics - Patterns and integration
  • -
  • Part IV: Examples Gallery - Complete working examples
  • -
-

Getting Help

-
    -
  • In-Editor: Hover over keywords for quick help
  • -
  • Search: Use the search box (top right) to find anything
  • -
  • Examples: Working code is the best teacher!
  • -
-
-

Ready to begin? Start with the Tutorial →

-

Welcome to Storybook

-
-

Bring characters to life with code that reads like stories.

-
-

Welcome! This tutorial will guide you through the Storybook language step by step. By the end, you will be able to create rich characters, define complex behaviors, build relationships, and model entire narrative worlds.

-

What You Will Learn

-

In this tutorial, we follow Martha and her bakery family, using their daily lives to learn each concept:

-
    -
  1. Creating Characters - Define Martha with traits and descriptions
  2. -
  3. Your First Behavior Tree - Give characters decision-making abilities
  4. -
  5. Making Characters Act - Actions, conditions, and decorators
  6. -
  7. Advanced Behaviors - Subtrees, parameters, and complex patterns
  8. -
  9. Character Relationships - Model how characters interact
  10. -
  11. Schedules and Time - Give characters daily routines
  12. -
  13. Life Arcs - Track character development over time
  14. -
-

What is Storybook?

-

Storybook is a domain-specific language (DSL) for narrative simulation. It lets you describe:

-
    -
  • Who characters are (traits, backstory, species)
  • -
  • What they do (behavior trees with decision logic)
  • -
  • How they relate to others (relationships with perspectives)
  • -
  • When they act (schedules and time-based routines)
  • -
  • How they change (life arcs and state machines)
  • -
-

All of this in syntax designed to be readable and expressive.

-

Your First Storybook File

-

Create a file called hello.sb and add this:

-
character Martha {
-    age: 34
-    skill_level: 0.95
-
-    ---description
-    A master baker who runs the most popular bakery in town,
-    known for her sourdough bread and apple pastries.
-    ---
-}
-
-

That is it. You have defined a character with two numeric fields and a prose description block. Let us break it down:

-
    -
  • character Martha declares a new character named Martha
  • -
  • { ... } contains her attributes
  • -
  • age: 34 is an integer field
  • -
  • skill_level: 0.95 is a floating-point field (0.0 to 1.0)
  • -
  • ---description ... --- is a prose block for narrative text
  • -
-

Key Concepts

-

Everything is a Declaration

-

Storybook files contain declarations – named definitions of things in your world:

-
character Martha { ... }      // A person or creature
-behavior BakeRoutine { ... }  // Decision-making logic
-relationship Family { ... }   // A connection between entities
-schedule DailyRoutine { ... } // Time-based activities
-life_arc Career { ... }       // How someone changes over time
-
-

Fields Hold Data

-

Fields use a simple name: value format:

-
age: 34                  // Integer
-skill_level: 0.95        // Float
-name: "Martha Baker"     // String
-is_open: true            // Boolean
-wake_time: 04:30         // Time
-bake_duration: 45m       // Duration
-
-

Prose Blocks Tell Stories

-

Prose blocks embed narrative text directly in your definitions:

-
---backstory
-Martha learned to bake from her grandmother, starting at age
-twelve with simple bread recipes. Over the years she mastered
-sourdough, pastries, and specialty cakes, eventually opening
-her own bakery.
----
-
-

You can have multiple prose blocks with different tags (backstory, appearance, personality, etc.) in a single declaration.

-

Project Structure

-

A typical Storybook project organizes files into directories:

-
my-world/
-  schema/
-    core_enums.sb      // Enum definitions (skill levels, moods, etc.)
-    templates.sb       // Reusable trait sets
-    beings.sb          // Species definitions
-  world/
-    characters/
-      martha.sb        // Character definitions
-      jane.sb
-    behaviors/
-      baking.sb        // Behavior trees
-    relationships/
-      family.sb        // Relationship definitions
-
-

Files reference each other using use statements:

-
use schema::core_enums::SkillLevel;
-use schema::beings::Human;
-
-character Martha: Human {
-    skill_level: expert
-}
-
-

Next Steps

-

Ready to create your first character? Head to Creating Characters to start building Martha in detail.

-
-

Tip: You do not need to memorize everything now. This tutorial builds concepts gradually, and you can always refer back to the Reference Guide for precise syntax details.

-

Creating Characters

-

Characters are the heart of every Storybook world. In this chapter, you will learn how to define characters with fields, prose blocks, species, and templates.

-

A Simple Character

-

The simplest character has a name and some fields:

-
character Martha {
-    age: 34
-    skill_level: 0.95
-    is_open: true
-}
-
-

Fields use the name: value format. Storybook supports several value types:

-
- - - - - - - -
TypeExampleDescription
Integer42Whole numbers
Float0.85Decimal numbers
String"hello"Text in double quotes
Booleantrue / falseYes or no values
Time14:30Clock times
Duration2h30mTime intervals
List[1, 2, 3]Ordered collections
-
-

Adding Descriptions with Prose Blocks

-

Prose blocks embed narrative text directly alongside data. They start and end with --- and have a tag name:

-
character Martha {
-    age: 34
-    skill_level: 0.95
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age
-    twelve with simple bread recipes. She mastered sourdough and
-    pastries, eventually opening the most popular bakery in town.
-    ---
-
-    ---appearance
-    A confident woman in her mid-thirties, usually dusted with
-    flour. Her hands are calloused from years of kneading dough.
-    ---
-}
-
-

You can use any tag name you like. Common ones include backstory, appearance, personality, motivation, and secrets.

-

Defining Species

-

Species define what a character fundamentally is. Define them separately, then reference them with the : syntax:

-
species Human {
-    lifespan: 70
-
-    ---description
-    Bipedal mammals with complex language and tool use.
-    ---
-}
-
-species Cat {
-    lifespan: 15
-
-    ---description
-    Domestic cats make loyal companions and effective
-    pest control for bakeries.
-    ---
-}
-
-

Now use species when creating characters:

-
character Martha: Human {
-    age: 34
-}
-
-character Whiskers: Cat {
-    friendly: true
-    catches_mice: true
-}
-
-

The : Human part says “Martha is a Human.” She inherits the species’ fields (like lifespan: 70) automatically.

-

A character can have only one species – you cannot be both Human and Cat.

-

But what about hybrids?

-

If you want a character that combines traits from different sources, use composition with templates instead:

-
species Human {
-    lifespan: 70
-    reasoning_ability: 1.0
-}
-
-template CulinaryExpert {
-    palate_sensitivity: 0.5..1.0
-    recipes_mastered: 0..500
-    can_identify_ingredients: true
-}
-
-template BusinessOwner {
-    business_acumen: 0.0..1.0
-    manages_finances: true
-    leadership: 0.0..1.0
-}
-
-// A character combining species with multiple templates
-character Martha: Human from CulinaryExpert, BusinessOwner {
-    age: 34
-
-    // From CulinaryExpert
-    palate_sensitivity: 0.9
-    recipes_mastered: 150
-    can_identify_ingredients: true
-
-    // From BusinessOwner
-    business_acumen: 0.8
-    manages_finances: true
-    leadership: 0.85
-
-    // Unique traits
-    specialty: "sourdough"
-    years_experience: 22
-
-    ---personality
-    A perfectionist in the kitchen who demands the best from her
-    ingredients and her team. Warm with customers but exacting
-    with her apprentices.
-    ---
-}
-
-

By combining a species with templates, you can achieve any combination you need. The species defines what the character fundamentally is, while templates add traits from other sources.

-

Reusing Traits with Templates

-

Templates define reusable sets of attributes. Characters inherit from them using the from keyword:

-
template SkilledWorker {
-    skill_level: 0.0..1.0
-    years_experience: 0..50
-}
-
-template Baker {
-    include SkilledWorker
-    specialty: "general"
-    recipes_mastered: 0..500
-}
-
-

Notice the 0.0..1.0 syntax – that is a range. When a character uses this template, a specific value within that range is selected. Ranges are only valid in templates.

-

Characters can inherit from multiple templates:

-
character Martha: Human from Baker, BusinessOwner {
-    age: 34
-    skill_level: 0.95
-    specialty: "sourdough"
-    recipes_mastered: 150
-}
-
-

The from Baker, BusinessOwner part says “Martha has the traits from both templates.” You can override any inherited field by specifying it directly.

-

Species vs. Templates

-

Understanding the difference is important:

-
- - - -
Species (:)Templates (from)
MeaningWhat the character isWhat the character has
CountExactly oneZero or more
Example: Humanfrom Baker, BusinessOwner
-
-

Think of it this way: a character is a Human, but has baking skills and business acumen.

-

Field Resolution

-

When a character inherits from multiple sources, fields are resolved in priority order:

-
    -
  1. Species fields (lowest priority)
  2. -
  3. Template fields (left to right in the from clause)
  4. -
  5. Character fields (highest priority – always wins)
  6. -
-
species Human {
-    speed: 1.0
-}
-
-template Warrior {
-    speed: 1.5
-    strength: 10
-}
-
-template Berserker {
-    speed: 2.0
-    strength: 15
-}
-
-character Conan: Human from Warrior, Berserker {
-    strength: 20
-}
-// Resolved: speed = 2.0 (Berserker), strength = 20 (Conan)
-
-

Using Enums for Controlled Values

-

Enums define a fixed set of named values. They prevent typos and ensure consistency:

-
enum SkillLevel {
-    Novice,
-    Beginner,
-    Intermediate,
-    Advanced,
-    Expert,
-    Master
-}
-
-enum Specialty {
-    Sourdough,
-    Pastries,
-    Cakes,
-    Bread,
-    Confections
-}
-
-

Use enum values as field values:

-
character Martha: Human {
-    skill_level: Master
-    specialty: Sourdough
-}
-
-

If you write skill_level: Professional, the compiler will catch the mistake because Professional is not defined in the SkillLevel enum.

-

Importing Across Files

-

Real projects split definitions across multiple files. Use the use statement to import:

-
// In world/characters/martha.sb
-use schema::core_enums::{SkillLevel, Specialty};
-use schema::templates::Baker;
-use schema::beings::Human;
-
-character Martha: Human from Baker {
-    skill_level: Master
-    specialty: Sourdough
-}
-
-

The use schema::core_enums::{SkillLevel, Specialty} line imports two enums from the schema/core_enums.sb file. You can also import everything with use schema::core_enums::*.

-

Putting It All Together

-

Here is a complete character definition with all the features:

-
use schema::core_enums::{SkillLevel, Specialty};
-use schema::templates::{Baker, BusinessOwner};
-use schema::beings::Human;
-
-character Martha: Human from Baker, BusinessOwner {
-    // Core identity
-    age: 34
-    skill_level: Master
-    specialty: Sourdough
-
-    // Professional
-    years_experience: 22
-    recipes_mastered: 150
-    can_teach: true
-
-    // Business
-    business_acumen: 0.8
-    leadership: 0.85
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age
-    twelve with simple bread recipes. She mastered sourdough and
-    pastries, eventually opening the most popular bakery in town.
-    ---
-
-    ---personality
-    A perfectionist in the kitchen who demands the best from her
-    ingredients and her team. Warm with customers but exacting
-    with her apprentices. Known for arriving at 4 AM to start
-    the morning batch.
-    ---
-}
-
-

Next Steps

-

Now that Martha exists, let us give her something to do. In Your First Behavior Tree, you will learn how characters make decisions.

-
-

Reference: For complete character syntax details, see the Characters Reference.

-

Your First Behavior Tree

-

Behavior trees define how characters make decisions. They model the thought process: “Try this first, and if it fails, try that instead.” In this chapter, you will create your first behavior tree for Martha.

-

What is a Behavior Tree?

-

A behavior tree is a hierarchy of nodes that executes from top to bottom. Each node either succeeds or fails, and the tree uses that result to decide what to do next.

-

There are two fundamental building blocks:

-
    -
  • choose (Selector): Try children in order until one succeeds. Think “try A, else try B, else try C.”
  • -
  • then (Sequence): Run children in order, stopping if any fails. Think “do A, then B, then C – all must succeed.”
  • -
-

Your First Tree

-

Let us give Martha a simple baking behavior:

-
behavior Martha_BakeRoutine {
-    choose what_to_do {
-        then fill_special_orders {
-            CheckSpecialOrders
-            PrepareSpecialIngredients
-            BakeSpecialItem
-        }
-
-        then daily_bread {
-            MixDough
-            KneadDough
-            BakeLoaves
-        }
-
-        CleanWorkstation
-    }
-}
-
-

Reading this as a story:

-
-

Martha will choose what to do. First, she tries to fill special orders: she checks for orders, prepares special ingredients, and bakes the item. If that path fails (maybe there are no special orders), she tries daily bread: she mixes dough, kneads it, and bakes loaves. If even that fails, she simply cleans her workstation.

-
-

Understanding choose (Selector)

-

A choose node tries its children one at a time. As soon as one succeeds, it stops and returns success. If all children fail, it returns failure.

-
choose response {
-    HandleUrgentOrder   // Try first: handle urgent order
-    ServeCustomer       // If that fails: serve a customer
-    RestockShelves      // If that fails: restock
-}
-
-

This is like a priority list – the first successful option wins.

-

Understanding then (Sequence)

-

A then node runs its children in order. If any child fails, the whole sequence fails and stops. All children must succeed for the sequence to succeed.

-
then make_sourdough {
-    MixDough         // Must succeed
-    KneadDough       // Must succeed
-    FirstRise        // Must succeed
-    ShapeLoaves      // Must succeed
-}
-
-

If MixDough fails (no flour available), the whole process stops.

-

Naming Your Nodes

-

Both choose and then accept optional labels:

-
choose daily_priority {
-    then morning_baking { ... }
-    then afternoon_sales { ... }
-}
-
-

Labels are optional but highly recommended. They make your trees readable as narratives and help with debugging. Compare:

-
// Without labels (hard to read)
-choose {
-    then { MixDough, BakeLoaves }
-    then { ServeCustomer, CollectPayment }
-}
-
-// With labels (reads like a story)
-choose priority {
-    then baking { MixDough, BakeLoaves }
-    then sales { ServeCustomer, CollectPayment }
-}
-
-

Combining choose and then

-

Behavior trees become powerful when you nest selectors and sequences:

-
behavior Jane_PastryRoutine {
-    choose pastry_priorities {
-        // Highest priority: fill custom cake orders
-        then custom_orders {
-            ReviewCakeOrder
-            DesignDecoration
-            BakeAndDecorate
-            PackageForPickup
-        }
-
-        // If no orders: prepare display pastries
-        then display_pastries {
-            RollPastryDough
-            PrepareFillings
-            AssemblePastries
-            ArrangeDisplay
-        }
-
-        // Default: experiment with new recipes
-        ExperimentWithFlavors
-    }
-}
-
-

Reading this as narrative:

-
-

Jane always prioritizes custom cake orders. She reviews the order, designs the decoration, bakes and decorates, then packages it. If there are no orders, she prepares display pastries. If there is nothing else to do, she experiments with new flavors.

-
-

Actions

-

The leaf nodes in a behavior tree are actions – concrete things a character does:

-
MixDough              // Simple action
-KneadDough            // Simple action
-ServeCustomer         // Simple action
-
-

Actions are identifiers that the runtime interprets. They represent the actual behaviors executed in your simulation.

-

A Complete Example

-

Here is a behavior tree for the morning rush at the bakery:

-
behavior Bakery_MorningRush {
-    ---description
-    Handles the busy morning rush when customers are
-    lining up for fresh bread and pastries.
-    ---
-
-    choose morning_priority {
-        then serve_waiting_customer {
-            GreetCustomer
-            TakeOrder
-            PackageItems
-            CollectPayment
-            ThankCustomer
-        }
-
-        then restock_display {
-            CheckDisplayLevels
-            FetchFromKitchen
-            ArrangeOnShelves
-        }
-
-        then quick_bake {
-            CheckInventory
-            StartQuickBatch
-            MonitorOven
-        }
-    }
-}
-
-

Notice the prose block (---description ... ---) at the top of the behavior. You can document what the behavior does right alongside the code.

-

Behavior-Character Connection

-

Characters link to behaviors using the uses behaviors clause:

-
character Martha: Human {
-    age: 34
-
-    uses behaviors: [
-        { tree: Martha_BakeRoutine },
-        { tree: HandleEmergency }
-    ]
-}
-
-

This tells the simulation that Martha uses two behavior trees. We will cover advanced behavior linking (priorities, conditions) in Making Characters Act.

-

Next Steps

-

Your behavior trees so far make decisions between options and run sequences of actions. In Making Characters Act, you will learn how to add conditions, decorators, and parameters to create truly dynamic behaviors.

-
-

Reference: For complete behavior tree syntax, see the Behavior Trees Reference.

-

Making Characters Act

-

In the previous chapter, you created behavior trees with selectors and sequences. Now you will add conditions, action parameters, and decorators to create dynamic, responsive behaviors.

-

Conditions: if and when

-

Conditions let behavior trees react to the world. Use if or when to test a condition before proceeding:

-
behavior Martha_React {
-    choose response {
-        then bake_path {
-            if(inventory_sufficient)
-            StartBaking
-        }
-
-        then restock_path {
-            if(inventory_low)
-            OrderSupplies
-        }
-
-        CleanWorkstation
-    }
-}
-
-

if(inventory_sufficient) succeeds when inventory is sufficient, and fails otherwise. If it fails, the entire bake_path sequence fails, and the tree moves on to the next option.

-

if and when are interchangeable – use whichever reads more naturally:

-
// "if" for state checks
-if(health < 20)
-
-// "when" for event-like conditions
-when(alarm_triggered)
-
-

Condition Expressions

-

Conditions support comparisons and logical operators:

-
// Comparisons
-if(health < 20)
-if(distance > 100)
-if(name == "Martha")
-if(status is Curious)        // 'is' is syntactic sugar for ==
-
-// Logical operators
-if(hungry and tired)
-if(rich or lucky)
-if(not is_dangerous)
-
-// Combined
-if(health < 50 and not has_potion)
-if((age > 18 and age < 65) or is_veteran)
-
-

Action Parameters

-

Actions can take named parameters using parenthesis syntax:

-
behavior Martha_BakeSpecial {
-    then baking {
-        MixDough(recipe: "sourdough", quantity: 10)
-        KneadDough(duration: 15m)
-        BakeLoaves(temperature: 230, duration: 35m)
-    }
-}
-
-

Parameters are fields inside ( ) after the action name. They let you customize behavior without defining separate actions for each variation.

-

Decorators

-

Decorators wrap a single child node and modify its behavior. They are your tools for timing, repetition, and conditional execution.

-

repeat – Looping

-
// Infinite repeat (checks oven forever)
-repeat {
-    CheckOvenTemperature
-}
-
-// Repeat exactly 3 times
-repeat(3) {
-    KneadDough
-}
-
-// Repeat between 2 and 5 times (random)
-repeat(2..5) {
-    FoldDough
-}
-
-

invert – Flip Results

-

Inverts success/failure. Useful for “if NOT” conditions:

-
behavior SafeBake {
-    choose options {
-        then bake_safely {
-            invert { OvenOverheating }   // Succeeds if oven is NOT overheating
-            ContinueBaking
-        }
-
-        StopAndInspect
-    }
-}
-
-

retry – Try Again on Failure

-

Retries the child up to N times if it fails:

-
retry(3) {
-    LightOven    // Try up to 3 times before giving up
-}
-
-

timeout – Time Limits

-

Fails the child if it does not complete within the duration:

-
timeout(10s) {
-    WaitForDoughToRise    // Must finish within 10 seconds
-}
-
-

cooldown – Rate Limiting

-

Prevents the child from running again within the cooldown period:

-
cooldown(30s) {
-    CheckOvenTemperature    // Can only check once every 30 seconds
-}
-
-

if as Decorator (Guard)

-

The if decorator only runs the child when a condition is true:

-
if(has_special_orders) {
-    PrepareSpecialBatch    // Only prepare when there are orders
-}
-
-

This is different from if as a condition node. As a decorator, if wraps a child and gates its execution. As a condition node, if is a simple pass/fail check inline in a sequence.

-

succeed_always and fail_always

-

Force a result regardless of the child:

-
// Try bonus task, but don't fail the routine if it fails
-succeed_always {
-    ExperimentWithNewRecipe
-}
-
-// Temporarily disable a feature
-fail_always {
-    UntestedBakingMethod
-}
-
-

Combining Decorators

-

Decorators can nest for complex control:

-
behavior ResilientAction {
-    // Only run if oven is ready, with 20s timeout, retrying up to 3 times
-    if(oven_ready) {
-        timeout(20s) {
-            retry(3) {
-                BakeDelicateItem
-            }
-        }
-    }
-}
-
-

Execution flows outside-in: first the if checks the oven, then the timeout starts, then the retry begins.

-

Subtree References

-

The include keyword references another behavior tree, enabling reuse:

-
behavior SourdoughRecipe {
-    then sourdough {
-        MixDough(recipe: "sourdough", quantity: 10)
-        KneadDough(duration: 15m)
-        FirstRise(duration: 2h)
-        ShapeLoaves
-    }
-}
-
-behavior Martha_DailyRoutine {
-    choose daily_priority {
-        then special_orders {
-            if(has_special_orders)
-            include SpecialOrderBehavior
-        }
-
-        include SourdoughRecipe    // Reuse sourdough behavior
-    }
-}
-
-

Subtrees help you avoid duplicating behavior logic. You can also reference behaviors from other modules using qualified paths:

-
include behaviors::baking::sourdough
-include behaviors::service::greet_customer
-
-

Behavior Linking with Priorities

-

Characters can link to multiple behaviors with priorities and conditions:

-
character Martha: Human {
-    uses behaviors: [
-        {
-            tree: BakerRoutine
-            priority: normal
-        },
-        {
-            tree: HandleEmergency
-            when: emergency_detected
-            priority: high
-        },
-        {
-            tree: HandleHealthInspection
-            when: inspector_present
-            priority: critical
-        }
-    ]
-}
-
-

The runtime evaluates behaviors by priority (critical > high > normal > low). Higher-priority behaviors preempt lower-priority ones when their conditions are met.

-

A Complete Example

-

Here is a complete behavior tree for handling the morning rush:

-
behavior MorningRush_Routine {
-    ---description
-    The bakery's morning rush routine: serve customers, restock,
-    and keep the ovens running.
-    ---
-
-    repeat {
-        then rush_cycle {
-            // Serve any waiting customers
-            choose service_mode {
-                then serve_regular {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                    PackageItems
-                    CollectPayment
-                }
-
-                then restock {
-                    if(display_low)
-                    FetchFromKitchen
-                    ArrangeOnShelves
-                }
-            }
-
-            // Check ovens between customers
-            timeout(5s) {
-                CheckAllOvens
-            }
-
-            PrepareNextBatch
-        }
-    }
-}
-
-

This tree repeats forever: serve a customer or restock the display, check the ovens, and prepare the next batch.

-

Next Steps

-

You now know the full toolkit for behavior trees. In Advanced Behaviors, you will learn patterns for building complex AI systems with nested trees, state-based switching, and modular design.

-
-

Reference: See Decorators Reference for all decorator types and Expression Language for complete condition syntax.

-

Advanced Behaviors

-

You have learned the fundamentals of behavior trees. This chapter covers advanced patterns: complex decision hierarchies, modular design with subtrees, and state-driven behavior.

-

Deep Decision Trees

-

Real characters need layered decision-making. Nest selectors and sequences to create rich AI:

-
behavior Baker_DailyAI {
-    choose daily_activity {
-        // Morning: Prepare the bakery
-        then morning_prep {
-            if(time_is_morning)
-            then prep_sequence {
-                LightOven
-                PrepareDough
-                StartFirstBatch
-            }
-        }
-
-        // Day: Serve customers
-        then day_service {
-            if(time_is_daytime)
-            choose service_mode {
-                then serve_customer {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                    PackageItems
-                    CollectPayment
-                }
-
-                then restock {
-                    if(display_low)
-                    FetchFromKitchen
-                }
-
-                CleanCounter
-            }
-        }
-
-        // Evening: Close up
-        then evening_close {
-            if(time_is_evening)
-            then close_sequence {
-                TurnOffOvens
-                CleanKitchen
-                CountRegister
-                LockUp
-            }
-        }
-    }
-}
-
-

Each level of nesting refines the decision. The outer choose selects the time of day; inner nodes handle the specifics.

-

Modular Subtrees

-

Large behavior trees become unwieldy. Break them into focused subtrees and compose with include:

-
// Focused subtree: just baking
-behavior Baking_Sourdough {
-    then sourdough_sequence {
-        MixDough
-        KneadDough
-        FirstRise
-        ShapeLoaves
-    }
-}
-
-// Focused subtree: just customer service
-behavior Service_ServeCustomer {
-    then service_sequence {
-        GreetCustomer
-        TakeOrder
-        PackageItems
-        CollectPayment
-    }
-}
-
-// Composition: combine subtrees
-behavior Martha_FullDay {
-    choose activity {
-        then morning_baking {
-            if(time_is_morning)
-            include Baking_Sourdough
-            include Baking_Pastries
-        }
-
-        then afternoon_sales {
-            if(time_is_afternoon)
-            include Service_ServeCustomer
-        }
-
-        CleanWorkstation
-    }
-}
-
-

Benefits of modular subtrees:

-
    -
  • Each subtree is testable in isolation
  • -
  • Multiple characters can share subtrees
  • -
  • Changes propagate automatically
  • -
-

Conditional Behavior Selection

-

Use conditions to switch between behavioral modes:

-
behavior SmartBaker {
-    choose strategy {
-        // Busy mode when there are many customers
-        then busy_mode {
-            if(customer_count > 5 and inventory_sufficient)
-            choose rush_tactics {
-                ServeFastOrder
-                QuickRestock
-                ExpressBake
-            }
-        }
-
-        // Careful mode when supplies are low
-        then careful_mode {
-            if(inventory_low or special_ingredients_missing)
-            choose conservation_tactics {
-                ReducePortions
-                SubstituteIngredients
-                OrderEmergencySupply
-            }
-        }
-
-        // Normal mode otherwise
-        then normal_mode {
-            if(customer_count <= 5 and inventory_sufficient)
-            StandardRoutine
-        }
-    }
-}
-
-

Decorator Combinations

-

Combine decorators to build sophisticated control patterns:

-
behavior Baker_SpecialRecipe {
-    // Only when inventory is sufficient
-    if(has_special_ingredients) {
-        // Limited to once per hour
-        cooldown(1h) {
-            // Must complete within 30 minutes
-            timeout(30m) {
-                // Try up to 3 times
-                retry(3) {
-                    then bake_special {
-                        PrepareSpecialDough
-                        BakeAtPreciseTemperature
-                    }
-                }
-            }
-        }
-    }
-}
-
-

Prose Documentation

-

Add narrative context to complex behaviors with prose blocks:

-
behavior Elena_TrainingSession {
-    ---description
-    Elena practicing a new recipe under Martha's guidance.
-    Uses retry decorator for persistence and if for
-    checking readiness.
-    ---
-
-    choose training_strategy {
-        then practice_supervised {
-            if(martha_available)
-            retry(3) {
-                then attempt_recipe {
-                    ReviewRecipeSteps
-                    MeasureIngredients
-                    MixAndKnead
-                    CheckWithMartha
-                }
-            }
-        }
-
-        then practice_solo {
-            if(not martha_available)
-            then solo_attempt {
-                ReviewRecipeNotes
-                AttemptRecipeFromMemory
-                TasteTestResult
-            }
-        }
-    }
-}
-
-

Design Tips

-

Prefer shallow trees: Break deep nesting into subtrees with include.

-

Name every composite node: Labels make trees self-documenting.

-

Use decorators for control flow: Timing, repetition, and gating belong in decorators, not in action logic.

-

Keep actions atomic: Each action should do one thing. Complex operations are sequences of simple actions.

-

Next Steps

-

Characters do not exist in isolation. In Character Relationships, you will model how characters connect to each other – friendships, rivalries, parent-child bonds, and more.

-
-

Reference: See Behavior Trees Reference and Decorators Reference for complete syntax.

-

Character Relationships

-

Characters exist in a web of connections – friendships, rivalries, parent-child bonds, and complex power dynamics. In Storybook, relationships are first-class declarations that capture these connections with nuance and perspective.

-

Basic Relationships

-

The simplest relationship connects two characters with shared fields:

-
relationship MarthaAndEmma {
-    Martha as parent {}
-    Emma as child {}
-
-    bond: 0.95
-    type: "parent_child"
-}
-
-

This says Martha and Emma share a relationship with a bond strength of 0.95 (very close). The bond field is shared – it applies equally to both participants.

-

Adding Roles

-

Roles label each participant’s function in the relationship:

-
relationship ParentChild {
-    Martha as parent
-    Emma as child
-
-    bond: 0.95
-    guardianship: true
-}
-
-

The as parent and as child labels clarify who plays which role. Roles are descriptive – you can use any name that makes sense.

-

Perspectives: Self and Other

-

Real relationships are not symmetric. How one person sees the relationship may differ from how the other sees it. Storybook handles this with self and other blocks:

-
relationship MentorApprentice {
-    Martha as mentor self {
-        patience: 0.8
-        investment_in_student: 0.9
-    } other {
-        sees_potential: 0.85
-        frustration_level: 0.2
-    }
-
-    Elena as apprentice self {
-        dedication: 0.9
-        overwhelmed: 0.4
-    } other {
-        admiration: 0.95
-        desire_to_impress: 0.9
-    }
-
-    bond: 0.85
-}
-
-

Reading this:

-
    -
  • Martha’s self view: She feels patient (80%), highly invested in her student
  • -
  • Martha’s view of Elena (other): Sees high potential (85%) with low frustration (20%)
  • -
  • Elena’s self view: Dedicated (90%) but sometimes overwhelmed (40%)
  • -
  • Elena’s view of Martha (other): Deep admiration (95%), strong desire to impress (90%)
  • -
  • Shared: Their bond strength is 0.85
  • -
-

Prose in Relationships

-

Relationships can include narrative descriptions for each participant:

-
relationship MarthaAndGregory {
-    Martha {
-        role: shopkeeper
-        values_loyalty: 0.9
-
-        ---perspective
-        Martha appreciates Gregory's unwavering loyalty. He has
-        been buying her sourdough loaf every morning for fifteen
-        years. Their brief daily exchanges about the weather and
-        local gossip are a comforting routine.
-        ---
-    }
-
-    Gregory {
-        role: regular_customer
-        always_orders: "sourdough_loaf"
-
-        ---perspective
-        Gregory considers Martha's bakery a cornerstone of his
-        daily routine. The bread is excellent, but it is the brief
-        human connection that keeps him coming back. He worries
-        about what would happen if she ever retired.
-        ---
-    }
-
-    bond: 0.7
-}
-
-

Multi-Party Relationships

-

Relationships can involve more than two participants:

-
relationship BakerFamily {
-    Martha as parent
-    Jane as parent
-    Emma as child
-
-    household: "Baker Residence"
-    family_bond: 0.95
-    dinner_time: 18:00
-
-    ---dynamics
-    A loving family running a bakery together. Martha handles
-    the bread, Jane manages pastries, and Emma helps out on
-    weekends while learning the craft.
-    ---
-}
-
-

Asymmetric Awareness

-

Relationships can model situations where one party does not know the relationship exists:

-
relationship BossAndNewHire {
-    Martha {
-        role: boss
-        aware_of_struggles: false
-        expects: high_quality_work
-
-        ---perspective
-        Martha sees the new hire as competent and expects them
-        to learn the bakery routines quickly. She has no idea
-        they are struggling with the early morning schedule.
-        ---
-    }
-
-    NewHire {
-        role: employee
-        intimidated: 0.8
-        hides_struggles: true
-
-        ---perspective
-        The new hire is in awe of Martha's skill but terrified
-        of disappointing her. They arrive thirty minutes early
-        every day to practice techniques before she gets in.
-        ---
-    }
-
-    bond: 0.4
-}
-
-

Institutional Relationships

-

Institutions can participate in relationships too:

-
relationship GuildMembership {
-    Martha as member
-    BakersGuild as organization
-
-    membership_since: "2015-01-01"
-    standing: "good"
-    dues_paid: true
-}
-
-

Building a Relationship Web

-

Multiple relationships create a rich social network:

-
relationship Marriage {
-    Martha as spouse
-    Jane as spouse
-    bond: 0.9
-}
-
-relationship MentorApprentice {
-    Martha as mentor
-    Elena as apprentice
-    bond: 0.85
-}
-
-relationship RegularCustomer {
-    Martha as shopkeeper
-    Gregory as customer
-    bond: 0.7
-}
-
-relationship Colleagues {
-    Martha as peer
-    NeighborBaker as peer
-    bond: 0.5
-    competitive: true
-}
-
-

Next Steps

-

Characters have traits, behaviors, and relationships. In Schedules and Time, you will give them daily routines and time-based activities.

-
-

Reference: For complete relationship syntax, see the Relationships Reference.

-

Schedules and Time

-

Characters live in time. A baker wakes before dawn to prepare dough; a guard patrols during the day shift; an innkeeper serves customers until late. Schedules define these time-based routines.

-

Basic Schedules

-

A schedule contains time blocks, each with a time range and an action:

-
schedule SimpleBaker {
-    block morning_prep {
-        05:00 - 08:00
-        action: baking::prepare_dough
-    }
-
-    block sales {
-        08:00 - 14:00
-        action: baking::serve_customers
-    }
-
-    block cleanup {
-        14:00 - 15:00
-        action: baking::close_shop
-    }
-}
-
-

Time ranges use 24-hour clock format (HH:MM). The action field links to a behavior tree that drives the character’s activity during that block.

-

Named Blocks

-

Blocks can have names (like morning_prep above). Named blocks are important for schedule composition – they allow child schedules to override specific blocks by name.

-

Linking Schedules to Characters

-

Characters use the uses schedule clause:

-
character Baker: Human {
-    uses schedule: SimpleBaker
-}
-
-

For multiple schedules:

-
character Innkeeper: Human {
-    uses schedules: [WeekdaySchedule, WeekendSchedule]
-}
-
-

Temporal Constraints

-

Blocks can be restricted to specific times using temporal constraints:

-

Season Constraints

-
schedule SeasonalBaker {
-    block summer_hours {
-        06:00 - 20:00
-        action: baking::long_shift
-        on season summer
-    }
-
-    block winter_hours {
-        07:00 - 18:00
-        action: baking::short_shift
-        on season winter
-    }
-}
-
-

Day of Week Constraints

-
schedule WeeklyPattern {
-    block weekday_work {
-        09:00 - 17:00
-        action: work::standard
-        on day monday
-    }
-
-    block weekend_rest {
-        10:00 - 16:00
-        action: leisure::relax
-        on day saturday
-    }
-}
-
-

Temporal constraint values (like summer or monday) reference enums defined in your storybook:

-
enum Season { spring, summer, fall, winter }
-enum DayOfWeek { monday, tuesday, wednesday, thursday, friday, saturday, sunday }
-
-

Recurring Events

-

Use recurs to define events that repeat on a schedule:

-
schedule MarketSchedule {
-    // Regular daily hours
-    block work {
-        08:00 - 17:00
-        action: shop::regular_sales
-    }
-
-    // Market day every Saturday
-    recurs MarketDay on day saturday {
-        block setup {
-            06:00 - 08:00
-            action: market::setup_stall
-        }
-
-        block busy_market {
-            08:00 - 18:00
-            action: market::busy_sales
-        }
-
-        block teardown {
-            18:00 - 20:00
-            action: market::pack_up
-        }
-    }
-}
-
-

Recurrences take priority over regular blocks. On Saturdays, the MarketDay blocks replace the regular work block.

-

Schedule Composition with extends

-

Schedules can extend other schedules, inheriting and overriding blocks:

-
schedule BaseShopkeeper {
-    block open {
-        09:00 - 17:00
-        action: shop::standard_hours
-    }
-}
-
-schedule EarlyBaker extends BaseShopkeeper {
-    block open {
-        05:00 - 13:00
-        action: baking::early_shift
-    }
-}
-
-

The EarlyBaker schedule overrides the open block by name – same block name, different hours. Any blocks not overridden are inherited unchanged.

-

You can chain extensions:

-
schedule MasterBaker extends EarlyBaker {
-    block open {
-        03:00 - 11:00
-        action: baking::master_work
-    }
-
-    block teaching {
-        14:00 - 16:00
-        action: baking::teach_apprentice
-    }
-}
-
-

MasterBaker overrides open again and adds a new teaching block.

-

Overnight Blocks

-

Time ranges can span midnight:

-
schedule NightGuard {
-    block night_patrol {
-        22:00 - 06:00
-        action: security::patrol
-    }
-}
-
-

The system interprets this as 22:00 to midnight on day one, then midnight to 06:00 on day two.

-

A Complete Schedule Example

-
schedule MasterBaker_FullYear {
-    // Daily base
-    block prep {
-        04:00 - 06:00
-        action: baking::prepare
-    }
-
-    block baking {
-        06:00 - 10:00
-        action: baking::bake
-    }
-
-    block sales {
-        10:00 - 16:00
-        action: baking::serve
-    }
-
-    block cleanup {
-        16:00 - 17:00
-        action: baking::clean
-    }
-
-    // Summer extended hours
-    block summer_sales {
-        10:00 - 20:00
-        action: baking::busy_summer
-        on season summer
-    }
-
-    // Weekly market
-    recurs MarketDay on day saturday {
-        block market_prep {
-            02:00 - 04:00
-            action: baking::market_prep
-        }
-
-        block market_sales {
-            08:00 - 18:00
-            action: baking::market_rush
-        }
-    }
-
-    // Annual harvest festival
-    recurs HarvestFestival on dates "Sep 20" .. "Sep 25" {
-        block festival {
-            06:00 - 23:00
-            action: baking::festival_mode
-        }
-    }
-}
-
-

Next Steps

-

Characters now have traits, behaviors, relationships, and schedules. In Life Arcs, you will learn how to model character development over time – how they grow, change, and evolve through different phases of life.

-
-

Reference: For complete schedule syntax, see the Schedules Reference.

-

Life Arcs

-

Characters grow and change. A timid apprentice becomes a confident master baker. A new employee finds their place in the team. Life arcs model these transformations as state machines – discrete phases with conditions that trigger transitions between them.

-

What is a Life Arc?

-

A life arc defines:

-
    -
  • States: Distinct phases (e.g., “apprentice”, “journeyman”, “master”)
  • -
  • Transitions: Conditions that move between states (e.g., “when skill > 80, become master”)
  • -
  • On-enter actions: Changes that happen when entering a state (e.g., set confidence to 0.9)
  • -
-

Your First Life Arc

-
life_arc BakerCareer {
-    state apprentice {
-        on enter {
-            Baker.skill_level: 0.2
-            Baker.confidence: 0.3
-        }
-
-        on skill_level > 0.5 -> journeyman
-    }
-
-    state journeyman {
-        on enter {
-            Baker.confidence: 0.6
-        }
-
-        on skill_level > 0.8 -> master
-    }
-
-    state master {
-        on enter {
-            Baker.confidence: 0.95
-            Baker.can_teach: true
-        }
-    }
-}
-
-

Reading this as a story:

-
-

The baker starts as an apprentice with low skill and confidence. When skill exceeds 0.5, they become a journeyman with improved confidence. When skill exceeds 0.8, they become a master who is confident and can teach others.

-
-

States

-

Each state represents a distinct phase. States contain:

-
    -
  • on enter block: Field updates that happen when entering the state
  • -
  • Transitions: Conditions that trigger moving to another state
  • -
  • Prose blocks: Narrative descriptions
  • -
-
state early_apprentice {
-    on enter {
-        Elena.skill_level: novice
-        Elena.confidence: timid
-    }
-
-    on recipes_mastered > 5 -> growing_apprentice
-    on quit_apprenticeship -> former_apprentice
-
-    ---narrative
-    Elena's hands shake as she measures flour. She checks the
-    recipe three times before adding each ingredient. Martha
-    patiently corrects her technique.
-    ---
-}
-
-

Transitions

-

Transitions use expressions to decide when to change state:

-
// Simple conditions
-on health < 20 -> fleeing
-on quest_complete -> celebrating
-
-// Boolean fields
-on is_hostile -> combat
-on not ready -> waiting
-
-// Equality checks
-on status is active -> active_state
-on name is "Martha" -> found_martha
-
-// Complex conditions
-on health < 50 and enemy_count > 3 -> retreat
-on (tired and hungry) or exhausted -> resting
-
-

Transition Priority

-

When multiple transitions could fire, the first one in declaration order wins:

-
state combat {
-    on health < 10 -> desperate    // Checked first
-    on health < 50 -> defensive    // Checked second
-    on surrounded -> retreat       // Checked third
-}
-
-

If health is 5, only desperate triggers, even though defensive is also true.

-

On-Enter Actions

-

The on enter block sets field values when entering a state. It runs exactly once per transition:

-
state master_baker {
-    on enter {
-        Elena.skill_level: master
-        Elena.confidence: commanding
-        Elena.can_teach: true
-    }
-}
-
-

The syntax is EntityName.field: value. This updates the referenced character’s field.

-

Elena’s Complete Journey

-

Here is a complete life arc tracking Elena’s growth from apprentice to master:

-
life_arc ElenaCareer {
-    ---description
-    Tracks Elena's professional and personal growth as she
-    progresses from nervous apprentice to confident master baker.
-    ---
-
-    state early_apprentice {
-        on enter {
-            Elena.skill_level: novice
-            Elena.confidence: timid
-        }
-
-        on recipes_mastered > 5 -> growing_apprentice
-
-        ---narrative
-        Elena's hands shake as she measures flour. She checks the
-        recipe three times before adding each ingredient. Martha
-        patiently corrects her technique.
-        ---
-    }
-
-    state growing_apprentice {
-        on enter {
-            Elena.skill_level: beginner
-            Elena.confidence: uncertain
-        }
-
-        on recipes_mastered > 15 -> journeyman
-
-        ---narrative
-        The shaking stops. Elena can make basic breads without
-        looking at the recipe. She still doubts herself but
-        Martha's encouragement is taking root.
-        ---
-    }
-
-    state journeyman {
-        on enter {
-            Elena.skill_level: intermediate
-            Elena.confidence: growing
-            Elena.can_work_independently: true
-        }
-
-        on recipes_mastered > 50 -> master
-
-        ---narrative
-        Elena runs the morning shift alone while Martha handles
-        special orders. Customers start asking for "Elena's rolls."
-        ---
-    }
-
-    state master {
-        on enter {
-            Elena.skill_level: master
-            Elena.confidence: commanding
-            Elena.can_teach: true
-        }
-
-        ---narrative
-        Master Baker Elena. She has earned it. The guild acknowledges
-        her mastery, and Martha beams with pride. Elena begins
-        mentoring her own apprentice.
-        ---
-    }
-}
-
-

Common Patterns

-

Hub-and-Spoke

-

A central idle state with branches to specialized states:

-
life_arc BakerBehavior {
-    state idle {
-        on customer_arrived -> serving
-        on order_placed -> baking
-        on delivery_arrived -> receiving
-    }
-
-    state serving { on customer_served -> idle }
-    state baking { on batch_complete -> idle }
-    state receiving { on delivery_processed -> idle }
-}
-
-

Linear Progression

-

States form a one-way sequence (quests, tutorials):

-
life_arc Tutorial {
-    state intro { on clicked_start -> movement }
-    state movement { on moved_forward -> combat }
-    state combat { on defeated_enemy -> inventory }
-    state inventory { on opened_inventory -> complete }
-    state complete {}
-}
-
-

Cyclic States

-

States form a loop (day/night, seasons, mood swings):

-
life_arc DayNightCycle {
-    state dawn { on hour >= 8 -> day }
-    state day { on hour >= 18 -> dusk }
-    state dusk { on hour >= 20 -> night }
-    state night { on hour >= 6 -> dawn }
-}
-
-

Tips

-

Order transitions by urgency: Put the most critical conditions first, since the first true transition wins.

-

Use descriptive state names: waiting_for_customer is clearer than state1.

-

Add narrative prose blocks: They make life arcs readable as stories and serve as documentation.

-

Avoid orphan states: Every state should be reachable from some other state (the compiler will warn you about unreachable states).

-

What You Have Learned

-

Congratulations! You have completed the tutorial. You now know how to:

-
    -
  • Create characters with species, templates, and enums
  • -
  • Build behavior trees with selectors, sequences, and decorators
  • -
  • Add conditions and action parameters
  • -
  • Model relationships with perspectives
  • -
  • Define time-based schedules
  • -
  • Track character development with life arcs
  • -
-

Where to Go Next

- -
-

Reference: For complete life arc syntax, see the Life Arcs Reference.

-

Locations and Institutions

-

So far you have created characters, given them behaviors, connected them with relationships, scheduled their days, and guided them through life arcs. But characters need places to be and organizations to belong to. That is what locations and institutions provide.

-
-

What Are Locations?

-

A location is a place in your world. It can be a building, a room, a park, a city – any space where things happen. Locations hold fields that describe the place and optional prose blocks for narrative detail.

-

Your First Location

-

Let’s create the bakery where Martha works:

-
location BakersBakery {
-    type: bakery
-    address: "14 Main Street"
-    capacity: 30
-}
-
-

That is all it takes. The location keyword, a name, and a block of fields. Every field is a key-value pair, and you choose whatever fields make sense for your world.

-

Adding Detail

-

A real location needs more than three fields. Let’s flesh out the bakery:

-
location BakersBakery {
-    type: bakery
-    address: "14 Main Street"
-    capacity: 30
-    employees: 4
-    specialty: "artisan sourdough"
-    daily_output_loaves: 80..120
-    open: true
-    established: "2011"
-}
-
-

Notice daily_output_loaves: 80..120 – that is a range. Each simulation run can pick a different number of loaves, adding natural variation.

-

Prose Blocks

-

Bare fields are good for data, but locations also need narrative flavor. Use prose blocks:

-
location BakersBakery {
-    type: bakery
-    address: "14 Main Street"
-    capacity: 30
-
-    ---description
-    A warm, inviting bakery on Main Street. The smell of fresh bread
-    wafts out the door every morning at dawn. Martha has run the shop
-    for fifteen years, and the locals consider it the heart of the
-    neighborhood.
-    ---
-}
-
-

Prose blocks start with ---tag_name and end with ---. The tag name (description here) becomes the key. You can have as many prose blocks as you want:

-
location BakersBakery {
-    type: bakery
-
-    ---description
-    The bakery on Main Street...
-    ---
-
-    ---history
-    Originally a hardware store, Martha converted the space in 2011...
-    ---
-
-    ---atmosphere
-    Flour dust catches the light from tall windows...
-    ---
-}
-
-
-

Building a World with Locations

-

Locations work best when they form a coherent world. Here is the Baker family’s neighborhood:

-
location BakersBakery {
-    type: bakery
-    address: "14 Main Street"
-    capacity: 30
-    owner: Martha
-
-    ---description
-    Martha's artisan bakery. The stone oven was imported from France.
-    ---
-}
-
-location BakerHome {
-    type: residence
-    address: "22 Elm Lane"
-    bedrooms: 4
-    has_garden: true
-
-    ---description
-    The Baker family home. Martha insisted on an oversized kitchen.
-    ---
-}
-
-location BakersGuildHall {
-    type: guild_hall
-    address: "7 Guild Row"
-    capacity: 100
-    established: "1892"
-
-    ---description
-    The historic headquarters of the Bakers Guild.
-    ---
-}
-
-location TownSquare {
-    type: public_square
-    capacity: 500
-    has_fountain: true
-    has_market_stalls: true
-
-    ---description
-    The central gathering place. On weekends, the farmers market
-    fills the square with produce stalls.
-    ---
-}
-
-

Modeling Hierarchy

-

Storybook does not enforce a built-in parent-child relationship for locations. Instead, you use fields to express hierarchy:

-
location MainStreet {
-    type: street
-    district: TownCenter
-    shops: 12
-}
-
-location BakersBakery {
-    type: bakery
-    street: MainStreet
-    district: TownCenter
-}
-
-

This convention-based approach keeps the language simple while letting you model whatever spatial relationships your world needs.

-
-

What Are Institutions?

-

An institution is an organization, group, or system. Think of it as a character that represents a collective: a guild, a government, a school, a business. Institutions have a key capability that locations lack – they can use behaviors and schedules, just like characters.

-

Your First Institution

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-}
-
-

This looks just like a location so far. The difference comes when you add behaviors.

-

Institutions with Behaviors

-

Institutions can act. The uses behaviors clause links behavior trees to the institution:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    reputation: 0.85
-
-    uses behaviors: [
-        { tree: ManageApprentices },
-        { tree: NegotiateSuppliers },
-        { tree: HostEvents }
-    ]
-}
-
-

Each entry in the list is a behavior link object with a tree field. This tells the simulation engine that the Bakers Guild can manage apprentices, negotiate with suppliers, and host events.

-

Behavior Priorities

-

Not all behaviors are equally important. Use the priority field:

-
institution BakersGuild {
-    type: trade_guild
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostEvents, priority: low }
-    ]
-}
-
-

Priority levels are low, normal, high, and critical. Higher-priority behaviors take precedence when the institution must choose between actions.

-

Conditional Behaviors

-

Some behaviors only activate under certain conditions:

-
institution BakersGuild {
-    type: trade_guild
-    reputation: 0.85
-
-    uses behaviors: [
-        { tree: ManageApprentices },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: EmergencyMeeting, when: reputation < 0.3, priority: critical }
-    ]
-}
-
-

The when clause uses an expression. Here, the emergency meeting behavior only activates when reputation drops below 0.3.

-

Institutions with Schedules

-

Institutions can also follow schedules:

-
institution BakersGuild {
-    type: trade_guild
-    uses schedule: GuildOperatingHours
-}
-
-

For multiple schedules:

-
institution BakersGuild {
-    type: trade_guild
-    uses schedules: [WeekdaySchedule, WeekendSchedule]
-}
-
-

Prose Blocks

-

Just like locations, institutions support prose blocks:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-
-    ---description
-    The Bakers Guild has been the backbone of the town's bread trade
-    since 1892. Members share recipes, arrange apprenticeships, and
-    collectively negotiate flour prices.
-    ---
-
-    ---charter
-    Article I: All members shall maintain the highest standards.
-    Article II: Apprentices must complete a three-year program.
-    ---
-}
-
-
-

Connecting Characters to Institutions

-

Institutions do not have a built-in membership list. You model membership through character fields or relationships.

-

Through Character Fields

-

The simplest approach – add fields to your characters:

-
character Martha {
-    age: 45
-    occupation: baker
-    guild: BakersGuild
-    guild_role: guild_master
-    guild_member_since: "2005"
-}
-
-character Jane {
-    age: 19
-    occupation: apprentice_baker
-    guild: BakersGuild
-    guild_role: apprentice
-    guild_member_since: "2024"
-}
-
-

Through Relationships

-

For richer modeling, use relationships:

-
relationship GuildMembership {
-    Martha as guild_master { years_active: 20 }
-    BakersGuild as organization { }
-    bond: 0.95
-}
-
-relationship Apprenticeship {
-    Jane as apprentice { skills_learned: 12 }
-    Martha as mentor { patience_remaining: 0.7 }
-    BakersGuild as guild { }
-    years_completed: 1
-}
-
-

This approach captures richer information: roles, duration, and multi-party connections.

-
-

Locations vs. Institutions

-

When should you use each?

-
- - - - - - -
QuestionUse…
Where does something happen?Location
Who or what organizes things?Institution
Does it need behaviors?Institution
Does it need a schedule?Institution
Is it purely a place?Location
Is it a group or organization?Institution
-
-

Sometimes the same concept needs both:

-
// The physical building
-location BakersGuildHall {
-    type: guild_hall
-    address: "7 Guild Row"
-    capacity: 100
-}
-
-// The organization that meets there
-institution BakersGuild {
-    type: trade_guild
-    members: 50
-    location: BakersGuildHall
-
-    uses behaviors: [
-        { tree: ManageApprentices },
-        { tree: NegotiateSuppliers }
-    ]
-
-    uses schedule: GuildOperatingHours
-}
-
-

The guild hall is a place. The guild is an organization. Keeping them separate lets you say “the guild meets at the guild hall” without conflating the building with the institution.

-
-

Putting It All Together

-

Here is a complete example showing how locations, institutions, and characters work together in the Baker family world:

-
// Enums for type safety
-enum PlaceType {
-    bakery, residence, guild_hall, public_square
-}
-
-enum GuildRole {
-    guild_master, journeyman, apprentice
-}
-
-// Locations: where things happen
-location BakersBakery {
-    type: bakery
-    address: "14 Main Street"
-    capacity: 30
-    owner: Martha
-
-    ---description
-    Martha's artisan bakery on Main Street.
-    ---
-}
-
-location BakerHome {
-    type: residence
-    address: "22 Elm Lane"
-    bedrooms: 4
-    residents: ["Martha", "David", "Jane", "Tom"]
-}
-
-location BakersGuildHall {
-    type: guild_hall
-    address: "7 Guild Row"
-    capacity: 100
-
-    ---description
-    The historic Bakers Guild headquarters, established 1892.
-    ---
-}
-
-// Institution: the organization
-institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-    location: BakersGuildHall
-    leader: Martha
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostAnnualBakeOff, when: month is october }
-    ]
-
-    uses schedule: GuildOperatingHours
-
-    ---description
-    The Bakers Guild oversees apprenticeships, quality standards,
-    and the annual Great Bake-Off competition.
-    ---
-}
-
-// Institution: the business
-institution BakersBakeryBusiness {
-    type: business
-    owner: Martha
-    employees: 4
-    location: BakersBakery
-
-    uses behaviors: [
-        { tree: DailyBakingOps, priority: high },
-        { tree: InventoryManagement }
-    ]
-
-    uses schedule: BakeryOperatingHours
-}
-
-// Characters connected to all of the above
-character Martha {
-    age: 45
-    occupation: baker
-    workplace: BakersBakery
-    home: BakerHome
-    guild: BakersGuild
-    guild_role: guild_master
-}
-
-character Jane {
-    age: 19
-    occupation: apprentice_baker
-    workplace: BakersBakery
-    home: BakerHome
-    guild: BakersGuild
-    guild_role: apprentice
-}
-
-// Relationships tying it all together
-relationship GuildLeadership {
-    Martha as guild_master { }
-    BakersGuild as guild { }
-    years_in_role: 8
-}
-
-relationship BakeryApprenticeship {
-    Jane as apprentice { }
-    Martha as mentor { }
-    BakersGuild as certifying_body { }
-    year: 1
-    total_years: 3
-}
-
-
-

Key Takeaways

-
    -
  1. Locations are simple: name, fields, prose blocks. They model places.
  2. -
  3. Institutions are richer: they add uses behaviors and uses schedule on top of fields and prose. They model organizations.
  4. -
  5. Membership is modeled through character fields or relationships, not built into institution syntax.
  6. -
  7. Separate place from organization: A guild hall (location) and the guild (institution) are different things.
  8. -
  9. Use enums for type-safe categorization of locations and institutions.
  10. -
-
-

Next Steps

- -

Language Overview

-
-

The Storybook language enables narrative simulation through structured declarations of characters, behaviors, relationships, and events.

-
-

Philosophy

-

Storybook is a domain-specific language for narrative simulation, influenced by:

-
    -
  • Rust: Strong typing, explicit declarations, and clear ownership semantics
  • -
  • C#: Object-oriented patterns with declarative syntax
  • -
  • Python: Readable, accessible syntax that prioritizes clarity
  • -
-

The language balances technical precision with narrative expressiveness, making it accessible to storytellers while maintaining the rigor developers need.

-

Design Principles

-

1. Code as Narrative

-

Named nodes and prose blocks let code read like stories:

-
behavior Baker_MorningRoutine {
-    choose daily_priority {
-        then prepare_sourdough { ... }
-        then serve_customers { ... }
-        then restock_display { ... }
-    }
-}
-
-

2. Explicit is Better Than Implicit

-

Every declaration is self-documenting:

-
    -
  • Character fields show what defines them
  • -
  • Behavior trees show decision structures
  • -
  • Relationships name their participants
  • -
-

3. Progressive Disclosure

-

Simple cases are simple, complex cases are possible:

-
    -
  • Basic characters need just a name and fields
  • -
  • Templates enable inheritance and reuse
  • -
  • Advanced features (state machines, decorators) available when needed
  • -
-

4. Semantic Validation

-

The compiler catches narrative errors:

-
    -
  • Bond values must be 0.0..1.0
  • -
  • Schedule blocks can’t overlap
  • -
  • Life arc transitions must reference valid states
  • -
-

Language Structure

-

Declaration Types

-

Storybook has 10 top-level declaration types:

-
- - - - - - - - - - -
DeclarationPurposeExample
characterDefine entities with traits and behaviorsA baker with skills and schedule
templateReusable patterns with rangesA generic NPC template
behaviorDecision trees for actionsHow a character responds to events
life_arcState machines for life stagesApprentice → Baker → Master
scheduleTime-based activitiesDaily routine from 6am to 10pm
relationshipConnections between entitiesParent-child with bond values
institutionOrganizations and groupsA bakery with employees
locationPlaces with propertiesThe town square
speciesType definitions with traitsHuman vs Cat vs Rabbit
enumNamed value setsEmotionalState options
-
-

Value Types

-

Fields can contain:

-
    -
  • Primitives: 42, 3.14, "text", true
  • -
  • Time: 08:30:00, 14:15
  • -
  • Duration: 2h30m, 45s
  • -
  • Ranges: 20..40 (for templates)
  • -
  • Identifiers: OtherCharacter, path::to::Thing
  • -
  • Lists: [1, 2, 3]
  • -
  • Objects: { field: value }
  • -
  • Prose blocks: ---tag\nMulti-line\ntext\n---
  • -
-

Expression Language

-

Conditions and queries use:

-
    -
  • Comparisons: age > 18, energy <= 0.5
  • -
  • Equality: status is active, ready is true
  • -
  • Logic: tired and hungry, rich or lucky, not ready
  • -
  • Field access: self.health, other.bond
  • -
  • Quantifiers: forall x in children: x.happy
  • -
-

Compilation Model

-

Source → AST → SBIR → Runtime

-
.sb files → Parser → Abstract Syntax Tree → Resolver → SBIR Binary
-
-

SBIR (Storybook Intermediate Representation) is a compact binary format that:

-
    -
  • Resolves all cross-file references
  • -
  • Validates semantic constraints
  • -
  • Optimizes for simulation runtime
  • -
-

Validation Layers

-
    -
  1. Lexical: Valid tokens and syntax
  2. -
  3. Syntactic: Correct grammar structure
  4. -
  5. Semantic: Type checking, reference resolution
  6. -
  7. Domain: Narrative constraints (bond ranges, schedule overlaps)
  8. -
-

File Organization

-

Project Structure

-
my-storybook/
-├── characters/
-│   ├── baker.sb
-│   └── family.sb
-├── behaviors/
-│   └── daily_routine.sb
-├── world/
-│   ├── locations.sb
-│   └── institutions.sb
-└── schema/
-    ├── species.sb
-    └── templates.sb
-
-

Import System

-

Use use statements to reference definitions from other files:

-
use schema::species::Human;
-use schema::templates::Adult;
-
-character Baker: Human from Adult {
-    // ...
-}
-
-

Resolution order:

-
    -
  1. Same file
  2. -
  3. Explicitly imported
  4. -
  5. Error if not found
  6. -
-

Quick Reference

-

Character Declaration

-
character Name: Species from Template {
-    field: value
-    field: value
-    ---prose_tag
-    Text content
-    ---
-}
-
-

Behavior Tree

-
behavior Name {
-    choose label {           // Selector
-        then label { ... }   // Sequence
-        if (condition)       // Condition
-        ActionName          // Action
-        include path        // Subtree
-    }
-}
-
-

Life Arc

-
life_arc Name {
-    state StateName {
-        on condition -> NextState
-    }
-}
-
-

Schedule

-
schedule Name {
-    08:00 -> 12:00: activity { }
-    12:00 -> 13:00: lunch { }
-}
-
-

Relationship

-
relationship Name {
-    Person1 as role
-    Person2 as role
-    bond: 0.85
-}
-
-

Next Steps

-

Dive deeper into each declaration type:

- -
-

Philosophy Note: Storybook treats narrative as data. Characters aren’t objects with methods - they’re declarations of traits, connected by behaviors and relationships. This separation enables rich analysis, modification, and simulation of narrative worlds.

-

Characters

-

Characters are the primary entities in Storybook—the people, creatures, and beings that inhabit your world. Each character has a set of attributes that define who they are, what they can do, and how they relate to the world around them.

-

Syntax

-
<character-decl> ::= "character" <identifier> <species-clause>? <template-clause>? <body>
-
-<species-clause> ::= ":" <qualified-path>
-
-<template-clause> ::= "from" <qualified-path> ("," <qualified-path>)*
-
-<body> ::= "{" <body-item>* "}"
-
-<body-item> ::= <field>
-              | <uses-behaviors>
-              | <uses-schedule>
-
-<uses-behaviors> ::= "uses" "behaviors" ":" <behavior-link-list>
-
-<uses-schedule> ::= "uses" ("schedule" | "schedules") ":" (<qualified-path> | <schedule-list>)
-
-<behavior-link-list> ::= "[" <behavior-link> ("," <behavior-link>)* "]"
-
-<behavior-link> ::= "{" <behavior-link-field>* "}"
-
-<behavior-link-field> ::= "tree" ":" <qualified-path>
-                        | "when" ":" <expression>
-                        | "priority" ":" ("low" | "normal" | "high" | "critical")
-
-<schedule-list> ::= "[" <qualified-path> ("," <qualified-path>)* "]"
-
-<field> ::= <identifier> ":" <value>
-
-<value> ::= <literal>
-          | <qualified-path>
-          | <list>
-          | <object>
-          | <prose-block>
-          | <override>
-
-<prose-block> ::= "---" <identifier> <content> "---"
-
-

Components

-

Name

-

The character’s identifier. Must be unique within its scope and follow standard identifier rules (alphanumeric + underscore, cannot start with digit).

-

Species (Optional)

-

The species clause (: SpeciesName) defines what the character fundamentally is. This is distinct from templates, which define what attributes they have.

-
    -
  • Purpose: Ontological typing—what kind of being this is
  • -
  • Validation: Must reference a defined species declaration
  • -
  • Single inheritance: A character can only have one species
  • -
  • Default behavior: Species fields are inherited automatically
  • -
-

Example:

-
character Martha: Human {
-    age: 34
-}
-
-

Template Inheritance (Optional)

-

The template clause (from Template1, Template2) specifies templates from which the character inherits fields. Templates provide reusable attribute sets.

-
    -
  • Purpose: Compositional inheritance—mix-and-match capabilities and traits
  • -
  • Multiple inheritance: Characters can inherit from multiple templates
  • -
  • Merge semantics: Fields from later templates override earlier ones
  • -
  • Override allowed: Character fields override all inherited fields
  • -
-

Example:

-
character Martha: Human from Baker, BusinessOwner {
-    specialty: "sourdough"
-}
-
-

Fields

-

Fields define the character’s attributes using the standard field syntax. All value types are supported.

-

Common field categories:

-
    -
  • Physical traits: height, weight, age, eye_color
  • -
  • Personality: confidence, patience, dedication
  • -
  • Professional: skill_level, specialty, recipes_mastered
  • -
  • State tracking: energy, mood, orders_today
  • -
  • Capabilities: can_teach, can_work_independently
  • -
-

Prose Blocks

-

Characters can contain multiple prose blocks for narrative content. Common tags:

-
    -
  • ---backstory: Character history and origin
  • -
  • ---appearance: Physical description
  • -
  • ---personality: Behavioral traits and quirks
  • -
  • ---motivation: Goals and desires
  • -
  • ---secrets: Hidden information
  • -
-

Prose blocks are narrative-only and do not affect simulation logic.

-

Behavior Integration

-

Characters can link to behavior trees using the uses behaviors clause.

-
character Guard {
-    uses behaviors: [
-        {
-            tree: combat::patrol_route
-            priority: normal
-        },
-        {
-            tree: combat::engage_intruder
-            when: threat_detected
-            priority: high
-        }
-    ]
-}
-
-

Each behavior link includes:

-
    -
  • tree: Qualified path to the behavior tree (required)
  • -
  • when: Condition expression for activation (optional)
  • -
  • priority: Execution priority (optional, default: normal)
  • -
-

See Behavior Trees for details on behavior tree syntax and semantics.

-

Schedule Integration

-

Characters can follow schedules using the uses schedule or uses schedules clause.

-
character Baker {
-    uses schedule: BakerySchedule
-}
-
-character Innkeeper {
-    uses schedules: [WeekdaySchedule, WeekendSchedule]
-}
-
-
    -
  • Single schedule: uses schedule: ScheduleName
  • -
  • Multiple schedules: uses schedules: [Schedule1, Schedule2]
  • -
-

The runtime selects the appropriate schedule based on temporal constraints. See Schedules for composition and selection semantics.

-

Species vs. Templates

-

The distinction between species (:) and templates (from) reflects ontological vs. compositional typing:

-
- - - - - -
FeatureSpecies (:)Templates (from)
SemanticsWhat the character isWhat the character has
CardinalityExactly oneZero or more
Example: Human, : Dragonfrom Warrior, Mage
PurposeFundamental natureReusable trait sets
OverrideCan override species fieldsCan override template fields
-
-

Example showing both:

-
species Dragon {
-    max_lifespan: 1000
-    can_fly: true
-}
-
-template Hoarder {
-    treasure_value: 0..1000000
-    greed_level: 0.0..1.0
-}
-
-template Ancient {
-    age: 500..1000
-    wisdom: 0.8..1.0
-}
-
-character Smaug: Dragon from Hoarder, Ancient {
-    age: 850
-    treasure_value: 500000
-    greed_level: 0.95
-}
-
-

Field Resolution Order

-

When a character inherits from species and templates, fields are resolved in this order (later overrides earlier):

-
    -
  1. Species fields (base ontology)
  2. -
  3. Template fields (left to right in from clause)
  4. -
  5. Character fields (highest priority)
  6. -
-

Example:

-
species Human {
-    lifespan: 80
-    speed: 1.0
-}
-
-template Warrior {
-    speed: 1.5
-    strength: 10
-}
-
-template Berserker {
-    speed: 2.0
-    strength: 15
-}
-
-character Conan: Human from Warrior, Berserker {
-    strength: 20
-}
-
-// Resolved fields:
-// lifespan: 80     (from Human)
-// speed: 2.0       (Berserker overrides Warrior overrides Human)
-// strength: 20     (character overrides Berserker)
-
-

Validation Rules

-

The Storybook compiler enforces these validation rules:

-
    -
  1. Unique names: Character names must be unique within their module
  2. -
  3. Species exists: If specified, the species must reference a defined species declaration
  4. -
  5. Templates exist: All templates in the from clause must reference defined template declarations
  6. -
  7. No circular inheritance: Templates cannot form circular dependency chains
  8. -
  9. Field type consistency: Field values must match expected types from species/templates
  10. -
  11. Reserved fields: Cannot use reserved keywords as field names
  12. -
  13. Behavior trees exist: All behavior tree references must resolve to defined behavior declarations
  14. -
  15. Schedules exist: All schedule references must resolve to defined schedule declarations
  16. -
  17. Prose tag uniqueness: Each prose tag can appear at most once per character
  18. -
-

Examples

-

Basic Character

-
character SimpleMerchant {
-    name: "Gregor"
-    occupation: "Fish Merchant"
-    wealth: 50
-
-    ---personality
-    A straightforward fish seller at the market. Honest, hardworking,
-    and always smells faintly of mackerel.
-    ---
-}
-
-

Character with Species

-
character Martha: Human {
-    age: 34
-    skill_level: 0.95
-    specialty: "sourdough"
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age
-    twelve. She now runs the most popular bakery in town.
-    ---
-}
-
-

Character with Template Inheritance

-
character Jane: Human from Baker, PastrySpecialist {
-    age: 36
-    specialty: "pastries"
-    recipes_mastered: 120
-
-    years_experience: 18
-    can_teach: true
-
-    ---appearance
-    A focused woman with flour-dusted apron and steady hands.
-    Known for her intricate pastry decorations and precise
-    temperature control.
-    ---
-}
-
-

Character with All Features

-
character CityGuard: Human from CombatTraining, LawEnforcement {
-    age: 30
-    rank: "Sergeant"
-
-    // Physical traits
-    height: 175
-    strength: 12
-
-    // Equipment
-    has_weapon: true
-    armor_level: 2
-
-    // Behavior integration
-    uses behaviors: [
-        {
-            tree: guards::patrol_route
-            priority: normal
-        },
-        {
-            tree: guards::engage_hostile
-            when: threat_detected
-            priority: high
-        },
-        {
-            tree: guards::sound_alarm
-            when: emergency
-            priority: critical
-        }
-    ]
-
-    // Schedule integration
-    uses schedules: [guards::day_shift, guards::night_shift]
-
-    ---backstory
-    A veteran of the city watch, now responsible for training new recruits
-    while maintaining order in the merchant district.
-    ---
-
-    ---personality
-    Gruff exterior with a hidden soft spot for street children. Follows
-    the rules but knows when to look the other way.
-    ---
-}
-
-

Character with Overrides

-
template WeaponUser {
-    damage: 5..15
-    accuracy: 0.7
-}
-
-character MasterSwordsman: Human from WeaponUser {
-    // Override template range with specific value
-    damage: 15
-    accuracy: 0.95
-
-    // Add character-specific fields
-    signature_move: "Whirlwind Strike"
-}
-
-

Use Cases

-

Protagonist Definition

-

Define rich, dynamic protagonists with complex attributes:

-
character Elena: Human from Scholar, Diplomat {
-    age: 28
-    intelligence: 18
-    charisma: 16
-
-    languages_known: ["Common", "Elvish", "Draconic"]
-    books_read: 347
-
-    current_quest: "Broker peace between warring kingdoms"
-
-    ---backstory
-    Raised in the Grand Library, Elena discovered ancient texts that
-    hinted at a forgotten alliance between humans and dragons. She now
-    seeks to revive that alliance to end the current war.
-    ---
-}
-
-

NPC Templates

-

Create diverse NPCs from templates:

-
template Villager {
-    occupation: "Farmer"
-    wealth: 10..50
-    disposition: 0.0..1.0  // 0=hostile, 1=friendly
-}
-
-character Oswald: Human from Villager {
-    occupation: "Blacksmith"
-    wealth: 45
-    disposition: 0.8
-}
-
-character Mildred: Human from Villager {
-    occupation: "Baker"
-    wealth: 35
-    disposition: 0.95
-}
-
-

Ensemble Casts

-

Define multiple related characters:

-
template BakeryStaff {
-    punctuality: 0.5..1.0
-    teamwork: 0.5..1.0
-}
-
-template Apprentice {
-    skill_level: 0.0..0.5
-    dedication: 0.5..1.0
-}
-
-character Elena: Human from BakeryStaff, Apprentice {
-    age: 16
-    natural_talent: 0.8
-    dedication: 0.9
-
-    ---backstory
-    Elena comes from a family of farmers who could never afford to
-    buy bread from the bakery. When Martha offered her an apprenticeship,
-    she jumped at the chance to learn a trade.
-    ---
-}
-
-

Cross-References

- - -
    -
  • Instantiation: Characters are concrete instances; they cannot be instantiated further
  • -
  • Composition: Prefer template composition over deep species hierarchies
  • -
  • Modularity: Characters can reference behaviors and schedules from other modules
  • -
  • Narrative-driven: Use prose blocks to embed storytelling directly with data
  • -
-

Behavior Trees

-

Behavior trees define the decision-making logic for characters, institutions, and other entities. They model how an entity chooses actions, responds to conditions, and adapts to its environment. Storybook uses behavior trees for character AI, NPC routines, and complex reactive behavior.

-

What is a Behavior Tree?

-

A behavior tree is a hierarchical structure that executes from root to leaves, making decisions based on success/failure of child nodes:

-
    -
  • Composite nodes (choose, then) have multiple children and control flow
  • -
  • Condition nodes (if, when) test predicates
  • -
  • Action nodes execute concrete behaviors
  • -
  • Decorator nodes (repeat, invert, timeout, etc.) modify child behavior
  • -
  • Subtree nodes (include) reference other behavior trees
  • -
-

Behavior trees are evaluated every tick (frame), flowing through the tree from root to leaves until a node returns success or failure.

-

Syntax

-
<behavior-decl> ::= "behavior" <identifier> <body>
-
-<body> ::= "{" <prose-blocks>* <behavior-node> "}"
-
-<behavior-node> ::= <selector>
-                  | <sequence>
-                  | <condition>
-                  | <action>
-                  | <decorator>
-                  | <subtree>
-
-<selector> ::= "choose" <label>? "{" <behavior-node>+ "}"
-
-<sequence> ::= "then" <label>? "{" <behavior-node>+ "}"
-
-<condition> ::= ("if" | "when") "(" <expression> ")"
-
-<action> ::= <identifier> ( "(" <param-list> ")" )?
-
-<param-list> ::= <field> ("," <field>)*
-
-<decorator> ::= <decorator-type> ("(" <params> ")")? "{" <behavior-node> "}"
-
-<subtree> ::= "include" <qualified-path>
-
-<label> ::= <identifier>
-
-

Composite Nodes

-

Selector: choose

-

A selector tries its children in order until one succeeds. Returns success if any child succeeds, failure if all fail.

-

Execution:

-
    -
  1. Try first child
  2. -
  3. If succeeds -> return success
  4. -
  5. If fails -> try next child
  6. -
  7. If all fail -> return failure
  8. -
-

Use case: “Try A, if that fails try B, if that fails try C…”

-
behavior GuardBehavior {
-    choose guard_actions {
-        AttackIntruder      // Try first
-        SoundAlarm          // If attack fails, sound alarm
-        FleeInPanic         // If alarm fails, flee
-    }
-}
-
-

Named selectors:

-
choose service_options {
-    then serve_regular {
-        CustomerIsWaiting
-        TakeOrder
-    }
-
-    then restock_display {
-        DisplayIsLow
-        FetchFromKitchen
-    }
-}
-
-

Labels are optional but recommended for complex trees–they improve readability and debugging.

-

Sequence: then

-

A sequence runs its children in order until one fails. Returns success only if all children succeed, failure if any fails.

-

Execution:

-
    -
  1. Run first child
  2. -
  3. If fails -> return failure
  4. -
  5. If succeeds -> run next child
  6. -
  7. If all succeed -> return success
  8. -
-

Use case: “Do A, then B, then C… all must succeed”

-
behavior BrewingSequence {
-    then brew_potion {
-        GatherIngredients   // Must succeed
-        MixIngredients      // Then this must succeed
-        Boil                // Then this must succeed
-        BottlePotion        // Finally this
-    }
-}
-
-

Named sequences:

-
then prepare_sourdough {
-    MixDough
-    KneadDough
-    ShapeLoaves
-}
-
-

Nesting Composites

-

Composite nodes can nest arbitrarily deep:

-
behavior ComplexAI {
-    choose root_decision {
-        // Combat branch
-        then engage_combat {
-            if(enemy_nearby)
-            choose combat_tactics {
-                AttackWithSword
-                AttackWithMagic
-                DefendAndWait
-            }
-        }
-
-        // Exploration branch
-        then explore_area {
-            if(safe)
-            choose exploration_mode {
-                SearchForTreasure
-                MapTerritory
-                Rest
-            }
-        }
-
-        // Default: Idle
-        Idle
-    }
-}
-
-

Condition Nodes

-

Conditions test expressions and return success/failure based on the result.

-

if vs. when

-

Both are semantically identical–use whichever reads better in context:

-
behavior Example {
-    choose options {
-        // "if" for state checks
-        then branch_a {
-            if(player_nearby)
-            Attack
-        }
-
-        // "when" for event-like conditions
-        then branch_b {
-            when(alarm_triggered)
-            Flee
-        }
-    }
-}
-
-

Condition Syntax

-
if(health < 20)                          // Comparison
-when(is_hostile)                         // Boolean field
-if(distance > 10 and has_weapon)         // Logical AND
-when(not is_stunned or is_enraged)       // Logical OR with NOT
-
-

See Expression Language for complete expression syntax.

-

Action Nodes

-

Actions are leaf nodes that execute concrete behaviors. They reference action implementations in the runtime.

-

Basic Actions

-
behavior SimpleActions {
-    then do_things {
-        MoveForward
-        TurnLeft
-        Attack
-    }
-}
-
-

Actions with Parameters

-

Actions can have named parameters using parenthesis syntax:

-
behavior ParameterizedActions {
-    then patrol {
-        MoveTo(destination: "Waypoint1", speed: 1.5)
-        WaitFor(duration: 5s)
-        MoveTo(destination: "Waypoint2", speed: 1.5)
-    }
-}
-
-

Parameter passing:

-
    -
  • Parameters are passed as fields (name: value)
  • -
  • All value types supported
  • -
  • Runtime validates parameter types
  • -
-
behavior RichParameters {
-    then complex_action {
-        CastSpell(spell: "Fireball", target: enemy_position, power: 75, multicast: false)
-        Heal(amount: 50, target: self)
-    }
-}
-
-

Decorator Nodes

-

Decorators wrap a single child node and modify its behavior. See Decorators for complete reference.

-

Common Decorators

-
behavior DecoratorExamples {
-    choose {
-        // Repeat infinitely
-        repeat {
-            PatrolRoute
-        }
-
-        // Repeat exactly 3 times
-        repeat(3) {
-            CheckDoor
-        }
-
-        // Repeat 2 to 5 times
-        repeat(2..5) {
-            SearchArea
-        }
-
-        // Invert success/failure
-        invert {
-            IsEnemyNearby  // Returns success if enemy NOT nearby
-        }
-
-        // Retry up to 5 times on failure
-        retry(5) {
-            OpenLockedDoor
-        }
-
-        // Timeout after 10 seconds
-        timeout(10s) {
-            SolveComplexPuzzle
-        }
-
-        // Cooldown: only run once per 30 seconds
-        cooldown(30s) {
-            FireCannon
-        }
-
-        // If: only run if condition true
-        if(health > 50) {
-            AggressiveAttack
-        }
-
-        // Always succeed regardless of child result
-        succeed_always {
-            AttemptOptionalTask
-        }
-
-        // Always fail regardless of child result
-        fail_always {
-            ImpossipleTask
-        }
-    }
-}
-
-

Subtree References

-

The include keyword references another behavior tree, enabling modularity and reuse.

-

Basic Subtree

-
behavior PatrolRoute {
-    then patrol {
-        MoveTo(destination: "Waypoint1")
-        MoveTo(destination: "Waypoint2")
-        MoveTo(destination: "Waypoint3")
-    }
-}
-
-behavior GuardBehavior {
-    choose guard_ai {
-        then combat {
-            if(enemy_nearby)
-            include combat::engage
-        }
-
-        include PatrolRoute  // Reuse patrol behavior
-    }
-}
-
-

Qualified Subtree References

-
behavior ComplexAI {
-    choose ai_modes {
-        include behaviors::combat::melee
-        include behaviors::combat::ranged
-        include behaviors::exploration::search
-        include behaviors::social::greet
-    }
-}
-
-

Named Nodes

-

Both composite nodes (choose, then) can have optional labels:

-
behavior NamedNodeExample {
-    choose daily_priority {                  // Named selector
-        then handle_special_orders {         // Named sequence
-            CheckOrderQueue
-            PrepareSpecialIngredients
-            BakeSpecialItem
-        }
-
-        choose regular_work {               // Named selector
-            then morning_bread {             // Named sequence
-                MixSourdough
-                BakeLoaves
-            }
-        }
-    }
-}
-
-

Benefits:

-
    -
  • Readability: Tree structure is self-documenting
  • -
  • Debugging: Named nodes appear in execution traces
  • -
  • Narrative: Labels can be narrative (“handle_special_orders” vs. anonymous node)
  • -
-

Guidelines:

-
    -
  • Use labels for important structural nodes
  • -
  • Use descriptive, narrative names
  • -
  • Omit labels for trivial nodes
  • -
-

Complete Examples

-

Simple Guard AI

-
behavior GuardPatrol {
-    choose guard_logic {
-        // Combat if enemy nearby
-        then combat_mode {
-            if(enemy_nearby and has_weapon)
-            Attack
-        }
-
-        // Sound alarm if see intruder
-        then alarm_mode {
-            if(intruder_detected)
-            SoundAlarm
-        }
-
-        // Default: Patrol
-        then patrol_mode {
-            include PatrolRoute
-        }
-    }
-}
-
-

Complex NPC Behavior

-
behavior Innkeeper_DailyRoutine {
-    ---description
-    The innkeeper's behavior throughout the day. Uses selectors for
-    decision-making and sequences for multi-step actions.
-    ---
-
-    choose daily_activity {
-        // Morning: Prepare for opening
-        then morning_prep {
-            when(time_is_morning)
-            then prep_sequence {
-                UnlockDoor
-                LightFireplace
-                PrepareBreakfast
-                WaitForGuests
-            }
-        }
-
-        // Day: Serve customers
-        then day_service {
-            when(time_is_daytime)
-            choose service_mode {
-                // Serve customer if present
-                then serve {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                    ServeMeal
-                    CollectPayment
-                }
-
-                // Restock if needed
-                then restock {
-                    if(inventory_low)
-                    ReplenishInventory
-                }
-
-                // Default: Clean
-                CleanTables
-            }
-        }
-
-        // Night: Close up
-        then evening_close {
-            when(time_is_evening)
-            then close_sequence {
-                DismissRemainingGuests
-                LockDoor
-                CountMoney
-                GoToBed
-            }
-        }
-    }
-}
-
-

Morning Baking Routine

-
behavior Baker_MorningRoutine {
-    ---description
-    Martha's morning routine: prepare dough step by step,
-    from mixing to shaping to baking.
-    ---
-
-    then morning_baking {
-        // Start with sourdough
-        then prepare_starter {
-            CheckStarter
-            FeedStarter
-            WaitForActivity
-        }
-
-        // Mix the dough
-        then mix_dough {
-            MeasureFlour
-            AddWater
-            IncorporateStarter
-        }
-
-        // Knead and shape
-        then shape_loaves {
-            KneadDough
-            FirstRise
-            ShapeLoaves
-        }
-
-        // Bake
-        then bake {
-            PreHeatOven
-            LoadLoaves
-            MonitorBaking
-        }
-    }
-}
-
-

Repeating Behavior

-
behavior Bakery_CustomerServiceLoop {
-    ---description
-    The bakery's continuous customer service loop. Uses infinite
-    repeat decorator to serve customers throughout the day.
-    ---
-
-    repeat {
-        then service_cycle {
-            // Check for customers
-            choose service_mode {
-                then serve_waiting {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                }
-
-                then restock_display {
-                    if(display_low)
-                    FetchFromKitchen
-                    ArrangeOnShelves
-                }
-            }
-
-            // Process payment
-            CollectPayment
-            ThankCustomer
-
-            // Brief pause between customers
-            timeout(5s) {
-                CleanCounter
-            }
-
-            PrepareForNextCustomer
-        }
-    }
-}
-
-

Retry Logic for Delicate Recipes

-
behavior Baker_DelicatePastry {
-    ---description
-    Elena attempting a delicate pastry recipe that requires
-    precise technique. Uses retry decorator for persistence.
-    ---
-
-    choose baking_strategy {
-        // Try when conditions are right
-        then attempt_pastry {
-            if(oven_at_temperature)
-            // Try up to 3 times
-            retry(3) {
-                then make_pastry {
-                    RollDoughThin
-                    ApplyFilling
-                    FoldAndSeal
-                    CheckForLeaks
-                }
-            }
-        }
-
-        // If oven not ready, prepare meanwhile
-        then prepare_meanwhile {
-            if(not oven_at_temperature)
-            then prep_sequence {
-                PrepareIngredients
-                MixFilling
-                ChillDough
-            }
-        }
-    }
-}
-
-

Integration with Characters

-

Characters link to behaviors using the uses behaviors clause:

-
character Guard {
-    uses behaviors: [
-        {
-            tree: guards::patrol_route
-            priority: normal
-        },
-        {
-            tree: guards::engage_hostile
-            when: threat_detected
-            priority: high
-        },
-        {
-            tree: guards::sound_alarm
-            when: emergency
-            priority: critical
-        }
-    ]
-}
-
-

Behavior selection:

-
    -
  • Multiple behaviors evaluated by priority (critical > high > normal > low)
  • -
  • Conditions (when clause) gate behavior activation
  • -
  • Higher-priority behaviors preempt lower-priority ones
  • -
-

See Characters for complete behavior linking syntax.

-

Execution Semantics

-

Tick-Based Evaluation

-

Behavior trees execute every “tick” (typically once per frame):

-
    -
  1. Start at root node
  2. -
  3. Traverse down to leaves based on composite logic
  4. -
  5. Execute leaf nodes (conditions, actions)
  6. -
  7. Return success/failure up the tree
  8. -
  9. Repeat next tick
  10. -
-

Node Return Values

-

Every node returns one of:

-
    -
  • Success: Node completed successfully
  • -
  • Failure: Node failed
  • -
  • Running: Node still executing (async action)
  • -
-

Stateful vs. Stateless

-
    -
  • Stateless nodes: Evaluate fresh every tick (conditions, simple actions)
  • -
  • Stateful nodes: Maintain state across ticks (decorators, long actions)
  • -
-

Example of stateful behavior:

-
behavior LongAction {
-    timeout(30s) {           // Stateful: tracks elapsed time
-        ComplexCalculation   // May take multiple ticks
-    }
-}
-
-

Validation Rules

-
    -
  1. At least one node: Behavior body must contain at least one node
  2. -
  3. Composite children: choose and then require at least one child
  4. -
  5. Decorator child: Decorators require exactly one child
  6. -
  7. Action exists: Action names must reference registered actions in runtime
  8. -
  9. Subtree exists: include must reference a defined behavior declaration
  10. -
  11. Expression validity: Condition expressions must be well-formed
  12. -
  13. Duration format: Decorator durations must be valid (e.g., 5s, 10m)
  14. -
  15. Unique labels: Node labels (if used) should be unique within their parent
  16. -
  17. Parameter types: Action parameters must match expected types
  18. -
-

Best Practices

-

1. Prefer Shallow Trees

-

Avoid:

-
choose {
-    then { then { then { then { Action } } } }  // Too deep!
-}
-
-

Prefer:

-
choose root {
-    include combat_tree
-    include exploration_tree
-    include social_tree
-}
-
-

2. Use Named Nodes for Clarity

-

Avoid:

-
choose {
-    then {
-        IsHungry
-        FindFood
-        Eat
-    }
-    Wander
-}
-
-

Prefer:

-
choose survival {
-    then eat_if_hungry {
-        IsHungry
-        FindFood
-        Eat
-    }
-    Wander
-}
-
-

3. Subtrees for Reusability

-

Avoid: Duplicating logic across behaviors

-

Prefer:

-
behavior Combat_Common {
-    then attack_sequence {
-        DrawWeapon
-        Approach
-        Strike
-    }
-}
-
-behavior Warrior {
-    include Combat_Common
-}
-
-behavior Guard {
-    include Combat_Common
-}
-
-

4. Decorators for Timing

-

Avoid: Manual timing in actions

-

Prefer:

-
timeout(10s) {
-    ComplexTask
-}
-
-cooldown(30s) {
-    SpecialAbility
-}
-
-

5. Guard for Preconditions

-

Avoid:

-
then problematic {
-    ExpensiveAction  // Always runs even if inappropriate
-}
-
-

Prefer:

-
if(can_afford_action) {
-    ExpensiveAction  // Only runs when condition passes
-}
-
-

Cross-References

- - -
    -
  • Reactive AI: Behavior trees continuously react to changing conditions
  • -
  • Hierarchical decision-making: Composite nodes create decision hierarchies
  • -
  • Modularity: Subtrees enable behavior reuse and composition
  • -
  • Narrative-driven design: Named nodes make behavior trees readable as stories
  • -
-

Decorators

-

Decorators are special nodes that wrap a single child and modify its execution behavior. They enable timing control, retry logic, conditional execution, and result inversion without modifying the child node itself.

-

What Are Decorators?

-

Decorators sit between a parent and child node, transforming the child’s behavior:

-
Parent
-  └─ Decorator
-       └─ Child
-
-

The decorator intercepts the child’s execution, potentially:

-
    -
  • Repeating it multiple times
  • -
  • Timing it out
  • -
  • Inverting its result
  • -
  • Guarding its execution
  • -
  • Forcing a specific result
  • -
-

Decorator Types

-

Storybook provides 10 decorator types:

-
- - - - - - - - - - -
DecoratorPurposeExample
repeatLoop infinitelyrepeat { Patrol }
repeat(N)Loop N timesrepeat(3) { Check }
repeat(min..max)Loop min to max timesrepeat(2..5) { Search }
invertFlip success/failureinvert { IsEnemy }
retry(N)Retry on failure (max N times)retry(5) { Open }
timeout(duration)Fail after durationtimeout(10s) { Solve }
cooldown(duration)Run at most once per durationcooldown(30s) { Fire }
if(condition)Only run if condition trueif(health > 50) { Attack }
succeed_alwaysAlways return successsucceed_always { Try }
fail_alwaysAlways return failurefail_always { Test }
-
-

Syntax

-
<decorator> ::= <repeat-decorator>
-              | <invert-decorator>
-              | <retry-decorator>
-              | <timeout-decorator>
-              | <cooldown-decorator>
-              | <if-decorator>
-              | <force-result-decorator>
-
-<repeat-decorator> ::= "repeat" <repeat-spec>? "{" <behavior-node> "}"
-
-<repeat-spec> ::= "(" <number> ")"
-                | "(" <number> ".." <number> ")"
-
-<invert-decorator> ::= "invert" "{" <behavior-node> "}"
-
-<retry-decorator> ::= "retry" "(" <number> ")" "{" <behavior-node> "}"
-
-<timeout-decorator> ::= "timeout" "(" <duration-literal> ")" "{" <behavior-node> "}"
-
-<cooldown-decorator> ::= "cooldown" "(" <duration-literal> ")" "{" <behavior-node> "}"
-
-<if-decorator> ::= "if" "(" <expression> ")" "{" <behavior-node> "}"
-
-<force-result-decorator> ::= ("succeed_always" | "fail_always") "{" <behavior-node> "}"
-
-<duration-literal> ::= <number> ("s" | "m" | "h" | "d")
-
-

Repeat Decorators

-

Infinite Repeat: repeat

-

Loops the child infinitely. The child is re-executed immediately after completing (success or failure).

-
behavior InfinitePatrol {
-    repeat {
-        PatrolRoute
-    }
-}
-
-

Execution:

-
    -
  1. Run child
  2. -
  3. Child completes (success or failure)
  4. -
  5. Immediately run child again
  6. -
  7. Go to step 2 (forever)
  8. -
-

Use cases:

-
    -
  • Perpetual patrols
  • -
  • Endless background processes
  • -
  • Continuous monitoring
  • -
-

Warning: Infinite loops never return to parent. Ensure they’re appropriate for your use case.

-

Repeat N Times: repeat N

-

Repeats the child exactly N times, then returns success.

-
behavior CheckThreeTimes {
-    repeat(3) {
-        CheckDoor
-    }
-}
-
-

Execution:

-
    -
  1. Counter = 0
  2. -
  3. Run child
  4. -
  5. Counter++
  6. -
  7. If counter < N, go to step 2
  8. -
  9. Return success
  10. -
-

Use cases:

-
    -
  • Fixed iteration counts
  • -
  • “Try three times then give up”
  • -
  • Deterministic looping
  • -
-

Repeat Range: repeat min..max

-

Repeats the child between min and max times. At runtime, a specific count is selected within the range.

-
behavior SearchRandomly {
-    repeat(2..5) {
-        SearchArea
-    }
-}
-
-

Execution:

-
    -
  1. Select count C randomly from [min, max]
  2. -
  3. Repeat child C times (as in repeat N)
  4. -
-

Use cases:

-
    -
  • Variable behavior
  • -
  • Procedural variation
  • -
  • Non-deterministic actions
  • -
-

Validation:

-
    -
  • min ≥ 0
  • -
  • max ≥ min
  • -
  • Both must be integers
  • -
-

Invert Decorator

-

Inverts the child’s return value: success becomes failure, failure becomes success.

-
behavior AvoidEnemies {
-    invert {
-        IsEnemyNearby  // Success if NOT nearby
-    }
-}
-
-

Truth table:

-
- - - -
Child returnsDecorator returns
SuccessFailure
FailureSuccess
RunningRunning (unchanged)
-
-

Use cases:

-
    -
  • Negating conditions (“if NOT X”)
  • -
  • Inverting success criteria
  • -
  • Converting “found” to “not found”
  • -
-

Example:

-
behavior SafeExploration {
-    choose safe_actions {
-        // Only explore if NOT dangerous
-        then explore {
-            invert { IsDangerous }
-            ExploreArea
-        }
-
-        // Default: Stay put
-        Wait
-    }
-}
-
-

Retry Decorator

-

Retries the child up to N times on failure. Returns success if any attempt succeeds, failure if all N attempts fail.

-
behavior PersistentDoor {
-    retry(5) {
-        OpenLockedDoor
-    }
-}
-
-

Execution:

-
    -
  1. Attempts = 0
  2. -
  3. Run child
  4. -
  5. If child succeeds → return success
  6. -
  7. If child fails: -
      -
    • Attempts++
    • -
    • If attempts < N, go to step 2
    • -
    • Else return failure
    • -
    -
  8. -
-

Use cases:

-
    -
  • Unreliable actions (lockpicking, persuasion)
  • -
  • Network/resource operations
  • -
  • Probabilistic success
  • -
-

Example with context:

-
behavior Thief_PickLock {
-    then attempt_entry {
-        // Try to pick lock (may fail)
-        retry(3) {
-            PickLock
-        }
-
-        // If succeeded, enter
-        EnterBuilding
-
-        // If failed after 3 tries, give up
-    }
-}
-
-

Validation:

-
    -
  • N must be ≥ 1
  • -
-

Timeout Decorator

-

Fails the child if it doesn’t complete within the specified duration.

-
behavior TimeLimitedPuzzle {
-    timeout(30s) {
-        SolvePuzzle
-    }
-}
-
-

Execution:

-
    -
  1. Start timer
  2. -
  3. Run child each tick
  4. -
  5. If child completes before timeout → return child’s result
  6. -
  7. If timer expires → return failure (interrupt child)
  8. -
-

Use cases:

-
    -
  • Time-limited actions
  • -
  • Preventing infinite loops
  • -
  • Enforcing deadlines
  • -
-

Duration formats:

-
    -
  • 5s - 5 seconds
  • -
  • 10m - 10 minutes
  • -
  • 2h - 2 hours
  • -
  • 3d - 3 days
  • -
-

Example:

-
behavior QuickDecision {
-    choose timed_choice {
-        // Give AI 5 seconds to find optimal move
-        timeout(5s) {
-            CalculateOptimalStrategy
-        }
-
-        // Fallback: Use simple heuristic
-        UseQuickHeuristic
-    }
-}
-
-

Notes:

-
    -
  • Timer starts when decorator is first entered
  • -
  • Timer resets if decorator exits and re-enters
  • -
  • Child node should handle interruption gracefully
  • -
-

Cooldown Decorator

-

Prevents the child from running more than once per cooldown period. Fails immediately if called within cooldown.

-
behavior SpecialAbility {
-    cooldown(30s) {
-        FireCannon
-    }
-}
-
-

Execution:

-
    -
  1. Check last execution time
  2. -
  3. If (current_time - last_time) < cooldown → return failure
  4. -
  5. Else: -
      -
    • Run child
    • -
    • Record current_time as last_time
    • -
    • Return child’s result
    • -
    -
  6. -
-

Use cases:

-
    -
  • Rate-limiting abilities
  • -
  • Resource cooldowns (spells, items)
  • -
  • Preventing spam
  • -
-

Example:

-
behavior Mage_SpellCasting {
-    choose spells {
-        // Fireball: 10 second cooldown
-        cooldown(10s) {
-            CastFireball
-        }
-
-        // Lightning: 5 second cooldown
-        cooldown(5s) {
-            CastLightning
-        }
-
-        // Basic attack: No cooldown
-        MeleeAttack
-    }
-}
-
-

State management:

-
    -
  • Cooldown state persists across behavior tree ticks
  • -
  • Each cooldown decorator instance has independent state
  • -
  • Cooldown timers are per-entity (not global)
  • -
-

If Decorator

-

Only runs the child if the condition is true. Fails immediately if condition is false.

-
behavior ConditionalAttack {
-    if(health > 50) {
-        AggressiveAttack
-    }
-}
-
-

Execution:

-
    -
  1. Evaluate condition expression
  2. -
  3. If true → run child and return its result
  4. -
  5. If false → return failure (do not run child)
  6. -
-

Use cases:

-
    -
  • Preconditions (“only if X”)
  • -
  • Resource checks (“only if have mana”)
  • -
  • Safety checks (“only if safe”)
  • -
-

Expression syntax: -See Expression Language for complete syntax.

-

Examples:

-
behavior GuardedActions {
-    choose options {
-        // Only attack if have weapon and enemy close
-        if(has_weapon and distance < 10) {
-            Attack
-        }
-
-        // Only heal if health below 50%
-        if(health < (max_health * 0.5)) {
-            Heal
-        }
-
-        // Only flee if outnumbered
-        if(enemy_count > ally_count) {
-            Flee
-        }
-    }
-}
-
-

Comparison with bare if conditions:

-
// Using bare 'if' condition (checks every tick, no body)
-then approach_and_attack {
-    if(enemy_nearby)
-    Approach
-    Attack
-}
-
-// Using 'if' decorator with body (precondition check, fails fast)
-if(enemy_nearby) {
-    then do_attack {
-        Approach
-        Attack
-    }
-}
-
-

The if decorator with a body is more efficient for gating expensive subtrees.

-

Force Result Decorators

-

succeed_always

-

Always returns success, regardless of child’s actual result.

-
behavior TryOptionalTask {
-    succeed_always {
-        AttemptBonus  // Even if fails, we don't care
-    }
-}
-
-

Use cases:

-
    -
  • Optional tasks that shouldn’t block progress
  • -
  • Logging/monitoring actions
  • -
  • Best-effort operations
  • -
-

Example:

-
behavior QuestSequence {
-    then main_quest {
-        TalkToNPC
-
-        // Try to find secret, but don't fail quest if not found
-        succeed_always {
-            SearchForSecretDoor
-        }
-
-        ReturnToQuestGiver
-    }
-}
-
-

fail_always

-

Always returns failure, regardless of child’s actual result.

-
behavior TestFailure {
-    fail_always {
-        AlwaysSucceedsAction  // But we force it to fail
-    }
-}
-
-

Use cases:

-
    -
  • Testing/debugging
  • -
  • Forcing alternative paths
  • -
  • Disabling branches temporarily
  • -
-

Example:

-
behavior UnderConstruction {
-    choose abilities {
-        // Temporarily disabled feature
-        fail_always {
-            NewExperimentalAbility
-        }
-
-        // Fallback to old ability
-        ClassicAbility
-    }
-}
-
-

Combining Decorators

-

Decorators can nest to create complex behaviors:

-
behavior ComplexPattern {
-    // Repeat 3 times, each with 10 second timeout
-    repeat(3) {
-        timeout(10s) {
-            SolveSubproblem
-        }
-    }
-}
-
-

More complex nesting:

-
behavior ResilientAction {
-    // If: Only if health > 30
-    if(health > 30) {
-        // Timeout: Must complete in 20 seconds
-        timeout(20s) {
-            // Retry: Try up to 5 times
-            retry(5) {
-                // Cooldown: Can only run once per minute
-                cooldown(1m) {
-                    PerformComplexAction
-                }
-            }
-        }
-    }
-}
-
-

Execution order: Outside → Inside

-
    -
  1. If checks condition
  2. -
  3. Timeout starts timer
  4. -
  5. Retry begins first attempt
  6. -
  7. Cooldown checks last execution time
  8. -
  9. Child action runs
  10. -
-

Duration Syntax

-

Timeout and cooldown decorators use duration literals:

-
<duration-literal> ::= <number> <unit>
-
-<unit> ::= "s"    // seconds
-         | "m"    // minutes
-         | "h"    // hours
-         | "d"    // days
-
-<number> ::= <digit>+
-
-

Examples:

-
    -
  • 5s - 5 seconds
  • -
  • 30s - 30 seconds
  • -
  • 2m - 2 minutes
  • -
  • 10m - 10 minutes
  • -
  • 1h - 1 hour
  • -
  • 24h - 24 hours
  • -
  • 7d - 7 days
  • -
-

Validation:

-
    -
  • Number must be positive integer
  • -
  • No compound durations (use 120s not 2m if runtime expects seconds)
  • -
  • No fractional units (1.5m not allowed; use 90s)
  • -
-

Comparison Table

-
- - - - - - - - - - -
DecoratorAffects SuccessAffects FailureAffects RunningStateful
repeatRepeatRepeatWaitYes (counter)
repeat NRepeatRepeatWaitYes (counter)
repeat min..maxRepeatRepeatWaitYes (counter)
invert→ Failure→ SuccessUnchangedNo
retry N→ SuccessRetry or failWaitYes (attempts)
timeout dur→ Success→ Success→ Failure if expiredYes (timer)
cooldown dur→ Success→ Success→ SuccessYes (last time)
if(expr)→ Success→ Success→ SuccessNo
succeed_always→ Success→ Success→ SuccessNo
fail_always→ Failure→ Failure→ FailureNo
-
-

Stateful decorators maintain state across ticks. Stateless decorators evaluate fresh every tick.

-

Validation Rules

-
    -
  1. Child required: All decorators must have exactly one child node
  2. -
  3. Repeat count: repeat N requires N ≥ 0
  4. -
  5. Repeat range: repeat min..max requires 0 ≤ min ≤ max
  6. -
  7. Retry count: retry N requires N ≥ 1
  8. -
  9. Duration positive: Timeout/cooldown durations must be > 0
  10. -
  11. Duration format: Must match <number><unit> (e.g., 10s, 5m)
  12. -
  13. Guard expression: Guard condition must be valid expression
  14. -
  15. No empty decorators: repeat { } is invalid (missing child)
  16. -
-

Use Cases by Category

-

Timing Control

-
    -
  • timeout: Prevent infinite loops, enforce time limits
  • -
  • cooldown: Rate-limit abilities, prevent spam
  • -
  • repeat: Continuous processes, patrols
  • -
-

Reliability

-
    -
  • retry: Handle unreliable actions, probabilistic success
  • -
  • if: Precondition checks, resource validation
  • -
  • succeed_always: Optional tasks, best-effort
  • -
-

Logic Control

-
    -
  • invert: Negate conditions, flip results
  • -
  • fail_always: Disable branches, testing
  • -
-

Iteration

-
    -
  • repeat N: Fixed loops, deterministic behavior
  • -
  • repeat min..max: Variable loops, procedural variation
  • -
-

Best Practices

-

1. Use Guards for Expensive Checks

-

Avoid:

-
then expensive {
-    if(complex_condition)
-    ExpensiveOperation
-}
-
-

Prefer:

-
if(complex_condition) {
-    ExpensiveOperation  // Only runs if condition passes
-}
-
-

2. Combine Timeout with Retry

-

Avoid: Infinite retry loops

-

Prefer:

-
timeout(30s) {
-    retry(5) {
-        UnreliableAction
-    }
-}
-
-

3. Use Cooldowns for Rate Limiting

-

Avoid: Manual timing in actions

-

Prefer:

-
cooldown(10s) {
-    FireCannon
-}
-
-

4. Invert for Readable Conditions

-

Avoid:

-
choose options {
-    then branch_a {
-        if(not is_dangerous)
-        Explore
-    }
-}
-
-

Prefer:

-
choose options {
-    then branch_a {
-        invert { IsDangerous }
-        Explore
-    }
-}
-
-

5. succeed_always for Optional Tasks

-

Avoid:

-
then quest {
-    MainTask
-    choose optional {
-        BonusTask
-        DoNothing  // Awkward fallback
-    }
-    NextTask
-}
-
-

Prefer:

-
then quest {
-    MainTask
-    succeed_always { BonusTask }  // Try bonus, don't fail quest
-    NextTask
-}
-
-

Cross-References

- - -
    -
  • Composability: Decorators can nest for complex control flow
  • -
  • Separation of concerns: Decorators handle control flow, children handle logic
  • -
  • State management: Stateful decorators (repeat, retry, timeout, cooldown) persist across ticks
  • -
  • Performance: Guards prevent unnecessary child execution
  • -
-

Life Arcs

-

Life arcs are state machines that model how characters or other entities evolve over time. They define discrete states and the conditions under which an entity transitions between states. Life arcs capture character development, quest progress, relationship phases, and any other finite-state processes.

-

What is a Life Arc?

-

A life arc is a finite state machine (FSM) composed of:

-
    -
  • States: Discrete phases or modes (e.g., “happy”, “angry”, “sleeping”)
  • -
  • Transitions: Conditional edges between states (e.g., “when health < 20, go to ‘fleeing’”)
  • -
  • On-enter actions: Field updates that occur when entering a state
  • -
-
[State A] --condition--> [State B] --condition--> [State C]
-    |                         |                       |
- on enter                  on enter                on enter
- (set fields)              (set fields)            (set fields)
-
-

Life arcs run continuously, evaluating transitions every tick and moving between states as conditions become true.

-

Syntax

-
<life-arc-decl> ::= "life_arc" <identifier> <body>
-
-<body> ::= "{" <prose-blocks>* <state>+ "}"
-
-<state> ::= "state" <identifier> "{" <state-body>* "}"
-
-<state-body> ::= <on-enter-block>
-               | <transition>
-               | <prose-block>
-
-<on-enter-block> ::= "on" "enter" "{" <field>+ "}"
-
-<transition> ::= "on" <expression> "->" <identifier>
-
-<prose-block> ::= "---" <identifier> <content> "---"
-
-

States

-

A state represents a discrete phase in an entity’s lifecycle.

-

Basic State

-
life_arc SimpleArc {
-    state idle {
-        ---narrative
-        The character is doing nothing, waiting for something to happen.
-        ---
-    }
-
-    state active {
-        ---narrative
-        The character is engaged in their primary activity.
-        ---
-    }
-}
-
-

State Names

-

State names are identifiers that must be unique within the life arc. Use descriptive names:

-
    -
  • Good: idle, combat, sleeping, enlightened
  • -
  • Avoid: state1, s, temp
  • -
-

On-Enter Actions

-

When entering a state, the on enter block updates entity fields.

-

Syntax

-
state state_name {
-    on enter {
-        EntityName.field_name: value
-        EntityName.other_field: other_value
-    }
-}
-
-

Examples

-
life_arc CharacterMood {
-    state happy {
-        on enter {
-            Martha.emotional_state: "happy"
-            Martha.energy: 100
-        }
-    }
-
-    state tired {
-        on enter {
-            Martha.emotional_state: "exhausted"
-            Martha.energy: 20
-        }
-    }
-}
-
-

Field Update Semantics

-
    -
  • Target: EntityName.field_name must reference an existing character/entity
  • -
  • Value: Any valid value type
  • -
  • Effect: Field is set to the specified value when state is entered
  • -
  • Timing: Happens immediately upon transition to the state
  • -
-

Multiple Field Updates

-
state exhausted_baker {
-    on enter {
-        Martha.energy: 0.1
-        Martha.mood: "stressed"
-        Martha.quality_output: 0.7
-        Martha.needs_break: true
-    }
-
-    ---narrative
-    After a sixteen-hour shift during the harvest festival,
-    Martha's hands are shaking. She knows her bread quality is
-    suffering and reluctantly steps away from the oven.
-    ---
-}
-
-

Transitions

-

Transitions define conditional edges between states. When a transition’s condition becomes true, the state machine moves to the target state.

-

Syntax

-
state source_state {
-    on condition_expression -> target_state
-    on another_condition -> another_target
-}
-
-

Basic Transitions

-
life_arc Combat {
-    state fighting {
-        on health < 20 -> fleeing
-        on enemy_defeated -> victorious
-    }
-
-    state fleeing {
-        on safe_distance_reached -> idle
-    }
-
-    state victorious {
-        on celebration_complete -> idle
-    }
-
-    state idle {}
-}
-
-

Expression Conditions

-

Transitions use the full expression language:

-

Comparisons:

-
on health < 20 -> low_health
-on distance > 100 -> far_away
-on count == 0 -> empty
-
-

Boolean fields:

-
on is_hostile -> combat
-on completed -> done
-on not ready -> waiting
-
-

Logical operators:

-
on health < 20 and not has_potion -> desperate
-on is_day or is_lit -> visible
-
-

Complex conditions:

-
on (health < 50 and enemy_count > 3) or surrounded -> retreat
-on forall e in enemies: e.defeated -> victory
-
-

Multiple Transitions

-

A state can have multiple outgoing transitions:

-
state monitoring {
-    on status is "active" -> active_state
-    on status is "inactive" -> inactive_state
-    on status is "error" -> error_state
-    on shutdown_requested -> shutting_down
-}
-
-

Evaluation order:

-
    -
  • Transitions are evaluated in declaration order (top to bottom)
  • -
  • First transition with a true condition is taken
  • -
  • If no conditions are true, state remains unchanged
  • -
-

Self-Transitions

-

A state can transition to itself:

-
state patrolling {
-    on enemy_spotted -> combat
-    on checkpoint_reached -> patrolling  // Reset patrol state
-}
-
-

Complete Examples

-

Elena’s Career Journey

-
life_arc ElenaCareer {
-    ---description
-    Tracks Elena's progression from nervous apprentice to confident
-    master baker. Each state represents a key phase of her career.
-    ---
-
-    state early_apprentice {
-        on enter {
-            Elena.skill_level: novice
-            Elena.confidence: timid
-        }
-
-        on recipes_mastered > 5 -> growing_apprentice
-
-        ---narrative
-        Elena's hands shake as she measures flour. She checks the
-        recipe three times before adding each ingredient. Martha
-        patiently corrects her technique.
-        ---
-    }
-
-    state growing_apprentice {
-        on enter {
-            Elena.skill_level: beginner
-            Elena.confidence: uncertain
-        }
-
-        on recipes_mastered > 15 -> journeyman
-
-        ---narrative
-        The shaking stops. Elena can make basic breads without
-        looking at the recipe. She still doubts herself but
-        Martha's encouragement is taking root.
-        ---
-    }
-
-    state journeyman {
-        on enter {
-            Elena.skill_level: intermediate
-            Elena.confidence: growing
-            Elena.can_work_independently: true
-        }
-
-        on recipes_mastered > 30 -> senior_journeyman
-
-        ---narrative
-        Elena runs the morning shift alone while Martha handles
-        special orders. Customers start asking for "Elena's rolls."
-        She begins experimenting with her own recipes.
-        ---
-    }
-
-    state senior_journeyman {
-        on enter {
-            Elena.skill_level: advanced
-            Elena.confidence: steady
-        }
-
-        on recipes_mastered > 50 -> master
-
-        ---narrative
-        Elena develops her signature recipe: rosemary olive bread
-        that becomes the bakery's bestseller. She handles difficult
-        customers with grace and trains new helpers.
-        ---
-    }
-
-    state master {
-        on enter {
-            Elena.skill_level: master
-            Elena.confidence: commanding
-            Elena.can_teach: true
-        }
-
-        ---narrative
-        Master Baker Elena. She has earned it. The guild acknowledges
-        her mastery, and Martha beams with pride. Elena begins
-        mentoring her own apprentice.
-        ---
-    }
-}
-
-

Quest Progress

-
life_arc HeroQuest {
-    state not_started {
-        on talked_to_elder -> received_quest
-    }
-
-    state received_quest {
-        on enter {
-            Hero.quest_active: true
-            Hero.quest_step: 0
-        }
-
-        on found_first_artifact -> collecting
-    }
-
-    state collecting {
-        on enter {
-            Hero.quest_step: 1
-        }
-
-        on artifact_count == 3 -> returning
-        on failed_trial -> failed
-    }
-
-    state returning {
-        on enter {
-            Hero.quest_step: 2
-        }
-
-        on reached_elder -> completed
-    }
-
-    state completed {
-        on enter {
-            Hero.quest_active: false
-            Hero.quest_completed: true
-            Hero.reputation: 100
-        }
-
-        ---narrative
-        The hero returns triumphant, artifacts in hand. The elder
-        bestows great rewards and the village celebrates.
-        ---
-    }
-
-    state failed {
-        on enter {
-            Hero.quest_active: false
-            Hero.quest_failed: true
-        }
-
-        on retry_accepted -> received_quest
-    }
-}
-
-

Name Checker (Equality Examples)

-
life_arc NameCheck {
-    state checking {
-        on name is "Martha" -> found_martha
-        on name is "Jane" -> found_jane
-    }
-
-    state found_martha {
-        on ready -> checking
-    }
-
-    state found_jane {
-        on ready -> checking
-    }
-}
-
-

Status Monitor

-
life_arc StatusMonitor {
-    state monitoring {
-        on status is active -> active_state
-        on status is inactive -> inactive_state
-        on status is error -> error_state
-    }
-
-    state active_state {
-        on enter {
-            System.led_color: "green"
-        }
-
-        on status is inactive -> inactive_state
-        on status is error -> error_state
-    }
-
-    state inactive_state {
-        on enter {
-            System.led_color: "yellow"
-        }
-
-        on status is active -> active_state
-        on status is error -> error_state
-    }
-
-    state error_state {
-        on enter {
-            System.led_color: "red"
-            System.alarm: true
-        }
-
-        on error_cleared -> monitoring
-    }
-}
-
-

Character Mood Swings

-
life_arc MoodSwings {
-    state neutral {
-        on provoked -> angry
-        on complimented -> happy
-        on tired -> sleepy
-    }
-
-    state angry {
-        on enter {
-            Character.aggression: 0.9
-            Character.willingness_to_talk: 0.1
-        }
-
-        on calmed_down -> neutral
-        on escalated -> furious
-    }
-
-    state furious {
-        on enter {
-            Character.aggression: 1.0
-            Character.will_attack: true
-        }
-
-        on timeout_elapsed -> angry
-        on apologized_to -> neutral
-    }
-
-    state happy {
-        on enter {
-            Character.aggression: 0.0
-            Character.willingness_to_talk: 1.0
-            Character.gives_discounts: true
-        }
-
-        on insulted -> neutral
-        on bored -> neutral
-    }
-
-    state sleepy {
-        on enter {
-            Character.responsiveness: 0.2
-        }
-
-        on woke_up -> neutral
-        on fell_asleep -> sleeping
-    }
-
-    state sleeping {
-        on enter {
-            Character.responsiveness: 0.0
-            Character.is_vulnerable: true
-        }
-
-        on woke_up -> neutral
-    }
-}
-
-

Execution Semantics

-

Tick-Based Evaluation

-

Life arcs evaluate transitions every “tick” (typically once per frame):

-
    -
  1. Current state: Start in the current state
  2. -
  3. Evaluate transitions: Check each outgoing transition’s condition (in order)
  4. -
  5. First true transition: Take the first transition with a true condition
  6. -
  7. Enter new state: Execute the new state’s on enter block
  8. -
  9. Repeat next tick
  10. -
-

Transition Priority

-

When multiple transitions could fire, the first one in declaration order is taken:

-
state combat {
-    on health < 10 -> desperate       // Checked first
-    on health < 50 -> defensive       // Checked second
-    on surrounded -> retreat          // Checked third
-}
-
-

If health is 5, only desperate transition fires (even though defensive condition is also true).

-

State Persistence

-

The current state persists across ticks until a transition fires.

-
state waiting {
-    on signal_received -> active
-}
-
-

The entity remains in waiting state indefinitely until signal_received becomes true.

-

On-Enter Execution

-

on enter blocks execute once when entering the state, not every tick:

-
state combat {
-    on enter {
-        Character.weapon_drawn: true  // Runs once when entering combat
-    }
-}
-
-

Validation Rules

-
    -
  1. At least one state: Life arc must contain at least one state
  2. -
  3. Unique state names: State names must be unique within the life arc
  4. -
  5. Valid transitions: Transition targets must reference defined states
  6. -
  7. No orphan states: All states should be reachable (warning, not error)
  8. -
  9. Expression validity: Transition conditions must be well-formed expressions
  10. -
  11. Field targets: On-enter field updates must reference valid entities/fields
  12. -
  13. No cyclic immediate transitions: Avoid transitions that fire immediately in a loop
  14. -
-

Design Patterns

-

1. Hub-and-Spoke

-

A central “hub” state with transitions to specialized states:

-
life_arc HubPattern {
-    state idle {
-        on combat_triggered -> combat
-        on quest_accepted -> questing
-        on entered_shop -> shopping
-    }
-
-    state combat {
-        on combat_ended -> idle
-    }
-
-    state questing {
-        on quest_completed -> idle
-    }
-
-    state shopping {
-        on left_shop -> idle
-    }
-}
-
-

2. Linear Progression

-

States form a linear sequence (quests, tutorials):

-
life_arc Tutorial {
-    state intro {
-        on clicked_start -> movement
-    }
-
-    state movement {
-        on moved_forward -> combat
-    }
-
-    state combat {
-        on defeated_enemy -> inventory
-    }
-
-    state inventory {
-        on opened_inventory -> complete
-    }
-
-    state complete {}
-}
-
-

3. Cyclic States

-

States form a cycle (day/night, seasons):

-
life_arc DayNightCycle {
-    state dawn {
-        on hour >= 8 -> day
-    }
-
-    state day {
-        on hour >= 18 -> dusk
-    }
-
-    state dusk {
-        on hour >= 20 -> night
-    }
-
-    state night {
-        on hour >= 6 -> dawn
-    }
-}
-
-

4. Hierarchical (Simulated)

-

Use multiple life arcs for hierarchical state:

-
// Top-level life arc
-life_arc CharacterState {
-    state alive {
-        on health <= 0 -> dead
-    }
-
-    state dead {}
-}
-
-// Nested life arc (only active when alive)
-life_arc CombatState {
-    state idle {
-        on enemy_nearby -> combat
-    }
-
-    state combat {
-        on enemy_defeated -> idle
-    }
-}
-
-

Best Practices

-

1. Use Descriptive State Names

-

Avoid:

-
state s1 { ... }
-state s2 { ... }
-
-

Prefer:

-
state waiting_for_player { ... }
-state engaged_in_combat { ... }
-
-

2. Add Narrative Prose Blocks

-
state master_baker {
-    ---narrative
-    Master Baker Elena. She has earned it. The guild acknowledges
-    her mastery, and Martha beams with pride. Elena begins
-    mentoring her own apprentice.
-    ---
-}
-
-

3. Order Transitions by Priority

-
state health_check {
-    on health <= 0 -> dead          // Most urgent
-    on health < 20 -> critical      // Very urgent
-    on health < 50 -> wounded       // Moderate
-}
-
-

4. Avoid Orphan States

-

Ensure all states are reachable from the initial state.

-

Avoid:

-
life_arc Broken {
-    state start {
-        on ready -> middle
-    }
-
-    state middle {
-        on done -> end
-    }
-
-    state unreachable {}  // No transition leads here!
-
-    state end {}
-}
-
-

5. Use On-Enter for State Initialization

-
state combat {
-    on enter {
-        Character.weapon_drawn: true
-        Character.combat_stance: "aggressive"
-        Character.target: nearest_enemy
-    }
-}
-
-

Cross-References

- - -
    -
  • Finite State Machines (FSM): Life arcs are FSMs
  • -
  • Character development: Track character growth over time
  • -
  • Quest states: Model quest progression
  • -
  • Mood systems: Model emotional states
  • -
  • Lifecycle modeling: Birth, growth, aging, death
  • -
-

Schedules

-

Schedules define time-based routines for characters and institutions. They specify what activities occur during specific time ranges, support seasonal variations, recurring events, and template composition. Schedules enable rich temporal behavior from simple daily routines to complex year-long patterns.

-

What is a Schedule?

-

A schedule is a collection of time blocks that define activities throughout a day, week, season, or year:

-
    -
  • Blocks: Time ranges (e.g., 06:00 - 14:00) with associated activities/behaviors
  • -
  • Temporal constraints: When blocks apply (season, day of week, month)
  • -
  • Recurrence patterns: Repeating events (e.g., “Market Day every Earthday”)
  • -
  • Composition: Schedules can extend and override other schedules
  • -
-
Schedule: BakerySchedule
-├─ Block: 06:00 - 08:00 → prepare_dough
-├─ Block: 08:00 - 14:00 → serve_customers
-├─ Recurrence: Market Day (on Earthday) → special_market_hours
-└─ Extends: BaseBusiness (inherits closing hours)
-
-

Syntax

-
<schedule-decl> ::= "schedule" <identifier> <extends-clause>? <body>
-
-<extends-clause> ::= "extends" <identifier>
-
-<body> ::= "{" <schedule-item>* "}"
-
-<schedule-item> ::= <schedule-block>
-                  | <recurrence-pattern>
-
-<schedule-block> ::= "block" <block-name>? "{" <block-content>+ "}"
-
-<block-name> ::= <identifier>
-
-<block-content> ::= <time-range>
-                  | "action" ":" <qualified-path>
-                  | <temporal-constraint>
-                  | <field>
-
-<time-range> ::= <time> "-" <time>
-
-<temporal-constraint> ::= "on" <temporal-spec>
-
-<temporal-spec> ::= "season" <identifier>
-                  | "day" <identifier>
-                  | "month" <identifier>
-                  | "dates" <string> ".." <string>
-
-<recurrence-pattern> ::= "recurs" <identifier> <temporal-constraint> "{" <schedule-block>+ "}"
-
-

Schedule Blocks

-

A schedule block defines an activity during a specific time range.

-

Basic Block

-
schedule SimpleBaker {
-    block {
-        06:00 - 14:00
-        action: baking::prepare_and_sell
-    }
-}
-
-

Named Block

-

Named blocks support the override system:

-
schedule BakeryBase {
-    block work {
-        09:00 - 17:00
-        action: baking::standard_work
-    }
-}
-
-schedule EarlyBaker extends BakeryBase {
-    block work {  // Override by name
-        05:00 - 13:00
-        action: baking::early_shift
-    }
-}
-
-

Block Content

-

Blocks can contain:

-
    -
  1. Time range (required): HH:MM - HH:MM
  2. -
  3. Action (optional): Behavior tree reference
  4. -
  5. Temporal constraint (optional): When the block applies
  6. -
  7. Fields (optional): Additional metadata
  8. -
-
schedule CompleteBlock {
-    block morning_work {
-        06:00 - 12:00
-        action: work::morning_routine
-        on season summer
-        location: "Outdoor Market"
-    }
-}
-
-

Time Ranges

-

Time ranges use 24-hour clock format.

-

Syntax

-
HH:MM - HH:MM
-
-
    -
  • HH: Hour (00-23)
  • -
  • MM: Minute (00-59)
  • -
  • Optional seconds: HH:MM:SS - HH:MM:SS
  • -
-

Examples

-
schedule Examples {
-    block early { 05:00 - 08:00, action: prep }
-    block midday { 12:00 - 13:00, action: lunch }
-    block late { 20:00 - 23:59, action: closing }
-}
-
-

Overnight Ranges

-

Blocks can span midnight:

-
schedule NightShift {
-    block night_work {
-        22:00 - 06:00  // 10 PM to 6 AM next day
-        action: security::patrol
-    }
-}
-
-

The system interprets this as 22:00-24:00 (day 1) + 00:00-06:00 (day 2).

-

Actions

-

The action field links a schedule block to a behavior tree.

-

Syntax

-
action: <qualified-path>
-
-

Examples

-
schedule BakerSchedule {
-    block morning {
-        05:00 - 08:00
-        action: baking::prepare_dough
-    }
-
-    block sales {
-        08:00 - 14:00
-        action: baking::serve_customers
-    }
-
-    block cleanup {
-        14:00 - 15:00
-        action: baking::close_shop
-    }
-}
-
-

Qualified Paths

-

Actions can reference behaviors from other modules:

-
schedule GuardSchedule {
-    block patrol {
-        08:00 - 16:00
-        action: behaviors::guards::patrol_route
-    }
-
-    block training {
-        16:00 - 18:00
-        action: combat::training::drills
-    }
-}
-
-

Temporal Constraints

-

Temporal constraints specify when a block applies (season, day of week, month, date range).

-

Season Constraint

-
schedule SeasonalHours {
-    block summer_hours {
-        06:00 - 20:00
-        action: work::long_day
-        on season summer
-    }
-
-    block winter_hours {
-        07:00 - 18:00
-        action: work::short_day
-        on season winter
-    }
-}
-
-

Season values are defined by enums in your storybook:

-
enum Season {
-    spring
-    summer
-    fall
-    winter
-}
-
-

Day of Week Constraint

-
schedule WeeklyPattern {
-    block weekday_work {
-        09:00 - 17:00
-        action: work::standard
-        on day monday  // Also: tuesday, wednesday, thursday, friday, saturday, sunday
-    }
-
-    block weekend_rest {
-        10:00 - 16:00
-        action: leisure::relax
-        on day saturday
-    }
-}
-
-

Day values are typically defined by a DayOfWeek enum:

-
enum DayOfWeek {
-    monday
-    tuesday
-    wednesday
-    thursday
-    friday
-    saturday
-    sunday
-}
-
-

Month Constraint

-
schedule AnnualPattern {
-    block harvest {
-        06:00 - 20:00
-        action: farming::harvest_crops
-        on month october
-    }
-
-    block spring_planting {
-        07:00 - 19:00
-        action: farming::plant_seeds
-        on month april
-    }
-}
-
-

Date Range Constraint

-
schedule TouristSeason {
-    block high_season {
-        08:00 - 22:00
-        action: tourism::busy_service
-        on dates "Jun 1" .. "Sep 1"
-    }
-}
-
-

Note: Date format is implementation-specific. Check your runtime for supported formats.

-

Recurrence Patterns

-

Recurrence patterns define recurring events that modify the schedule.

-

Syntax

-
recurs EventName on <temporal-constraint> {
-    <schedule-block>+
-}
-
-

Examples

-

Weekly Recurring Event

-
schedule MarketSchedule {
-    // Regular daily hours
-    block work {
-        08:00 - 17:00
-        action: shop::regular_sales
-    }
-
-    // Market day every saturday
-    recurs MarketDay on day saturday {
-        block setup {
-            06:00 - 08:00
-            action: market::setup_stall
-        }
-
-        block busy_market {
-            08:00 - 18:00
-            action: market::busy_sales
-        }
-
-        block teardown {
-            18:00 - 20:00
-            action: market::pack_up
-        }
-    }
-}
-
-

Monthly Recurring Event

-
schedule TownSchedule {
-    recurs CouncilMeeting on month first_monday {
-        block meeting {
-            18:00 - 21:00
-            action: governance::council_session
-        }
-    }
-}
-
-

Seasonal Recurring Event

-
schedule FarmSchedule {
-    recurs SpringPlanting on season spring {
-        block planting {
-            06:00 - 18:00
-            action: farming::plant_all_fields
-        }
-    }
-
-    recurs FallHarvest on season fall {
-        block harvest {
-            06:00 - 20:00
-            action: farming::harvest_all_crops
-        }
-    }
-}
-
-

Schedule Composition

-

Schedules can extend other schedules using extends, inheriting and overriding blocks.

-

Extends Clause

-
schedule Base {
-    block work {
-        09:00 - 17:00
-        action: work::standard
-    }
-}
-
-schedule Extended extends Base {
-    block work {  // Override inherited block
-        05:00 - 13:00
-        action: work::early_shift
-    }
-}
-
-

Override Semantics

-

When extending a schedule:

-
    -
  1. Named blocks with matching names override base blocks
  2. -
  3. Unnamed blocks are appended
  4. -
  5. Time range can change
  6. -
  7. Action can change
  8. -
  9. Constraints can be added/changed
  10. -
-

Multiple Levels

-
schedule BaseWork {
-    block work {
-        09:00 - 17:00
-        action: work::standard
-    }
-}
-
-schedule BakerWork extends BaseWork {
-    block work {
-        05:00 - 13:00  // Earlier hours
-        action: baking::work
-    }
-}
-
-schedule MasterBaker extends BakerWork {
-    block work {
-        03:00 - 11:00  // Even earlier!
-        action: baking::master_work
-    }
-
-    block teaching {
-        14:00 - 16:00
-        action: baking::teach_apprentice
-    }
-}
-
-

Resolution:

-
    -
  • work block: 03:00-11:00 with baking::master_work (MasterBaker overrides BakerWork overrides BaseWork)
  • -
  • teaching block: 14:00-16:00 with baking::teach_apprentice (from MasterBaker)
  • -
-

Complete Examples

-

Simple Daily Schedule

-
schedule SimpleFarmer {
-    block sleep {
-        22:00 - 05:00
-        action: rest::sleep
-    }
-
-    block morning_chores {
-        05:00 - 08:00
-        action: farming::feed_animals
-    }
-
-    block fieldwork {
-        08:00 - 17:00
-        action: farming::tend_crops
-    }
-
-    block evening_chores {
-        17:00 - 19:00
-        action: farming::evening_tasks
-    }
-
-    block leisure {
-        19:00 - 22:00
-        action: social::family_time
-    }
-}
-
-

Seasonal Variation

-
schedule SeasonalBaker {
-    block summer_work {
-        06:00 - 20:00
-        action: baking::long_shift
-        on season summer
-    }
-
-    block winter_work {
-        07:00 - 18:00
-        action: baking::short_shift
-        on season winter
-    }
-
-    block spring_work {
-        06:30 - 19:00
-        action: baking::medium_shift
-        on season spring
-    }
-
-    block fall_work {
-        06:30 - 19:00
-        action: baking::medium_shift
-        on season fall
-    }
-}
-
-

Weekly Pattern with Recurrence

-
schedule InnkeeperSchedule {
-    // Weekday routine
-    block weekday_service {
-        08:00 - 22:00
-        action: inn::regular_service
-        on day monday  // Repeat for each weekday
-    }
-
-    block weekday_service {
-        08:00 - 22:00
-        action: inn::regular_service
-        on day tuesday
-    }
-
-    // ... (wednesday, thursday, friday)
-
-    // Weekend hours
-    block weekend_service {
-        10:00 - 24:00
-        action: inn::busy_service
-        on day saturday
-    }
-
-    block weekend_service {
-        10:00 - 24:00
-        action: inn::busy_service
-        on day sunday
-    }
-
-    // Weekly market day
-    recurs MarketDay on day wednesday {
-        block market_prep {
-            06:00 - 08:00
-            action: inn::prepare_market_goods
-        }
-
-        block market_rush {
-            08:00 - 16:00
-            action: inn::market_day_chaos
-        }
-    }
-}
-
-

Extended Schedule

-
schedule BaseShopkeeper {
-    block open {
-        09:00 - 17:00
-        action: shop::standard_hours
-    }
-}
-
-schedule BlacksmithSchedule extends BaseShopkeeper {
-    block open {  // Override
-        06:00 - 18:00  // Longer hours
-        action: smithing::work
-    }
-
-    block forge_heat {  // New block
-        05:00 - 06:00
-        action: smithing::heat_forge
-    }
-}
-
-

Complex Year-Round Schedule

-
schedule MasterBakerYear {
-    // Daily base pattern
-    block prep {
-        04:00 - 06:00
-        action: baking::prepare
-    }
-
-    block baking {
-        06:00 - 10:00
-        action: baking::bake
-    }
-
-    block sales {
-        10:00 - 16:00
-        action: baking::serve
-    }
-
-    block cleanup {
-        16:00 - 17:00
-        action: baking::clean
-    }
-
-    // Seasonal variations
-    block summer_hours {
-        10:00 - 20:00  // Extended sales
-        action: baking::busy_summer
-        on season summer
-    }
-
-    // Weekly market
-    recurs MarketDay on day saturday {
-        block market_prep {
-            02:00 - 04:00
-            action: baking::market_prep
-        }
-
-        block market_sales {
-            08:00 - 18:00
-            action: baking::market_rush
-        }
-    }
-
-    // Annual events
-    recurs HarvestFestival on dates "Sep 20" .. "Sep 25" {
-        block festival {
-            06:00 - 23:00
-            action: baking::festival_mode
-        }
-    }
-}
-
-

Integration with Characters

-

Characters link to schedules using the uses schedule clause:

-
character Martha {
-    uses schedule: BakerySchedule
-}
-
-

Multiple schedules:

-
character Innkeeper {
-    uses schedules: [WeekdaySchedule, WeekendSchedule]
-}
-
-

See Characters for complete integration syntax.

-

Execution Semantics

-

Time-Based Selection

-

At any given time, the runtime:

-
    -
  1. Evaluates temporal constraints: Which blocks apply right now?
  2. -
  3. Selects matching block: First block whose time range and constraint match
  4. -
  5. Executes action: Runs the associated behavior tree
  6. -
  7. Repeats next tick
  8. -
-

Priority Order

-

When multiple blocks could apply:

-
    -
  1. Recurrences take priority over regular blocks
  2. -
  3. Constraints filter blocks (season, day, month)
  4. -
  5. Time ranges must overlap current time
  6. -
  7. First match wins (declaration order)
  8. -
-

Block Overlap

-

Blocks can overlap in time. The runtime selects the first matching block.

-

Example:

-
schedule Overlapping {
-    block general {
-        08:00 - 17:00
-        action: work::general
-    }
-
-    block specialized {
-        10:00 - 12:00  // Overlaps with general
-        action: work::specialized
-        on day wednesday
-    }
-}
-
-

On Wednesday at 11:00, specialized block is selected (more specific constraint).

-

Validation Rules

-
    -
  1. Time format: Times must be valid HH:MM or HH:MM:SS (24-hour)
  2. -
  3. Time order: Start time must be before end time (unless spanning midnight)
  4. -
  5. Extends exists: If using extends, base schedule must be defined
  6. -
  7. No circular extends: Cannot form circular dependency chains
  8. -
  9. Named blocks unique: Block names must be unique within a schedule
  10. -
  11. Action exists: Action references must resolve to defined behaviors
  12. -
  13. Constraint values: Temporal constraint values must reference defined enums
  14. -
  15. Recurrence names unique: Recurrence names must be unique within a schedule
  16. -
-

Best Practices

-

1. Use Named Blocks for Overrides

-

Avoid:

-
schedule Extended extends Base {
-    block { 05:00 - 13:00, action: work }  // Appends instead of overriding
-}
-
-

Prefer:

-
schedule Extended extends Base {
-    block work { 05:00 - 13:00, action: early_work }  // Overrides by name
-}
-
- -
schedule DailyRoutine {
-    // Sleep blocks
-    block night_sleep { 22:00 - 05:00, action: sleep }
-
-    // Morning blocks
-    block wake_up { 05:00 - 06:00, action: morning_routine }
-    block breakfast { 06:00 - 07:00, action: eat_breakfast }
-
-    // Work blocks
-    block commute { 07:00 - 08:00, action: travel_to_work }
-    block work { 08:00 - 17:00, action: work }
-}
-
-

3. Use Recurrences for Special Events

-

Avoid: Duplicating blocks manually

-

Prefer:

-
recurs MarketDay on day saturday {
-    block market { 08:00 - 16:00, action: market_work }
-}
-
-

4. Extend for Variations

-

Avoid: Duplicating entire schedules

-

Prefer:

-
schedule WorkerBase { ... }
-schedule EarlyWorker extends WorkerBase { ... }
-schedule NightWorker extends WorkerBase { ... }
-
-

5. Use Temporal Constraints for Clarity

-
block summer_hours {
-    06:00 - 20:00
-    action: long_shift
-    on season summer  // Explicit and readable
-}
-
-

Cross-References

- - -
    -
  • Time-based AI: Schedules drive time-dependent behavior
  • -
  • Template inheritance: extends enables schedule reuse
  • -
  • Temporal constraints: Filter blocks by season, day, month
  • -
  • Recurrence patterns: Define repeating events
  • -
  • Composition: Build complex schedules from simple parts
  • -
-

Relationships

-

Relationships define connections between characters, institutions, and other entities. They capture social bonds, power dynamics, emotional ties, and interactive patterns. Relationships can be symmetric (friendship) or asymmetric (parent-child), and support bidirectional perspectives where each participant has different fields.

-

What is a Relationship?

-

A relationship connects two or more participants and describes:

-
    -
  • Participants: The entities involved (characters, institutions)
  • -
  • Roles: Optional labels (parent, employer, spouse)
  • -
  • Shared fields: Properties of the relationship itself (bond strength, duration)
  • -
  • Perspective fields: How each participant views the relationship (self/other blocks)
  • -
-
Relationship: ParentChild
-├─ Participant: Martha (as parent)
-│   ├─ self: { responsibility: 1.0, protective: 0.9 }
-│   └─ other: { dependent: 0.8 }
-├─ Participant: Tommy (as child)
-└─ Shared: { bond: 0.9, years_together: 8 }
-
-

Syntax

-
<relationship-decl> ::= "relationship" <identifier> <body>
-
-<body> ::= "{" <participant>+ <field>* "}"
-
-<participant> ::= <qualified-path> <role-clause>? <perspective-blocks>?
-
-<role-clause> ::= "as" <identifier>
-
-<perspective-blocks> ::= "self" "{" <field>* "}" "other" "{" <field>* "}"
-                       | "self" "{" <field>* "}"
-                       | "other" "{" <field>* "}"
-
-<field> ::= <identifier> ":" <value>
-
-

Basic Relationships

-

Simple Two-Party Relationship

-
relationship Friendship {
-    Martha
-    Gregory
-    bond: 0.8
-    years_known: 15
-}
-
-

Semantics:

-
    -
  • Two participants: Martha and Gregory
  • -
  • Shared field: bond (strength of friendship)
  • -
  • Shared field: years_known (duration)
  • -
-

Multi-Party Relationship

-
relationship Family {
-    Martha
-    David
-    Tommy
-    Elena
-
-    household: "Baker Residence"
-    family_bond: 0.95
-}
-
-

Relationships can have any number of participants.

-

Roles

-

Roles label a participant’s function in the relationship.

-

Syntax

-
ParticipantName as role_name
-
-

Examples

-
relationship Marriage {
-    Martha as spouse
-    David as spouse
-
-    bond: 0.9
-    anniversary: "2015-06-20"
-}
-
-
relationship ParentChild {
-    Martha as parent
-    Tommy as child
-
-    bond: 0.95
-    guardianship: true
-}
-
-
relationship EmployerEmployee {
-    Martha as employer
-    Elena as employee
-
-    workplace: "Martha's Bakery"
-    salary: 45000
-}
-
-

Role Semantics

-
    -
  • Labels: Roles are descriptive labels, not types
  • -
  • Multiple roles: Same person can have different roles in different relationships
  • -
  • Optional: Roles are optional—participants can be unnamed
  • -
  • Flexibility: No predefined role vocabulary—use what makes sense
  • -
-

Perspective Fields (Self/Other Blocks)

-

Perspective fields specify how each participant views the relationship. They enable asymmetric, bidirectional relationships.

-

Syntax

-
ParticipantName as role self {
-    // Fields describing this participant's perspective
-} other {
-    // Fields describing how this participant views others
-}
-
-

Self Block

-

The self block contains fields about how the participant experiences the relationship:

-
relationship ParentChild {
-    Martha as parent self {
-        responsibility: 1.0
-        protective: 0.9
-        anxiety_level: 0.6
-    }
-    Tommy as child
-}
-
-

Martha’s perspective:

-
    -
  • responsibility: She feels 100% responsible
  • -
  • protective: She’s highly protective (90%)
  • -
  • anxiety_level: Moderate anxiety about parenting
  • -
-

Other Block

-

The other block contains fields about how the participant views the other participants:

-
relationship ParentChild {
-    Martha as parent self {
-        responsibility: 1.0
-    } other {
-        dependent: 0.8      // She sees Tommy as 80% dependent
-        mature_for_age: 0.7  // She thinks he's fairly mature
-    }
-    Tommy as child
-}
-
-

Both Blocks

-
relationship EmployerEmployee {
-    Martha as employer self {
-        authority: 0.9
-        stress: 0.6
-    } other {
-        respect: 0.8
-        trust: 0.85
-    }
-    Elena as employee
-}
-
-

Martha’s perspective:

-
    -
  • Self: She has high authority (90%), moderate stress (60%)
  • -
  • Other: She respects Elena (80%), trusts her (85%)
  • -
-

Asymmetric Relationships

-

Different participants can have different perspective fields:

-
relationship TeacherStudent {
-    Gandalf as teacher self {
-        patience: 0.8
-        wisdom_to_impart: 1.0
-    } other {
-        potential: 0.9
-        ready_to_learn: 0.6
-    }
-
-    Frodo as student self {
-        eager_to_learn: 0.7
-        overwhelmed: 0.5
-    } other {
-        admiration: 0.95
-        intimidated: 0.4
-    }
-
-    bond: 0.85
-}
-
-

Gandalf’s view:

-
    -
  • He’s patient (80%), has much wisdom to share
  • -
  • Sees Frodo as having high potential but only moderately ready
  • -
-

Frodo’s view:

-
    -
  • He’s eager but overwhelmed
  • -
  • Deeply admires Gandalf, slightly intimidated
  • -
-

Shared Fields

-

Fields declared at the relationship level (not in self/other blocks) are shared among all participants.

-
relationship Friendship {
-    Martha
-    Gregory
-
-    bond: 0.8           // Shared: mutual bond strength
-    years_known: 15     // Shared: how long they've known each other
-    shared_routines: 3  // Shared: number of daily routines
-}
-
-

Common shared fields:

-
    -
  • bond: Relationship strength (0.0 to 1.0)
  • -
  • years_known: Duration of relationship
  • -
  • trust: Mutual trust level
  • -
  • commitment: Commitment to the relationship
  • -
  • compatibility: How well they get along
  • -
-

Prose Blocks

-

Relationships can include prose blocks for narrative context.

-
relationship MarthaAndGregory {
-    Martha {
-        role: shopkeeper
-        values_loyalty: 0.9
-
-        ---perspective
-        Martha appreciates Gregory's unwavering loyalty. He has
-        been buying her sourdough loaf every morning for fifteen
-        years. Their brief daily exchanges about the weather and
-        local gossip are a comforting routine.
-        ---
-    }
-
-    Gregory {
-        role: regular_customer
-        always_orders: "sourdough_loaf"
-
-        ---perspective
-        Gregory considers Martha's bakery a cornerstone of his
-        daily routine. The bread is excellent, but it is the brief
-        human connection that keeps him coming back.
-        ---
-    }
-}
-
-

Common prose tags:

-
    -
  • ---perspective: How a participant views the relationship
  • -
  • ---history: Background of the relationship
  • -
  • ---dynamics: How the relationship functions
  • -
  • ---notes: Design or development notes
  • -
-

Note: In this syntax, perspective fields are inside participant blocks (not separate self/other blocks).

-

Complete Examples

-

Simple Friendship

-
relationship Friendship {
-    Martha
-    NeighborBaker
-
-    bond: 0.6
-    years_known: 10
-}
-
-

Marriage with Roles

-
relationship Marriage {
-    Martha as spouse
-    David as spouse
-
-    bond: 0.9
-    anniversary: "2015-06-20"
-    children: 2
-}
-
-

Parent-Child with Perspectives

-
relationship ParentChild {
-    Martha as parent self {
-        responsibility: 1.0
-        protective: 0.9
-        anxiety_level: 0.6
-    } other {
-        dependent: 0.8
-        mature_for_age: 0.7
-    }
-
-    Tommy as child self {
-        seeks_independence: 0.7
-        appreciates_parent: 0.9
-    } other {
-        feels_understood: 0.6
-        wants_more_freedom: 0.8
-    }
-
-    bond: 0.95
-    years_together: 8
-}
-
-

Employer-Employee

-
relationship EmployerEmployee {
-    Martha as employer self {
-        authority: 0.9
-        satisfaction_with_employee: 0.85
-    } other {
-        respect: 0.8
-        trust: 0.85
-    }
-
-    Elena as employee self {
-        job_satisfaction: 0.8
-        career_growth: 0.7
-    } other {
-        respects_boss: 0.9
-        appreciates_flexibility: 0.95
-    }
-
-    workplace: "Martha's Bakery"
-    salary: 45000
-    employment_start: "2023-01-15"
-}
-
-

Complex Multi-Perspective

-
relationship MentorApprentice {
-    Martha {
-        role: mentor
-        teaching_style: "patient"
-        investment: 0.9
-
-        ---perspective
-        Martha sees Elena as the daughter she might have had in
-        the trade. She recognizes the same passion she felt at
-        that age and pushes Elena harder because she knows the
-        talent is there. Every correction comes from love.
-        ---
-    }
-
-    Elena {
-        role: apprentice
-        dedication: 0.9
-        anxiety: 0.4
-
-        ---perspective
-        Elena idolizes Martha's skill but fears disappointing
-        her. Every morning she arrives thirty minutes early to
-        practice techniques before Martha gets in. She keeps a
-        notebook of every correction, reviewing them each night.
-
-        "I want to be half as good as her someday" -- this quiet
-        ambition drives everything Elena does.
-        ---
-    }
-
-    bond: 0.85
-}
-
-

Business Rivalry

-
relationship BakeryRivalry {
-    Martha {
-        role: established_baker
-        aware_of_competition: true
-        respects_rival: 0.6
-
-        ---perspective
-        Martha views the new bakery across town as healthy
-        competition. She respects their pastry work but knows
-        her sourdough is unmatched. The rivalry pushes her to
-        keep innovating.
-        ---
-    }
-
-    RivalBaker {
-        role: newcomer
-        wants_to_surpass: true
-        studies_martha: 0.8
-
-        ---perspective
-        The rival baker moved to town specifically because of
-        Martha's reputation. They study her techniques, buy her
-        bread to analyze it, and dream of the day a customer
-        chooses their loaf over Martha's sourdough.
-        ---
-    }
-
-    bond: 0.3
-}
-
-

Multi-Party Family

-
relationship BakerFamily {
-    Martha as parent
-    David as parent
-    Tommy as child
-    Elena as child
-
-    household: "Baker Residence"
-    family_bond: 0.95
-    dinner_time: 18:00
-
-    ---dynamics
-    A loving queer family running a bakery together. Martha and
-    David met at culinary school, married, and adopted Tommy and
-    Elena. The whole family works at the bakery on weekends.
-    ---
-}
-
-

Co-Owners Partnership

-
relationship BakeryPartnership {
-    Martha {
-        role: co_owner
-        specialty: "bread"
-        handles_finances: true
-
-        ---perspective
-        Martha and Jane complement each other perfectly. Martha
-        handles the bread and business side while Jane creates
-        the pastries that draw customers in. Together they have
-        built something neither could alone.
-        ---
-    }
-
-    Jane {
-        role: co_owner
-        specialty: "pastries"
-        handles_creativity: true
-
-        ---perspective
-        Jane considers Martha the steady foundation of their
-        partnership. While Jane experiments and creates, Martha
-        ensures the bakery runs like clockwork. Their different
-        strengths make the bakery stronger.
-        ---
-    }
-
-    bond: 0.9
-}
-
-

Participant Types

-

Participants can be:

-
    -
  1. Characters: Most common
  2. -
  3. Institutions: Organizations in relationships
  4. -
  5. Locations: Less common, but valid (e.g., “GuardianOfPlace”)
  6. -
-
relationship GuildMembership {
-    Elena as member
-    BakersGuild as organization
-
-    membership_since: "2023-01-01"
-    standing: "good"
-    dues_paid: true
-}
-
-

Field Resolution

-

When a relationship is resolved, fields are merged:

-
    -
  1. Relationship shared fields apply to all participants
  2. -
  3. Participant self blocks apply to that participant
  4. -
  5. Participant other blocks describe how that participant views others
  6. -
-

Example:

-
relationship Example {
-    Martha as friend self {
-        loyalty: 0.9
-    } other {
-        trust: 0.8
-    }
-    Gregory as friend
-
-    bond: 0.85
-}
-
-

Resolution:

-
    -
  • Martha gets: loyalty: 0.9 (from self), trust: 0.8 (towards Gregory, from other), bond: 0.85 (shared)
  • -
  • Gregory gets: bond: 0.85 (shared)
  • -
  • Relationship gets: bond: 0.85
  • -
-

Validation Rules

-
    -
  1. At least two participants: Relationships require ≥2 participants
  2. -
  3. Participants exist: All participant names must reference defined entities
  4. -
  5. Unique participant names: Each participant appears at most once
  6. -
  7. Field type consistency: Fields must have valid value types
  8. -
  9. No circular relationships: Avoid infinite relationship chains (warning)
  10. -
  11. Self/other completeness: If using self/other, both blocks should be present (best practice)
  12. -
-

Use Cases

-

Social Networks

-
relationship BakerFriendship {
-    Martha
-    Gregory
-    bond: 0.8
-}
-
-relationship SupplierPartnership {
-    Martha
-    Farmer_Jenkins
-    bond: 0.7
-}
-
-relationship BakeryRivalry {
-    Martha
-    RivalBaker
-    bond: 0.2
-    competitive: true
-}
-
-

Family Structures

-
relationship ParentChild {
-    Martha as parent
-    Tommy as child
-    bond: 0.95
-}
-
-relationship Siblings {
-    Tommy as older_sibling
-    Elena as younger_sibling
-    bond: 0.85
-    rivalry: 0.3
-}
-
-

Power Dynamics

-
relationship Vassalage {
-    King as lord self {
-        grants: "protection"
-        expects: "loyalty"
-    } other {
-        trusts: 0.6
-    }
-
-    Knight as vassal self {
-        swears: "fealty"
-        expects: "land"
-    } other {
-        respects: 0.9
-    }
-
-    oath_date: "1205-03-15"
-}
-
-

Asymmetric Awareness

-
relationship StalkingVictim {
-    Stalker as pursuer self {
-        obsession: 0.95
-        distance_maintained: 50  // meters
-    } other {
-        believes_unnoticed: true
-    }
-
-    Victim as unaware_target self {
-        awareness: 0.0
-    }
-
-    danger_level: 0.8
-}
-
-

Best Practices

-

1. Use Descriptive Relationship Names

-

Avoid:

-
relationship R1 { ... }
-relationship MarthaGregory { ... }
-
-

Prefer:

-
relationship Friendship { ... }
-relationship ParentChild { ... }
-relationship MentorApprentice { ... }
-
-

2. Use Roles for Clarity

-
relationship Marriage {
-    Martha as spouse
-    David as spouse
-}
-
-

Better than:

-
relationship Marriage {
-    Martha
-    David
-}
-
-

3. Shared Fields for Mutual Properties

-
relationship Partnership {
-    Martha
-    Jane
-
-    bond: 0.9           // Mutual bond
-    years_together: 5   // Shared history
-}
-
-

4. Self/Other for Perspectives

-
relationship TeacherStudent {
-    Teacher as mentor self {
-        patience: 0.8
-    } other {
-        potential: 0.9
-    }
-
-    Student as learner self {
-        motivation: 0.7
-    } other {
-        admiration: 0.95
-    }
-}
-
-

5. Prose Blocks for Rich Context

-
relationship ComplexDynamic {
-    Martha { ... }
-    Jane { ... }
-
-    ---dynamics
-    Their relationship is characterized by mutual respect but
-    divergent goals. Martha focuses on traditional bread while Jane
-    pushes for experimental pastries, creating creative tension.
-    ---
-}
-
-

Cross-References

- - -
    -
  • Bidirectional modeling: self/other blocks enable asymmetric perspectives
  • -
  • Social simulation: Relationships drive character interactions
  • -
  • Narrative depth: Prose blocks embed storytelling in relationship data
  • -
  • Power dynamics: Roles and perspective fields model hierarchies
  • -
  • Emotional bonds: Bond strength and trust metrics quantify connections
  • -
-

Locations

-

Locations define places in your world – rooms, buildings, cities, landscapes, or abstract spaces. They provide spatial context for characters, events, and narratives.

-
-

Syntax

-
<location-decl> ::= "location" <identifier> "{" <field>* <prose-block>* "}"
-
-

A location declaration consists of:

-
    -
  • The location keyword
  • -
  • A unique name (identifier)
  • -
  • A body block containing fields and optional prose blocks
  • -
-

Locations are one of the simpler declaration types – they hold fields and prose blocks but do not support resource linking (uses behaviors / uses schedule) like characters or institutions.

-
-

Basic Location

-

The simplest location has a name and descriptive fields:

-
location BakersBakery {
-    type: bakery
-    capacity: 30
-    address: "14 Main Street"
-    open_hours: "06:00-18:00"
-}
-
-

Fields can use any value type: integers, floats, strings, booleans, enums, lists, ranges, and durations.

-
-

Fields

-

Location fields describe properties of the place:

-
location BakerHome {
-    type: residence
-    bedrooms: 3
-    has_garden: true
-    garden_size_sqft: 450.0
-    residents: ["Martha", "David", "Jane"]
-    comfort_level: 0.85
-}
-
-

Common Field Patterns

-
- - - - - -
FieldTypeDescription
typeenum/identifierCategory of the place
capacityintegerHow many can be in this place
sizeenum/floatPhysical size
coordinatesinteger/floatPosition in a world map
accessiblebooleanWhether characters can enter
-
-

These are conventions, not enforced schema. You define whatever fields are meaningful for your world.

-
-

Prose Blocks

-

Locations support prose blocks for rich narrative content. Prose blocks are delimited by ---tag markers:

-
location BakersBakery {
-    type: bakery
-    capacity: 30
-
-    ---description
-    A warm, inviting bakery on Main Street. The smell of fresh bread
-    wafts out the door every morning at dawn. Martha has run the shop
-    for fifteen years, and the locals consider it the heart of the
-    neighborhood.
-    ---
-
-    ---atmosphere
-    Flour dust catches the light from tall windows. A display case
-    holds rows of golden pastries. Behind the counter, the kitchen
-    hums with activity from 4 AM onward.
-    ---
-}
-
-

Prose block rules:

-
    -
  • Start with ---tag_name on its own line
  • -
  • Content is free-form text (Markdown supported)
  • -
  • End with --- on its own line
  • -
  • The tag name becomes the key for retrieval
  • -
  • Multiple prose blocks per location are allowed
  • -
  • Each tag must be unique within the location
  • -
-
-

Ranges

-

Locations can use range values for procedural variation:

-
location MarketSquare {
-    type: outdoor_market
-    stalls: 10..25
-    daily_visitors: 50..200
-    noise_level: 0.4..0.9
-}
-
-

When instantiated, values are selected from within the specified range. This is useful for locations that should vary across simulation runs.

-
-

Lists

-

Locations can hold list values:

-
location BakersBakery {
-    type: bakery
-    products: ["sourdough", "croissants", "rye bread", "cinnamon rolls"]
-    equipment: ["stone oven", "mixing station", "proofing cabinet"]
-}
-
-
-

Referencing Other Entities

-

Location fields can reference other declarations by name:

-
location BakersBakery {
-    type: bakery
-    owner: Martha
-    neighborhood: MainStreet
-    part_of: TownCenter
-}
-
-

These are identifier references – they are not validated as cross-references at parse time, but the resolver checks that referenced names exist in the name table.

-
-

Nested Structure with Fields

-

You can model spatial hierarchy using fields:

-
location BakersBakery {
-    type: bakery
-    parent: MainStreet
-
-    // Zones within the bakery
-    has_kitchen: true
-    has_storefront: true
-    has_storage_room: true
-
-    // Dimensions
-    total_sqft: 1200
-    kitchen_sqft: 600
-    storefront_sqft: 400
-    storage_sqft: 200
-}
-
-location MainStreet {
-    type: street
-    parent: TownCenter
-    length_meters: 500
-    shops: 12
-}
-
-location TownCenter {
-    type: district
-    population: 2000
-}
-
-

There is no built-in parent-child relationship for locations – you model hierarchy through conventional field names like part_of, parent, or contains.

-
-

Location with Enum Fields

-

Use enums for type-safe categorization:

-
enum PlaceType {
-    residence, shop, workshop, office,
-    park, street, square, church
-}
-
-enum Accessibility {
-    public, private, restricted, members_only
-}
-
-location BakersBakery {
-    type: shop
-    accessibility: public
-    capacity: 30
-}
-
-location BakerHome {
-    type: residence
-    accessibility: private
-    capacity: 8
-}
-
-
-

Complete Example: Baker Family Locations

-
use schema::enums::{PlaceType, Accessibility};
-
-location BakersBakery {
-    type: shop
-    accessibility: public
-    owner: Martha
-    address: "14 Main Street"
-    capacity: 30
-    employees: 4
-    established: "2011"
-    specialty: "artisan sourdough"
-    daily_output_loaves: 80..120
-
-    ---description
-    Martha Baker's artisan bakery, known throughout town for its
-    sourdough and pastries. The shop opens at 6 AM sharp, and by
-    mid-morning there's usually a line out the door.
-    ---
-
-    ---history
-    Originally a hardware store, Martha converted the space after
-    winning a local baking competition. The stone oven was imported
-    from France and is the heart of the operation.
-    ---
-}
-
-location BakerHome {
-    type: residence
-    accessibility: private
-    address: "22 Elm Lane"
-    bedrooms: 4
-    has_garden: true
-    garden_size_sqft: 600
-    residents: ["Martha", "David", "Jane", "Tom"]
-    comfort_level: 0.9
-
-    ---description
-    A comfortable family home on a quiet street. The kitchen is
-    oversized (Martha insisted) and there's always something
-    baking, even at home.
-    ---
-}
-
-location BakersGuildHall {
-    type: office
-    accessibility: members_only
-    address: "7 Guild Row"
-    capacity: 100
-    meeting_room_capacity: 40
-    established: "1892"
-
-    ---description
-    The historic headquarters of the Bakers Guild, where trade
-    matters are discussed and apprenticeships are arranged.
-    ---
-}
-
-
-

Validation Rules

-
    -
  1. Unique names: Location names must be unique within their scope
  2. -
  3. Valid field values: All fields must have values that conform to value types
  4. -
  5. Unique field names: No duplicate field names within a location
  6. -
  7. Unique prose tags: No duplicate prose block tags within a location
  8. -
  9. Valid identifiers: Location names must follow identifier rules ([a-zA-Z_][a-zA-Z0-9_]*)
  10. -
-
-

Locations vs. Other Declarations

-
- - - - - -
AspectLocationsInstitutionsCharacters
PurposePhysical/abstract placesOrganizations/groupsIndividuals
Resource linkingNoYesYes
Prose blocksYesYesYes
SpeciesNoNoYes
TemplatesNoNoYes
-
-

Locations are intentionally simple. They define where things happen. For who does things, use characters. For organizational structures, use institutions.

-
-

Cross-References

- -

Institutions

-

Institutions define organizations, groups, and systems – entities that function like characters but represent collectives rather than individuals. Unlike locations (which model where), institutions model what structures and organizations operate in your world.

-
-

Syntax

-
<institution-decl> ::= "institution" <identifier> "{" <institution-body> "}"
-
-<institution-body> ::= (<field> | <uses-behaviors> | <uses-schedule> | <prose-block>)*
-
-<uses-behaviors>  ::= "uses" "behaviors" ":" "[" <behavior-link> ("," <behavior-link>)* "]"
-
-<behavior-link>   ::= "{" "tree" ":" <path> ","?
-                           ("when" ":" <expression> ","?)?
-                           ("priority" ":" <priority-level> ","?)? "}"
-
-<priority-level>  ::= "low" | "normal" | "high" | "critical"
-
-<uses-schedule>   ::= "uses" "schedule" ":" <identifier>
-                     | "uses" "schedules" ":" "[" <identifier> ("," <identifier>)* "]"
-
-

An institution declaration consists of:

-
    -
  • The institution keyword
  • -
  • A unique name (identifier)
  • -
  • A body block containing fields, resource links, and optional prose blocks
  • -
-
-

Basic Institution

-

The simplest institution has a name and descriptive fields:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-}
-
-
-

Fields

-

Institution fields describe properties of the organization:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-    dues_annual: 120
-    meeting_frequency: "monthly"
-    accepts_apprentices: true
-    max_apprentices: 10
-    location: BakersGuildHall
-}
-
-

Common Field Patterns

-
- - - - - - -
FieldTypeDescription
typeenum/identifierCategory of organization
membersintegerMembership count
foundedstringEstablishment date
reputationfloatPublic standing (0.0-1.0)
locationidentifierWhere the institution operates
leaderidentifierWho runs the institution
-
-

These are conventions – you define whatever fields make sense for your world.

-
-

Prose Blocks

-

Institutions support prose blocks for rich narrative documentation:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-
-    ---description
-    The Bakers Guild has been the backbone of the town's bread trade
-    since 1892. Members share recipes, arrange apprenticeships, and
-    collectively negotiate flour prices with suppliers.
-    ---
-
-    ---charter
-    Article I: All members shall maintain the highest standards of
-    baking quality. Article II: Apprentices must complete a three-year
-    training program. Article III: Monthly meetings are mandatory.
-    ---
-
-    ---traditions
-    Every autumn, the Guild hosts the Great Bake-Off, a competition
-    open to all members. The winner earns the title of Master Baker
-    for the following year.
-    ---
-}
-
-

Prose block rules:

-
    -
  • Start with ---tag_name on its own line
  • -
  • Content is free-form text (Markdown supported)
  • -
  • End with --- on its own line
  • -
  • Multiple prose blocks per institution are allowed
  • -
  • Each tag must be unique within the institution
  • -
-
-

Resource Linking: Behaviors

-

Institutions can link to behavior trees using the uses behaviors clause. This defines what actions the institution takes as a collective entity.

-

Simple Behavior Linking

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-
-    uses behaviors: [
-        { tree: ManageApprentices },
-        { tree: NegotiateSuppliers },
-        { tree: HostEvents }
-    ]
-}
-
-

Each behavior link is an object with a tree field referencing a behavior tree by name or path.

- -
institution BakersGuild {
-    type: trade_guild
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostEvents, priority: low }
-    ]
-}
-
-

Priority levels: low, normal (default), high, critical.

- -
institution BakersGuild {
-    type: trade_guild
-
-    uses behaviors: [
-        { tree: ManageApprentices },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: EmergencyMeeting, when: reputation < 0.3, priority: critical }
-    ]
-}
-
-

The when clause takes an expression that determines when the behavior activates.

- -
- - - -
FieldRequiredTypeDescription
treeYespathReference to a behavior tree
priorityNopriority levelExecution priority (default: normal)
whenNoexpressionActivation condition
-
-
-

Resource Linking: Schedules

-

Institutions can link to schedules using the uses schedule or uses schedules clause.

-

Single Schedule

-
institution BakersGuild {
-    type: trade_guild
-    uses schedule: GuildOperatingHours
-}
-
-

Multiple Schedules

-
institution BakersGuild {
-    type: trade_guild
-    uses schedules: [WeekdaySchedule, WeekendSchedule, HolidaySchedule]
-}
-
-
-

Complete Syntax Example

-

An institution using all available features:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-    dues_annual: 120
-    location: BakersGuildHall
-    leader: Martha
-    accepts_apprentices: true
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostAnnualBakeOff, when: month is october, priority: high },
-        { tree: EmergencyMeeting, when: reputation < 0.3, priority: critical }
-    ]
-
-    uses schedule: GuildOperatingHours
-
-    ---description
-    The Bakers Guild has been the backbone of the town's bread trade
-    since 1892. Martha Baker currently serves as Guild Master.
-    ---
-
-    ---membership_rules
-    New members must be nominated by an existing member and pass
-    a baking trial. Apprentices are accepted from age 16.
-    ---
-}
-
-
-

Membership Modeling

-

Institutions themselves don’t have a built-in membership list. Instead, model membership through character fields or relationships:

-

Via Character Fields

-
character Martha {
-    age: 45
-    guild_member: true
-    guild_role: guild_master
-    guild: BakersGuild
-}
-
-character Jane {
-    age: 19
-    guild_member: true
-    guild_role: apprentice
-    guild: BakersGuild
-}
-
-

Via Relationships

-
relationship GuildMembership {
-    Martha as guild_master { }
-    BakersGuild as organization { }
-    bond: 0.95
-    years_active: 20
-}
-
-relationship Apprenticeship {
-    Jane as apprentice { }
-    BakersGuild as guild { }
-    Martha as mentor { }
-    years_completed: 1
-    years_remaining: 2
-}
-
-
-

Institutions vs. Characters

-

Both institutions and characters can use behaviors and schedules, but they serve different purposes:

-
- - - - - - - -
AspectInstitutionsCharacters
RepresentsOrganizations, collectivesIndividuals
SpeciesNoYes (optional)
TemplatesNoYes (optional)
uses behaviorsYesYes
uses scheduleYesYes
Prose blocksYesYes
Participation in relationshipsYes (via name)Yes (via name)
-
-

Use institutions when you need an entity that acts collectively: a guild votes, a government issues decrees, a school enrolls students.

-
-

Use Cases

-
    -
  • Organizations: Guilds, companies, governments, religions
  • -
  • Social structures: Families, tribes, castes, classes
  • -
  • Systems: Economic systems, magical systems, legal frameworks
  • -
  • Abstract entities: Dream logic, fate, cultural norms
  • -
  • Collectives: Military units, sports teams, musical ensembles
  • -
-
-

Complete Example: Baker Family World

-
use schema::enums::{GuildRole, InstitutionType};
-
-institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-    location: BakersGuildHall
-    leader: Martha
-    annual_dues: 120
-    accepts_apprentices: true
-    max_apprentices_per_mentor: 2
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostAnnualBakeOff, when: month is october, priority: high }
-    ]
-
-    uses schedule: GuildOperatingHours
-
-    ---description
-    The Bakers Guild has served the town since 1892, ensuring quality
-    standards and fair pricing across all bakeries. Monthly meetings
-    are held at the Guild Hall, and the annual Bake-Off is the
-    highlight of the autumn calendar.
-    ---
-}
-
-institution TownCouncil {
-    type: government
-    members: 12
-    meets: "first Monday of each month"
-    location: TownHall
-    jurisdiction: "town limits"
-
-    uses behaviors: [
-        { tree: ReviewPetitions },
-        { tree: AllocateBudget, priority: high }
-    ]
-
-    ---description
-    The elected body governing the town. Martha Baker has been
-    lobbying them for years about flour import tariffs.
-    ---
-}
-
-institution BakersBakeryBusiness {
-    type: business
-    owner: Martha
-    employees: 4
-    location: BakersBakery
-    annual_revenue: 180000
-    established: "2011"
-
-    uses behaviors: [
-        { tree: DailyBakingOps, priority: high },
-        { tree: InventoryManagement },
-        { tree: CustomerService }
-    ]
-
-    uses schedule: BakeryOperatingHours
-
-    ---description
-    The business entity behind Baker's Bakery. Martha runs the
-    operation with help from her daughter Jane (apprentice baker),
-    two full-time bakers, and a part-time cashier.
-    ---
-}
-
-
-

Validation Rules

-
    -
  1. Unique names: Institution names must be unique within their scope
  2. -
  3. Valid field values: All fields must have values conforming to value types
  4. -
  5. Unique field names: No duplicate field names within an institution
  6. -
  7. Unique prose tags: No duplicate prose block tags within an institution
  8. -
  9. Valid behavior links: Each behavior link must have a tree field
  10. -
  11. Valid priority levels: Priority must be low, normal, high, or critical
  12. -
  13. Valid schedule references: Schedule names in uses schedule/uses schedules must be valid identifiers
  14. -
  15. Valid identifiers: Institution names must follow identifier rules ([a-zA-Z_][a-zA-Z0-9_]*)
  16. -
-
-

Cross-References

- -

Other Declarations

-

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.

-
-

Templates

-

Templates are reusable field sets that characters inherit using the from keyword. Unlike species (which define what an entity is), templates define what an entity has—capabilities, traits, and characteristics.

-

Syntax

-
<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>
-
-

Basic Template

-
template Warrior {
-    strength: 10..20
-    dexterity: 8..15
-    weapon_proficiency: 0.7..1.0
-}
-
-

Characters inheriting this template get these fields with values selected from the specified ranges.

-

Template Includes

-

Templates can include other templates to compose functionality:

-
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
-}
-
-

Semantics:

-
    -
  • include SkilledWorker brings in all fields from that template
  • -
  • Fields are merged left-to-right (later overrides earlier)
  • -
  • Transitive includes supported
  • -
  • Multiple includes allowed: include A, B, C
  • -
-

Range Values

-

Templates can specify ranges for procedural variation:

-
template Villager {
-    age: 18..65
-    wealth: 10..100
-    height: 150.0..190.0
-    disposition: 0.0..1.0
-}
-
-

Range syntax:

-
    -
  • Integer ranges: min..max (inclusive)
  • -
  • Float ranges: min..max (inclusive)
  • -
  • Both bounds must be same type
  • -
  • min ≤ max required
  • -
-

When a character uses this template, the runtime selects specific values within each range.

-

Strict Mode

-

Strict templates enforce that characters using them can only have fields defined in the template:

-
template RecipeCard strict {
-    include SkilledWorker
-
-    recipe_name: string
-    difficulty: Difficulty
-    prep_time_minutes: 10..180
-    requires_starter: false
-}
-
-

Strict semantics:

-
    -
  • Characters using strict templates cannot add extra fields
  • -
  • All template fields must be present in the character
  • -
  • Enables type safety for well-defined schemas
  • -
  • Use for controlled domains (game cards, rigid categories)
  • -
-

Non-strict (default):

-
template Flexible {
-    base_stat: 10
-}
-
-character Custom from Flexible {
-    base_stat: 15      // Override
-    extra_field: 42    // Allowed in non-strict
-}
-
-

Strict:

-
template Rigid strict {
-    required_stat: 10
-}
-
-character Constrained from Rigid {
-    required_stat: 15  // OK: Override
-    extra_field: 42    // ERROR: Not allowed in strict template
-}
-
-

Resource Linking in Templates

-

Templates can link to behaviors and schedules (v0.2.0+):

-
template BakeryStaffMember
-    uses behaviors: DailyBakingRoutine, CustomerService
-    uses schedule: BakerySchedule
-{
-    include SkilledWorker
-
-    on_shift: true
-    orders_completed: 0..1000
-    current_station: 0..4
-}
-
-

Characters inheriting this template automatically get the linked behaviors and schedule.

-

Templates vs. Species

-
- - - - - -
AspectTemplates (from)Species (:)
SemanticsWhat entity hasWhat entity is
CardinalityMultiple inheritanceSingle inheritance
RangesAllowedNot allowed
Strict modeSupportedNot supported
Use caseCompositional traitsOntological identity
-
-

Example combining both:

-
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
-}
-
-

Validation Rules

-
    -
  1. Includes exist: All included templates must be defined
  2. -
  3. No circular includes: Cannot form cycles
  4. -
  5. Range validity: min ≤ max for all ranges
  6. -
  7. Strict enforcement: Strict templates reject extra fields in characters
  8. -
  9. Resource links valid: Behavior/schedule references must resolve
  10. -
-
-

Institutions

-

Institutions define organizations, groups, and systems—entities that function like characters but represent collectives rather than individuals.

-

Syntax

-
<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>* "}"
-
-

Basic Institution

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1450-03-15"
-    reputation: 0.85
-}
-
-

Institutions with Fields

-
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.
-    ---
-}
-
-

Resource Linking

-

Institutions can use behaviors and schedules:

-
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.
-    ---
-}
-
-

Prose Blocks

-

Institutions support rich narrative documentation:

-
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.
-    ---
-}
-
-

Use Cases

-
    -
  • Organizations: Guilds, companies, governments
  • -
  • Systems: Magical systems, physical laws, economies
  • -
  • Social structures: Families, tribes, castes
  • -
  • Abstract entities: Dream logic, fate, chaos
  • -
-

Validation Rules

-
    -
  1. Unique names: Institution names must be unique
  2. -
  3. Resource links valid: Behaviors/schedules must exist
  4. -
  5. Field types: All fields must have valid values
  6. -
-
-

Locations

-

Locations define places in your world—rooms, buildings, cities, landscapes, or abstract spaces.

-

Syntax

-
<location-decl> ::= "location" <identifier> <body>
-
-<body> ::= "{" <field>* <prose-block>* "}"
-
-

Basic Location

-
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.
-    ---
-}
-
-

Location with Structure

-
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.
-    ---
-}
-
-

Geographic Hierarchy

-

Locations can reference other locations:

-
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.
-    ---
-}
-
-

Location with State

-
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.
-    ---
-}
-
-

Use Cases

-
    -
  • Physical places: Cities, buildings, rooms
  • -
  • Geographic features: Mountains, rivers, forests
  • -
  • Abstract spaces: Dream realms, pocket dimensions
  • -
  • Game boards: Arenas, dungeons, maps
  • -
-

Validation Rules

-
    -
  1. Unique names: Location names must be unique
  2. -
  3. Field types: All fields must have valid values
  4. -
  5. References valid: Location references (like part_of) should resolve
  6. -
-
-

Species

-

Species define the fundamental ontological categories of beings. A species represents what an entity is at its core—human, dragon, sentient tree, animated playing card.

-

Syntax

-
<species-decl> ::= "species" <identifier> <includes-clause>? <body>
-
-<includes-clause> ::= "includes" <identifier> ("," <identifier>)*
-
-<body> ::= "{" <field>* <prose-block>* "}"
-
-

Basic Species

-
species Human {
-    lifespan: 70
-
-    ---description
-    Bipedal mammals with complex language and tool use.
-    Highly variable in cultures and capabilities.
-    ---
-}
-
-

Species with Includes

-

Species can include other species for composition:

-
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.
-    ---
-}
-
-

Field Resolution with Includes

-

When a species includes others, fields are merged in declaration order:

-
    -
  1. Base species (leftmost in includes)
  2. -
  3. Middle species
  4. -
  5. Rightmost species
  6. -
  7. Current species (highest priority)
  8. -
-

Example:

-
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)
-
-

Species vs. Templates

-
- - - - - -
AspectSpecies (:)Templates (from)
Question“What is it?”“What traits does it have?”
CardinalityOne per characterZero or more
Inheritanceincludes (species → species)Characters inherit from templates
VariationConcrete defaultsRanges allowed
Examplespecies Humantemplate Warrior
-
-

When to use species:

-
species Dragon {
-    lifespan: 1000
-    can_fly: true
-    breathes_fire: true
-}
-
-character Smaug: Dragon {
-    age: 850  // Smaug IS a Dragon
-}
-
-

When to use templates:

-
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
-}
-
-

Design Pattern: Prefer Composition Over Deep Hierarchies

-

Avoid:

-
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!
-
-

Prefer:

-
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 { ... }
-
-

Validation Rules

-
    -
  1. Unique names: Species names must be unique
  2. -
  3. No circular includes: Cannot form cycles
  4. -
  5. Includes exist: All included species must be defined
  6. -
  7. Field types: All fields must have valid values
  8. -
-
-

Enums

-

Enums define controlled vocabularies—fixed sets of named values. They enable type-safe categorization and validation.

-

Syntax

-
<enum-decl> ::= "enum" <identifier> "{" <variant>+ "}"
-
-<variant> ::= <identifier> ","?
-
-

Basic Enum

-
enum Size {
-    tiny,
-    small,
-    normal,
-    large,
-    huge
-}
-
-

Using Enums

-

Enums are used as field values throughout the system:

-
character Martha: Human {
-    skill_level: master     // References SkillLevel enum
-    specialty: sourdough    // References Specialty enum
-}
-
-

Common Enum Patterns

-

Emotional States:

-
enum EmotionalState {
-    curious,
-    frightened,
-    confused,
-    brave,
-    angry,
-    melancholy,
-    amused
-}
-
-

Card Suits:

-
enum CardSuit {
-    hearts,
-    diamonds,
-    clubs,
-    spades
-}
-
-enum CardRank {
-    two, three, four, five, six, seven, eight, nine, ten,
-    knave, queen, king
-}
-
-

Time States:

-
enum TimeState {
-    normal,
-    frozen,
-    reversed,
-    accelerated
-}
-
-

Government Types:

-
enum GovernmentType {
-    monarchy,
-    democracy,
-    anarchy,
-    tyranny,
-    oligarchy
-}
-
-enum GovernmentStyle {
-    absolute_tyranny,
-    benevolent_dictatorship,
-    constitutional_monarchy,
-    direct_democracy,
-    representative_democracy
-}
-
-

Calendar Enums (Configurable)

-

Define custom calendars for your world:

-
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
-}
-
-

Custom calendars:

-
enum EightSeasons {
-    deep_winter,
-    late_winter,
-    early_spring,
-    late_spring,
-    early_summer,
-    late_summer,
-    early_fall,
-    late_fall
-}
-
-

Validation Integration

-

Enums enable compile-time validation:

-
enum Size {
-    tiny, small, normal, large, huge
-}
-
-character Martha {
-    skill_level: medium  // ERROR: 'medium' not in SkillLevel enum
-}
-
-

Use Cases

-
    -
  • Controlled vocabularies: Prevent typos and invalid values
  • -
  • Schema constraints: Temporal systems, card decks, status types
  • -
  • Type safety: Catch errors at compile time
  • -
  • Documentation: Enumerate all valid options
  • -
-

Validation Rules

-
    -
  1. Unique enum names: Enum names must be unique
  2. -
  3. Unique variants: Variant names must be unique within the enum
  4. -
  5. Non-empty: Enums must have at least one variant
  6. -
  7. Valid identifiers: Variants must follow identifier rules
  8. -
-
-

Use Statements

-

Use statements import definitions from other files, enabling modular organization and code reuse.

-

Syntax

-
<use-decl> ::= "use" <use-path> <use-kind>
-
-<use-path> ::= <identifier> ("::" <identifier>)*
-
-<use-kind> ::= ";"                                   // Single import
-             | "::{" <identifier> ("," <identifier>)* "}" ";"  // Grouped import
-             | "::*" ";"                             // Wildcard import
-
-

Single Import

-
use schema::beings::Human;
-
-

Imports the Human species from schema/beings.sb.

-

Grouped Import

-
use schema::core_enums::{Size, EmotionalState};
-
-

Imports multiple items from the same module.

-

Wildcard Import

-
use schema::beings::*;
-
-

Imports all public items from schema/beings.sb.

-

Qualified Paths

-

Module structure:

-
examples/alice-in-wonderland/
-├─ schema/
-│   ├─ core_enums.sb
-│   ├─ templates.sb
-│   └─ beings.sb
-└─ world/
-    ├─ characters/
-    │   └─ alice.sb
-    └─ locations/
-        └─ wonderland_places.sb
-
-

In martha.sb:

-
use schema::core_enums::{SkillLevel, Specialty};
-use schema::templates::Baker;
-use schema::beings::Human;
-
-character Martha: Human from Baker {
-    skill_level: master
-    specialty: sourdough
-}
-
-

Path Resolution

-
    -
  1. Relative to file’s module path: Imports are resolved relative to the current file’s location
  2. -
  3. Module hierarchy: schema::beings maps to schema/beings.sb
  4. -
  5. Transitive imports: Imported modules can themselves import others
  6. -
-

Common Patterns

-

Schema organization:

-
// 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};
-
-

Template composition:

-
// In schema/templates.sb
-template SkilledWorker { ... }
-template Baker {
-    include SkilledWorker
-    ...
-}
-
-// In world/characters/martha.sb
-use schema::templates::Baker;
-
-

Cross-file references:

-
// In world/characters/martha.sb
-character Martha { ... }
-
-// In world/relationships/bakery.sb
-use world::characters::Martha;
-
-relationship MarthaAndJane {
-    Martha
-    Jane
-}
-
-

Validation Rules

-
    -
  1. Path exists: Imported paths must reference defined modules/items
  2. -
  3. No circular imports: Modules cannot form circular dependency chains
  4. -
  5. Valid identifiers: All path segments must be valid identifiers
  6. -
  7. Grouped import validity: All items in {} must exist
  8. -
-

Best Practices

-

1. Group related imports:

-
use schema::core_enums::{SkillLevel, Specialty, Confidence};
-use schema::beings::{Human, Cat};
-
-

2. Explicit over wildcard:

-
// Prefer:
-use schema::core_enums::{SkillLevel, Specialty};
-
-// Over:
-use schema::core_enums::*;  // Imports everything
-
-

3. Organize by hierarchy:

-
// Schema imports first
-use schema::core_enums::SkillLevel;
-use schema::templates::Baker;
-
-// Then world imports
-use world::characters::Martha;
-
-

4. Use qualified paths for clarity:

-
character Elena: Human from Baker, Apprentice {
-    // Human is species (from schema::beings)
-    // Baker, Apprentice are templates (from schema::templates)
-}
-
-
-

Cross-References

- - -
    -
  • Modularity: Use statements enable file organization
  • -
  • Composition: Templates provide trait-based composition
  • -
  • Type safety: Enums prevent invalid values
  • -
  • World-building: Locations and institutions model environments
  • -
  • Ontology: Species define entity essence
  • -
-

Expression Language

-

The Storybook expression language enables conditions, queries, and logic throughout the system. Expressions appear in life arc transitions, behavior tree guards, decorator conditions, and relationship queries. This chapter provides a complete reference for expression syntax and semantics.

-

What are Expressions?

-

Expressions are logical statements that evaluate to true or false. They combine:

-
    -
  • Literals: Numbers, strings, booleans
  • -
  • Identifiers: References to fields and entities
  • -
  • Comparisons: ==, !=, <, <=, >, >=
  • -
  • Logical operators: and, or, not
  • -
  • Field access: self.field, other.field
  • -
  • Quantifiers: forall, exists (for collections)
  • -
-

Syntax

-
<expression> ::= <literal>
-               | <identifier>
-               | <field-access>
-               | <comparison>
-               | <logical>
-               | <unary>
-               | <quantifier>
-               | "(" <expression> ")"
-
-<literal> ::= <int> | <float> | <string> | <bool>
-
-<identifier> ::= <simple-name>
-               | <qualified-path>
-
-<field-access> ::= <expression> "." <identifier>
-                 | "self" "." <identifier>
-                 | "other" "." <identifier>
-
-<comparison> ::= <expression> <comp-op> <expression>
-
-<comp-op> ::= "==" | "!=" | "<" | "<=" | ">" | ">="
-
-<logical> ::= <expression> "and" <expression>
-            | <expression> "or" <expression>
-
-<unary> ::= "not" <expression>
-          | "-" <expression>
-
-<quantifier> ::= ("forall" | "exists") <identifier> "in" <expression> ":" <expression>
-
-

Literals

-

Integer Literals

-
42
--7
-0
-1000
-
-

Float Literals

-
3.14
--0.5
-0.0
-100.25
-
-

String Literals

-
"Martha"
-"Sourdough takes patience."
-"active"
-
-

Strings are enclosed in double quotes. Escape sequences: \n, \t, \\, \".

-

Boolean Literals

-
true
-false
-
-

Identifiers

-

Identifiers reference fields or entities.

-

Simple Identifiers

-
health
-enemy_count
-is_ready
-
-

Qualified Paths

-
Martha.skill_level
-Character.emotional_state
-
-

Comparison Operators

-

Equality: ==

-

Tests if two values are equal.

-
name == "Martha"
-count == 5
-status == active
-
-

Type compatibility:

-
    -
  • Both operands must be the same type
  • -
  • Works with: int, float, string, bool, enum values
  • -
-

Inequality: !=

-

Tests if two values are not equal.

-
name != "Gregory"
-health != 0
-ready != true
-
-

Less Than: <

-

Tests if left operand is less than right.

-
health < 20
-age < 18
-distance < 10.0
-
-

Valid types: int, float

-

Less Than or Equal: <=

-
health <= 50
-count <= max_count
-
-

Greater Than: >

-
strength > 10
-bond > 0.5
-
-

Greater Than or Equal: >=

-
age >= 21
-score >= 100
-
-

Logical Operators

-

AND: and

-

Both operands must be true.

-
health < 50 and has_potion
-is_ready and not is_busy
-age >= 18 and age < 65
-
-

Evaluation: Short-circuit (if left is false, right is not evaluated)

-

OR: or

-

At least one operand must be true.

-
is_day or is_lit
-health < 20 or surrounded
-enemy_count == 0 or all_enemies_dead
-
-

Evaluation: Short-circuit (if left is true, right is not evaluated)

-

Operator Precedence

-

From highest to lowest:

-
    -
  1. Parentheses: (...)
  2. -
  3. Unary: not, -
  4. -
  5. Comparisons: ==, !=, <, <=, >, >=
  6. -
  7. AND: and
  8. -
  9. OR: or
  10. -
-

Examples:

-
not is_ready and is_awake
-// Equivalent to: (not is_ready) and is_awake
-
-health < 50 or is_poisoned and has_antidote
-// Equivalent to: (health < 50) or (is_poisoned and has_antidote)
-
-// Use parentheses for clarity:
-(health < 50 or is_poisoned) and has_antidote
-
-

Unary Operators

-

NOT: not

-

Inverts a boolean value.

-
not is_ready
-not (health < 20)
-not enemy_nearby and safe
-
-

Negation: -

-

Negates a numeric value.

-
-health
--10
--(max_value - current_value)
-
-

Field Access

-

Direct Field Access

-
health
-bond
-emotional_state
-
-

References a field on the current entity.

-

Dot Access

-
Martha.skill_level
-Character.emotional_state
-enemy.health
-
-

Access fields on other entities.

-

Self Access

-

In relationships and certain contexts, self refers to the current participant:

-
self.bond
-self.responsibility
-self.trust
-
-

Use case: Relationship transitions, symmetric queries

-

Other Access

-

In relationships, other refers to other participants:

-
other.bond
-other.aware_of_mentor
-other.respect
-
-

Use case: Relationship queries with perspective

-

Example in Life Arcs

-
life_arc RelationshipState {
-    state new {
-        on self.bond > 0.7 and other.bond > 0.7 -> stable
-    }
-
-    state stable {
-        on self.bond < 0.3 -> troubled
-        on other.bond < 0.3 -> troubled
-    }
-
-    state troubled {
-        on self.bond < 0.1 or other.bond < 0.1 -> broken
-    }
-
-    state broken {}
-}
-
-

Quantifiers

-

Quantifiers test conditions over collections.

-

ForAll: forall

-

Tests if a condition holds for all elements in a collection.

-
forall e in enemies: e.defeated
-forall item in inventory: item.weight < 10
-
-

Syntax:

-
forall <variable> in <collection>: <predicate>
-
-

Semantics:

-
    -
  • Returns true if predicate is true for every element
  • -
  • Returns true for empty collections (vacuously true)
  • -
-

Examples:

-
// All enemies defeated?
-forall enemy in enemies: enemy.health <= 0
-
-// All party members ready?
-forall member in party: member.is_ready
-
-// All doors locked?
-forall door in doors: door.is_locked
-
-

Exists: exists

-

Tests if a condition holds for at least one element.

-
exists e in enemies: e.is_hostile
-exists item in inventory: item.is_healing_potion
-
-

Syntax:

-
exists <variable> in <collection>: <predicate>
-
-

Semantics:

-
    -
  • Returns true if predicate is true for any element
  • -
  • Returns false for empty collections
  • -
-

Examples:

-
// Any enemy nearby?
-exists enemy in enemies: enemy.distance < 10
-
-// Any door unlocked?
-exists door in doors: not door.is_locked
-
-// Any ally wounded?
-exists ally in allies: ally.health < ally.max_health * 0.5
-
-

Nested Quantifiers

-

Quantifiers can nest:

-
forall team in teams: exists player in team: player.is_leader
-// Every team has at least one leader
-
-exists room in dungeon: forall enemy in room.enemies: enemy.defeated
-// At least one room has all enemies defeated
-
-

Usage in Context

-

Life Arc Transitions

-
life_arc CombatState {
-    state idle {
-        on enemy_count > 0 -> combat
-    }
-
-    state combat {
-        on health < 20 -> fleeing
-        on enemy_count == 0 -> victorious
-    }
-
-    state fleeing {
-        on distance_from_enemies > 100 -> safe
-    }
-
-    state victorious {
-        on celebration_complete -> idle
-    }
-
-    state safe {
-        on health >= 50 -> idle
-    }
-}
-
-

Behavior Tree Conditions

-
behavior GuardedAction {
-    if(health > 50 and has_weapon) {
-        AggressiveAttack
-    }
-}
-
-behavior ConditionalChoice {
-    choose tactics {
-        then melee {
-            if(distance < 5 and weapon_type == "sword")
-            MeleeAttack
-        }
-
-        then ranged {
-            if(distance >= 5 and has_arrows)
-            RangedAttack
-        }
-    }
-}
-
-

Behavior Tree Conditions

-
behavior SmartAI {
-    choose strategy {
-        then aggressive {
-            if(health > 70 and enemy_count < 3)
-            Attack
-        }
-
-        then defensive {
-            if(health < 30 or enemy_count >= 5)
-            Defend
-        }
-
-        then balanced {
-            if(health >= 30 and health <= 70)
-            TacticalManeuver
-        }
-    }
-}
-
-

Type System

-

Type Compatibility

-

Comparisons require compatible types:

-
- - - - - - - - - -
OperatorLeft TypeRight TypeValid?
==, !=intint
==, !=floatfloat
==, !=stringstring
==, !=boolbool
==, !=enumsame enum
==, !=intfloat
<, <=, >, >=intint
<, <=, >, >=floatfloat
<, <=, >, >=stringstring
-
-

Implicit Coercion

-

None. Storybook has no implicit type coercion. All comparisons must be between compatible types.

-

Error:

-
count == "5"  // Error: int vs string
-health < true  // Error: int vs bool
-
-

Correct:

-
count == 5
-health < 50
-
-

Special Keyword: is

-

The is keyword provides syntactic sugar for equality with enum values:

-
// Instead of:
-status == active
-
-// You can write:
-status is active
-
-

More examples:

-
name is "Martha"
-skill_level is master
-emotional_state is focused
-
-

This is purely syntactic—is and == are equivalent.

-

Complete Examples

-

Simple Conditions

-
health < 20
-enemy_nearby
-not is_ready
-count > 5
-
-

Complex Conditions

-
(health < 20 and not has_potion) or surrounded
-forall e in enemies: e.defeated
-exists item in inventory: item.is_healing_potion and item.quantity > 0
-
-

Life Arc with Complex Conditions

-
life_arc CharacterMood {
-    state content {
-        on health < 30 or hunger > 80 -> distressed
-        on social_interaction > 0.8 -> happy
-    }
-
-    state distressed {
-        on health >= 50 and hunger < 30 -> content
-        on (health < 10 or hunger > 95) and help_available -> desperate
-    }
-
-    state happy {
-        on social_interaction < 0.3 -> content
-        on received_bad_news -> distressed
-    }
-
-    state desperate {
-        on help_received -> distressed
-    }
-}
-
-

Behavior with Quantifiers

-
behavior SquadLeader {
-    choose leadership {
-        then regroup {
-            if(squad_has_wounded)
-            OrderRetreat
-        }
-
-        then advance {
-            if(squad_all_ready)
-            OrderAdvance
-        }
-
-        then hold_position {
-            if(not squad_all_ready)
-            OrderHold
-        }
-    }
-}
-
-

Relationship Query

-
life_arc FriendshipQuality {
-    state new_friends {
-        on self.bond > 0.7 and other.bond > 0.7 -> strong_bond
-        on self.trust < 0.3 or other.trust < 0.3 -> shaky
-    }
-
-    state strong_bond {
-        on self.bond < 0.5 -> weakening
-    }
-
-    state weakening {
-        on self.bond < 0.2 or other.bond < 0.2 -> ended
-        on self.bond > 0.7 and other.bond > 0.7 -> strong_bond
-    }
-
-    state shaky {
-        on self.trust > 0.6 and other.trust > 0.6 -> new_friends
-        on self.trust < 0.1 or other.trust < 0.1 -> ended
-    }
-
-    state ended {}
-}
-
-

Validation Rules

-
    -
  1. Type consistency: Both sides of comparison must be compatible types
  2. -
  3. Boolean context: Logical operators (and, or, not) require boolean operands
  4. -
  5. Field existence: Referenced fields must exist on the entity
  6. -
  7. Collection validity: Quantifiers require collection-typed expressions
  8. -
  9. Variable scope: Quantifier variables only valid within their predicate
  10. -
  11. No division by zero: Arithmetic operations must not divide by zero
  12. -
  13. Enum validity: Enum comparisons must reference defined enum values
  14. -
-

Best Practices

-

1. Use Parentheses for Clarity

-

Avoid:

-
health < 50 or is_poisoned and has_antidote
-
-

Prefer:

-
(health < 50 or is_poisoned) and has_antidote
-
-

2. Break Complex Conditions

-

Avoid:

-
on (health < 20 and not has_potion) or (surrounded and not has_escape) or (enemy_count > 10 and weapon_broken) -> desperate
-
-

Prefer:

-
state combat {
-    on health < 20 and not has_potion -> desperate
-    on surrounded and not has_escape -> desperate
-    on enemy_count > 10 and weapon_broken -> desperate
-}
-
-

3. Name Complex Conditions

-

For repeated complex conditions, consider using intermediate fields:

-

Instead of:

-
on health < (max_health * 0.2) and enemy_count > 5 -> flee
-
-

Consider:

-
// In character definition:
-critically_wounded: health < (max_health * 0.2)
-outnumbered: enemy_count > 5
-
-// In life arc:
-on critically_wounded and outnumbered -> flee
-
-

4. Use is for Enums

-

Prefer:

-
status is active
-emotional_state is focused
-
-

Over:

-
status == active
-emotional_state == focused
-
-

5. Quantifiers for Collections

-

Avoid:

-
// Manual checks for each element
-if enemy1.defeated and enemy2.defeated and enemy3.defeated
-
-

Prefer:

-
if forall enemy in enemies: enemy.defeated
-
-

Cross-References

- - -
    -
  • Type safety: Strong typing prevents type errors at compile time
  • -
  • Short-circuit evaluation: AND/OR operators optimize evaluation
  • -
  • Quantifiers: Enable expressive collection queries
  • -
  • Field access: Context-sensitive (self, other) for relationships
  • -
  • Boolean algebra: Standard logical operators with expected semantics
  • -
-

Values

-

Values are the fundamental data types in Storybook. Every field in a character, template, or other declaration contains a value. This chapter provides a complete reference for all supported value types.

-

Value Types Overview

-

Storybook supports 12 value types:

-
- - - - - - - - - - - - -
TypeExampleUse Case
Int42, -7Quantities, IDs, counts
Float3.14, -0.5Measurements, probabilities
String"Hello", "Martha"Text, names, descriptions
Booltrue, falseFlags, switches
Time14:30, 09:15:30Clock times, schedule blocks
Duration2h30m, 45sTime intervals
Range20..40, 0.5..1.0Template variation bounds
IdentifierMartha, items::swordReferences to other declarations
List[1, 2, 3], ["a", "b"]Collections
Object{x: 10, y: 20}Structured data
ProseBlock---tag content ---Long-form narrative
OverrideTemplateX with {...}Template instantiation with modifications
-
-

Integer

-

Signed 64-bit integers.

-

Syntax

-
<int> ::= ["-"] <digit>+
-<digit> ::= "0".."9"
-
-

Examples

-
character Hero {
-    age: 25
-    gold: 1500
-    reputation: -10
-}
-
-

Range

-
    -
  • Minimum: -9,223,372,036,854,775,808
  • -
  • Maximum: 9,223,372,036,854,775,807
  • -
-

Use Cases

-
    -
  • Counts (items, population)
  • -
  • Identifiers (IDs, keys)
  • -
  • Scores (reputation, alignment)
  • -
  • Whole quantities (gold pieces, HP)
  • -
-

Float

-

64-bit floating-point numbers (IEEE 754 double precision).

-

Syntax

-
<float> ::= ["-"] <digit>+ "." <digit>+
-          | ["-"] <digit>+ ("e" | "E") ["+"|"-"] <digit>+
-
-

Examples

-
character Wizard {
-    mana: 100.0
-    spell_power: 1.5
-    corruption: 0.03
-    precision: 1e-6
-}
-
-

Special Values

-
    -
  • No NaN or Infinity support (use validation to prevent)
  • -
  • Negative zero (-0.0) equals positive zero (0.0)
  • -
-

Use Cases

-
    -
  • Probabilities (0.0 to 1.0)
  • -
  • Percentages (0.0 to 100.0)
  • -
  • Measurements with precision
  • -
  • Ratios and scaling factors
  • -
-

String

-

UTF-8 encoded text enclosed in double quotes.

-

Syntax

-
<string> ::= '"' <string-char>* '"'
-<string-char> ::= <any-char-except-quote-or-backslash>
-                | <escape-sequence>
-<escape-sequence> ::= "\n" | "\r" | "\t" | "\\" | "\""
-
-

Escape Sequences

-
    -
  • \n - Newline
  • -
  • \r - Carriage return
  • -
  • \t - Tab
  • -
  • \\ - Backslash
  • -
  • \" - Double quote
  • -
-

Examples

-
character Martha {
-    name: "Martha Baker"
-    greeting: "Fresh from the oven!"
-    multiline: "Line 1\nLine 2\nLine 3"
-    quote: "She said, \"The bread is ready!\""
-}
-
-

Limitations

-
    -
  • No raw strings (r“…“) or multi-line literals
  • -
  • For long text, use prose blocks
  • -
  • Maximum length: Implementation-defined (typically several MB)
  • -
-

Use Cases

-
    -
  • Character names
  • -
  • Short descriptions
  • -
  • Dialogue snippets
  • -
  • Enum-like values (before proper enums)
  • -
-

Boolean

-

Logical true/false values.

-

Syntax

-
<bool> ::= "true" | "false"
-
-

Examples

-
character Guard {
-    is_awake: true
-    has_seen_player: false
-    loyal_to_king: true
-}
-
-

Use Cases

-
    -
  • Feature flags (can_fly, is_hostile)
  • -
  • State tracking (door_open, quest_complete)
  • -
  • Conditions (is_friendly, accepts_bribes)
  • -
-

Time

-

Clock time in 24-hour format.

-

Syntax

-
<time> ::= <hour> ":" <minute>
-         | <hour> ":" <minute> ":" <second>
-
-<hour> ::= "0".."23"
-<minute> ::= "0".."59"
-<second> ::= "0".."59"
-
-

Examples

-
schedule BakerySchedule {
-    block {
-        start: 06:00
-        end: 08:30
-        action: baking::prepare_dough
-    }
-
-    block {
-        start: 14:30:15  // With seconds
-        end: 15:00:00
-        action: baking::afternoon_cleanup
-    }
-}
-
-character EarlyRiser {
-    wake_time: 05:30
-    bedtime: 21:00
-}
-
-

Validation

-
    -
  • Hours: 0-23 (24-hour format)
  • -
  • Minutes: 0-59
  • -
  • Seconds: 0-59 (optional)
  • -
  • No AM/PM notation
  • -
  • No timezone support (context-dependent)
  • -
-

Use Cases

-
    -
  • Schedule blocks (see Schedules)
  • -
  • Character routines
  • -
  • Event timing
  • -
  • Time-based conditions
  • -
-

Duration

-

Time intervals with hour/minute/second components.

-

Syntax

-
<duration> ::= <duration-component>+
-
-<duration-component> ::= <number> ("h" | "m" | "s")
-
-<number> ::= <digit>+
-
-

Examples

-
character Traveler {
-    journey_time: 2h30m
-    rest_needed: 8h
-    sprint_duration: 45s
-}
-
-behavior TimedAction {
-    choose {
-        timeout(5m) {
-            CompleteObjective
-        }
-
-        cooldown(30s) {
-            UseSpecialAbility
-        }
-    }
-}
-
-

Components

-
    -
  • h - Hours
  • -
  • m - Minutes
  • -
  • s - Seconds
  • -
-

Can combine multiple components: 1h30m15s

-

Validation

-
    -
  • All components non-negative
  • -
  • No fractional components (1.5h not allowed; use 1h30m)
  • -
  • Can specify same unit multiple times: 90m = 1h30m (normalized)
  • -
-

Use Cases

-
    -
  • Behavior tree timeouts/cooldowns
  • -
  • Travel times
  • -
  • Cooldown periods
  • -
  • Event durations
  • -
-

Range

-

Numeric range with inclusive bounds (for templates only).

-

Syntax

-
<range> ::= <value> ".." <value>
-
-

Both bounds must be the same type (both int or both float).

-

Examples

-
template Villager {
-    age: 18..65
-    wealth: 10..100
-    height: 150.0..190.0  // Float range
-}
-
-template RandomEvent {
-    probability: 0.0..1.0
-    damage: 5..20
-}
-
-

Semantics

-
    -
  • Templates only: Ranges are only valid in templates
  • -
  • Instantiation: When a template is used, a specific value within the range is selected
  • -
  • Inclusive bounds: Both min and max are included
  • -
  • Order matters: min must be ≤ max
  • -
-

Validation

-
    -
  • Both bounds same type
  • -
  • minmax
  • -
  • Cannot use ranges in character/species/etc. (only templates)
  • -
-

Use Cases

-
    -
  • Template variation
  • -
  • Procedural generation
  • -
  • Random NPC attributes
  • -
  • Loot table ranges
  • -
-

Identifier

-

Reference to another declaration by qualified path.

-

Syntax

-
<identifier> ::= <simple-name>
-               | <qualified-path>
-
-<simple-name> ::= <ident>
-
-<qualified-path> ::= <ident> ("::" <ident>)+
-
-

Examples

-
character Martha: Human {  // Species reference
-    // ...
-}
-
-character Elena from Apprentice {  // Template reference
-    // ...
-}
-
-character Guard {
-    uses behaviors: [
-        { tree: guards::patrol }  // Behavior reference
-    ]
-    uses schedule: DailyRoutine  // Schedule reference
-}
-
-relationship Partnership {
-    Martha  // Character reference
-    Jane  // Character reference
-}
-
-

Resolution

-
    -
  • Unqualified: Searches current module, then imports
  • -
  • Qualified: module::submodule::Name
  • -
  • Validation: Compiler ensures all references resolve
  • -
-

Use Cases

-
    -
  • Species typing (: Species)
  • -
  • Template inheritance (from Template)
  • -
  • Behavior tree references
  • -
  • Schedule references
  • -
  • Relationship participants
  • -
  • Cross-references
  • -
-

List

-

Ordered collection of values.

-

Syntax

-
<list> ::= "[" "]"
-         | "[" <value> ("," <value>)* "]"
-
-

Examples

-
character Mage {
-    known_spells: ["Fireball", "Lightning", "Shield"]
-    spell_levels: [3, 5, 2]
-    party_members: [Martha, Jane, Elena]
-}
-
-character Traveler {
-    inventory: [
-        {item: "Sword", damage: 10},
-        {item: "Potion", healing: 50},
-        {item: "Key", opens: "TowerDoor"}
-    ]
-}
-
-

Type Constraints

-
    -
  • Homogeneous preferred: All elements should be the same type
  • -
  • Heterogeneous allowed: Mixed types permitted but discouraged
  • -
  • Empty lists: [] is valid
  • -
-

Operations

-

Lists are immutable at declaration time. Runtime list operations depend on the execution environment.

-

Use Cases

-
    -
  • Collections (inventory, spells, party members)
  • -
  • References (multiple behaviors, schedules, participants)
  • -
  • Enum-like sets (before proper enums)
  • -
-

Object

-

Structured data with named fields.

-

Syntax

-
<object> ::= "{" "}"
-           | "{" <field> ("," <field>)* "}"
-
-<field> ::= <identifier> ":" <value>
-
-

Examples

-
character Hero {
-    position: {x: 100, y: 200}
-
-    stats: {
-        strength: 15,
-        dexterity: 12,
-        intelligence: 10
-    }
-
-    equipment: {
-        weapon: {
-            name: "Longsword",
-            damage: 10,
-            enchantment: "Fire"
-        },
-        armor: {
-            name: "Plate Mail",
-            defense: 8
-        }
-    }
-}
-
-

Nesting

-

Objects can be nested arbitrarily deep:

-
character Complex {
-    deep: {
-        level1: {
-            level2: {
-                level3: {
-                    value: 42
-                }
-            }
-        }
-    }
-}
-
-

Use Cases

-
    -
  • Structured data (position, stats)
  • -
  • Nested configurations
  • -
  • Inline data structures
  • -
  • Complex field values
  • -
-

Prose Blocks

-

Long-form narrative text with semantic tags.

-

Syntax

-
<prose-block> ::= "---" <tag> <content> "---"
-
-<tag> ::= <identifier>
-
-<content> ::= <any-text-except-triple-dash>
-
-

Common Tags

-
    -
  • ---description: General description
  • -
  • ---backstory: Character history
  • -
  • ---appearance: Physical description
  • -
  • ---personality: Behavioral traits
  • -
  • ---motivation: Goals and desires
  • -
  • ---notes: Meta-commentary
  • -
  • ---ecology: Species habitat/behavior
  • -
  • ---culture: Social structures
  • -
  • ---narrative: Story context
  • -
-

Examples

-
character Martha {
-    age: 34
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age
-    twelve. She now runs the most popular bakery in town, known
-    for her sourdough bread and unwavering quality standards.
-    ---
-
-    ---personality
-    Meticulous and patient, with an unwavering commitment to
-    quality. Tough but fair with her staff, and deeply loyal
-    to the customers who have supported her bakery for years.
-    ---
-}
-
-species Dragon {
-    lifespan: 1000
-
-    ---ecology
-    Dragons nest in high mountain caves and emerge every few decades
-    to hunt large prey. They hoard treasure as a mating display.
-    ---
-}
-
-

Formatting

-
    -
  • Leading/trailing whitespace is preserved
  • -
  • No escape sequences needed
  • -
  • Can contain any characters except --- on its own line
  • -
  • Indentation is significant for readability but not semantics
  • -
-

Multiple Prose Blocks

-

A single declaration can have multiple prose blocks with different tags:

-
character Gandalf {
-    ---appearance
-    An old man with a long gray beard, pointed hat, and staff.
-    ---
-
-    ---backstory
-    One of the Istari sent to Middle-earth to contest Sauron.
-    ---
-
-    ---personality
-    Patient and wise, but with a mischievous streak.
-    ---
-}
-
-

Use Cases

-
    -
  • Character backstories
  • -
  • Species descriptions
  • -
  • World-building flavor text
  • -
  • Design notes
  • -
  • Narrative context
  • -
-

Override

-

Template instantiation with field modifications.

-

Syntax

-
<override> ::= <qualified-path> "with" "{" <override-op>* "}"
-
-<override-op> ::= <identifier> ":" <value>           // Set
-                | "remove" <identifier>              // Remove
-                | "append" <identifier> ":" <value>  // Append (for lists)
-
-

Examples

-

Basic Override

-
template BaseWarrior {
-    strength: 10
-    dexterity: 8
-    weapon: "Sword"
-}
-
-character StrongWarrior {
-    stats: BaseWarrior with {
-        strength: 15  // Override strength
-    }
-}
-
-

Remove Fields

-
template FullEquipment {
-    helmet: "Iron"
-    chest: "Plate"
-    legs: "Mail"
-    boots: "Leather"
-}
-
-character LightFighter {
-    equipment: FullEquipment with {
-        remove helmet
-        remove chest
-    }
-}
-
-

Append to Lists

-
template BasicSpells {
-    spells: ["Fireball", "Shield"]
-}
-
-character AdvancedMage {
-    magic: BasicSpells with {
-        append spells: "Teleport"
-        append spells: "Lightning"
-    }
-    // Result: ["Fireball", "Shield", "Teleport", "Lightning"]
-}
-
-

Complex Override

-
template RogueTemplate {
-    stealth: 15
-    lockpicking: 12
-    backstab_damage: 20
-    equipment: ["Dagger", "Lockpicks"]
-}
-
-character MasterThief {
-    abilities: RogueTemplate with {
-        stealth: 20              // Set
-        remove backstab_damage   // Remove
-        append equipment: "Grappling Hook"  // Append
-    }
-}
-
-

Operations

-

set (default)

-

Replace a field’s value:

-
field_name: new_value
-
-

remove

-

Delete a field from the template:

-
remove field_name
-
-

append

-

Add to a list field (field must be a list):

-
append field_name: value_to_add
-
-

Validation

-
    -
  • Base template must exist
  • -
  • Overridden fields must exist in template
  • -
  • Removed fields must exist in template
  • -
  • Appended fields must be lists
  • -
  • Type compatibility enforced
  • -
-

Use Cases

-
    -
  • Customizing template instances
  • -
  • Procedural character generation
  • -
  • Variant creation
  • -
  • Data composition
  • -
-

Type Coercion

-

Storybook has no implicit type coercion. All type conversions must be explicit.

-

Not allowed:

-
character Wrong {
-    count: "42"  // Error: expected int, got string
-    flag: 1      // Error: expected bool, got int
-}
-
-

Correct:

-
character Right {
-    count: 42
-    flag: true
-}
-
-

Null and Optional

-

Storybook does not have null. For optional values, use:

-
    -
  1. -

    Template ranges with 0 as lower bound:

    -
    template MaybeWeapon {
    -    weapon_count: 0..5
    -}
    -
    -
  2. -
  3. -

    Boolean flags:

    -
    character Guard {
    -    has_weapon: false
    -}
    -
    -
  4. -
  5. -

    Empty lists:

    -
    character Unarmed {
    -    weapons: []
    -}
    -
    -
  6. -
-

Summary Table

-
- - - - - - - - - - - - -
TypeMutable?Comparable?Valid in Templates?Notes
IntNoYesYes64-bit signed
FloatNoYesYes64-bit IEEE 754
StringNoYesYesUTF-8
BoolNoYesYestrue/false
TimeNoYesNoHH:MM or HH:MM:SS
DurationNoYesNoCompounds (2h30m)
RangeNoNoYes (only)Template variation
IdentifierNoYesYesDeclaration reference
ListNoYesYesOrdered collection
ObjectNoYesYesNamed fields
ProseBlockNoNoYesNarrative text
OverrideNoNoYesTemplate modification
-
-

Cross-References

- - -
    -
  • Immutability: All values are immutable at declaration time
  • -
  • Type safety: Strong static typing with no implicit coercion
  • -
  • Structural equivalence: Objects/lists compared by structure, not identity
  • -
  • Prose as data: Narrative text is first-class data, not comments
  • -
-

Validation Rules

-

The Storybook compiler performs multi-layered validation to catch errors before runtime. This chapter documents all validation rules, organized by declaration type, along with the error messages you can expect and how to fix them.

-

Validation Layers

-

Storybook validation happens in four stages:

-
    -
  1. Lexical: Tokenization of raw text (invalid characters, malformed literals)
  2. -
  3. Syntactic: Grammar structure (missing braces, wrong keyword order)
  4. -
  5. Semantic: Cross-reference resolution, type checking, field merging
  6. -
  7. Domain: Narrative-specific constraints (bond ranges, schedule overlaps)
  8. -
-

Errors at earlier stages prevent later stages from running.

-

Character Validation

-

Required Rules

-
- - - - - - - - -
RuleDescriptionSeverity
Unique nameCharacter names must be unique within their moduleError
Species existsIf : Species is used, the species must be definedError
Templates existAll templates in from clause must be definedError
No circular inheritanceTemplate chains cannot form cyclesError
Field type consistencyField values must match expected typesError
Behavior trees existAll uses behaviors references must resolveError
Schedules existAll uses schedule references must resolveError
Prose tag uniquenessEach prose tag can appear at most once per characterError
-
-

Examples

-

Species not found:

-
character Martha: Hobbit {  // Error: species 'Hobbit' not defined
-    age: 34
-}
-
-

Fix: Define the species or correct the reference:

-
species Hobbit {
-    lifespan: 130
-}
-
-character Martha: Hobbit {
-    age: 34
-}
-
-

Duplicate character name:

-
character Martha { age: 34 }
-character Martha { age: 36 }  // Error: duplicate character name 'Martha'
-
-

Template Validation

-
- - - - - - - -
RuleDescriptionSeverity
Unique nameTemplate names must be unique within their moduleError
Includes existAll included templates must be definedError
No circular includesInclude chains cannot form cyclesError
Range validityRange bounds must satisfy min <= maxError
Range type matchBoth bounds of a range must be the same typeError
Strict enforcementCharacters using strict templates cannot add extra fieldsError
Resource links validBehavior/schedule references must resolveError
-
-

Examples

-

Invalid range:

-
template BadRange {
-    age: 65..18  // Error: range min (65) must be <= max (18)
-}
-
-

Strict template violation:

-
template Rigid strict {
-    required_stat: 10
-}
-
-character Constrained from Rigid {
-    required_stat: 15
-    extra_field: 42    // Error: field 'extra_field' not allowed by strict template 'Rigid'
-}
-
-

Behavior Tree Validation

-
- - - - - - - - - -
RuleDescriptionSeverity
At least one nodeBehavior body must contain at least one nodeError
Composite childrenchoose and then require at least one childError
Decorator childDecorators require exactly one childError
Subtree existsinclude must reference a defined behaviorError
Expression validityCondition expressions must be well-formedError
Duration formatDecorator durations must be valid (e.g., 5s, 10m)Error
Repeat count validrepeat N requires N >= 0Error
Repeat range validrepeat min..max requires 0 <= min <= maxError
Retry count validretry N requires N >= 1Error
-
-

Examples

-

Empty composite:

-
behavior Empty {
-    choose options {
-        // Error: 'choose' requires at least one child
-    }
-}
-
-

Invalid subtree reference:

-
behavior Main {
-    include NonExistentBehavior  // Error: behavior 'NonExistentBehavior' not defined
-}
-
-

Life Arc Validation

-
- - - - - - -
RuleDescriptionSeverity
At least one stateLife arc must contain at least one stateError
Unique state namesState names must be unique within the life arcError
Valid transitionsTransition targets must reference defined statesError
Expression validityTransition conditions must be well-formedError
Field targets validOn-enter field references must resolveError
Reachable statesAll states should be reachable from initial stateWarning
-
-

Examples

-

Invalid transition target:

-
life_arc Broken {
-    state active {
-        on timer_expired -> nonexistent  // Error: state 'nonexistent' not defined
-    }
-}
-
-

Unreachable state (warning):

-
life_arc HasOrphan {
-    state start {
-        on ready -> middle
-    }
-
-    state middle {
-        on done -> end
-    }
-
-    state orphan {}  // Warning: state 'orphan' is not reachable
-
-    state end {}
-}
-
-

Schedule Validation

-
- - - - - - - -
RuleDescriptionSeverity
Time formatTimes must be valid HH:MM or HH:MM:SSError
Extends existsBase schedule must be definedError
No circular extendsSchedule chains cannot form cyclesError
Named blocks uniqueBlock names must be unique within a scheduleError
Action references validAction references must resolve to defined behaviorsError
Constraint values validTemporal constraint values must reference defined enumsError
Recurrence names uniqueRecurrence names must be unique within a scheduleError
-
-

Examples

-

Invalid time format:

-
schedule Bad {
-    block work {
-        25:00 - 17:00  // Error: invalid hour '25'
-        action: work
-    }
-}
-
-

Circular extends:

-
schedule A extends B { }
-schedule B extends A { }  // Error: circular schedule extension detected
-
-

Relationship Validation

-
- - - - -
RuleDescriptionSeverity
At least two participantsRelationships require >= 2 participantsError
Participants existAll participant names must reference defined entitiesError
Unique participantsEach participant appears at most onceError
Field type consistencyFields must have valid value typesError
-
-

Examples

-

Too few participants:

-
relationship Lonely {
-    Martha  // Error: relationship requires at least 2 participants
-    bond: 0.5
-}
-
-

Species Validation

-
- - - - - -
RuleDescriptionSeverity
Unique nameSpecies names must be unique within their moduleError
No circular includesInclude chains cannot form cyclesError
Includes existAll included species must be definedError
Field type consistencyFields must have valid valuesError
Prose tag uniquenessEach prose tag can appear at most onceError
-
-

Enum Validation

-
- - - - -
RuleDescriptionSeverity
Unique enum nameEnum names must be unique within their moduleError
Unique variantsVariant names must be unique within the enumError
Non-emptyEnums must have at least one variantError
Valid identifiersVariants must follow identifier rulesError
-
-

Examples

-

Duplicate variant:

-
enum Size {
-    tiny,
-    small,
-    small,  // Error: duplicate variant 'small' in enum 'Size'
-    large
-}
-
-

Institution and Location Validation

-
- - - -
RuleDescriptionSeverity
Unique nameNames must be unique within their moduleError
Resource links validBehavior/schedule references must resolveError
Field type consistencyFields must have valid valuesError
-
-

Expression Validation

-

Expressions are validated wherever they appear (life arc transitions, behavior tree conditions, if decorators).

-
- - - - - - -
RuleDescriptionSeverity
Type consistencyBoth sides of comparison must have compatible typesError
Boolean contextLogical operators require boolean operandsError
Field existenceReferenced fields must exist on the entityError
Collection validityQuantifiers require collection-typed expressionsError
Variable scopeQuantifier variables only valid within their predicateError
Enum validityEnum comparisons must reference defined valuesError
-
-

Examples

-

Type mismatch:

-
life_arc TypeError {
-    state checking {
-        on count == "five" -> done  // Error: cannot compare int with string
-    }
-
-    state done {}
-}
-
-

Use Statement Validation

-
- - - - -
RuleDescriptionSeverity
Path existsImported paths must reference defined modules/itemsError
No circular importsModules cannot form circular dependency chainsError
Valid identifiersAll path segments must be valid identifiersError
Grouped import validityAll items in {} must exist in the target moduleError
-
-

Examples

-

Missing import:

-
use schema::nonexistent::Thing;  // Error: module 'schema::nonexistent' not found
-
-

Cross-File Validation

-

When resolving across multiple .sb files, the compiler performs additional checks:

-
- - - -
RuleDescriptionSeverity
All references resolveCross-file references must find their targetsError
No naming conflictsDeclarations must not collide across files in the same moduleError
Import visibilityOnly public declarations can be importedError
-
-

Common Error Patterns

-

Missing Definitions

-

The most common error is referencing something that does not exist:

-
character Martha: Human from Baker {
-    specialty: sourdough
-}
-
-

If Human, Baker, or the sourdough enum variant are not defined or imported, the compiler will report an error. Fix by adding the appropriate use statements:

-
use schema::core_enums::{SkillLevel, Specialty};
-use schema::templates::Baker;
-use schema::beings::Human;
-
-character Martha: Human from Baker {
-    specialty: sourdough
-}
-
-

Circular Dependencies

-

Circular references are rejected at every level:

-
    -
  • Templates including each other
  • -
  • Species including each other
  • -
  • Schedules extending each other
  • -
  • Modules importing each other
  • -
-

Break cycles by restructuring into a hierarchy or extracting shared parts into a common module.

-

Type Mismatches

-

Storybook has no implicit type coercion. Ensure values match their expected types:

-
// Wrong:
-character Bad {
-    age: "twenty"  // Error: expected int, got string
-    is_ready: 1    // Error: expected bool, got int
-}
-
-// Correct:
-character Good {
-    age: 20
-    is_ready: true
-}
-
-

Validation Summary

-
- - - - - - - - - - - -
DeclarationKey Constraints
CharacterUnique name, valid species/templates, no circular inheritance
TemplateUnique name, valid includes, valid ranges, strict enforcement
BehaviorNon-empty, valid composites, valid decorators, valid subtrees
Life ArcNon-empty, unique states, valid transitions, reachable states
ScheduleValid times, valid extends chain, unique block names
Relationship>= 2 participants, valid references
SpeciesUnique name, valid includes, no cycles
EnumUnique name, unique variants, non-empty
InstitutionUnique name, valid resource links
LocationUnique name, valid field types
UseValid paths, no circular imports
-
-

Cross-References

- -

Design Patterns

-

This chapter presents proven patterns for structuring Storybook projects. These patterns have emerged from building complex narrative simulations and represent best practices for maintainability, reuse, and clarity.

-

Behavior Tree Patterns

-

Priority Fallback Chain

-

Use a selector to try increasingly desperate options:

-
behavior Survival {
-    choose survival_priority {
-        then optimal {
-            if(health > 70 and has_supplies)
-            ProceedNormally
-        }
-
-        then cautious {
-            if(health > 30)
-            ProceedCarefully
-        }
-
-        then desperate {
-            if(health > 10)
-            SeekHelp
-        }
-
-        LastResortPanic
-    }
-}
-
-

The tree naturally degrades: first tries the best option, then falls back through progressively worse alternatives.

-

Conditional Behavior Switching

-

Use guards at the top level to switch between behavioral modes:

-
behavior ModeSwitcher {
-    choose mode {
-        if(is_combat_mode) {
-            include CombatBehavior
-        }
-
-        if(is_exploration_mode) {
-            include ExplorationBehavior
-        }
-
-        if(is_social_mode) {
-            include SocialBehavior
-        }
-
-        include IdleBehavior
-    }
-}
-
-

Composite Subtree Pattern

-

Break complex behaviors into focused, reusable subtrees:

-
// Atomic subtrees
-behavior Navigate { then nav { PlanPath, FollowPath } }
-behavior Interact { then talk { Approach, Greet, Converse } }
-behavior Trade { then exchange { ShowGoods, Negotiate, Exchange } }
-
-// Composed behavior
-behavior Merchant_AI {
-    choose activity {
-        then serve_customer {
-            if(customer_present)
-            include Interact
-            include Trade
-        }
-
-        then travel_to_market {
-            if(is_market_day)
-            include Navigate
-        }
-
-        Idle
-    }
-}
-
-

Repeating Patrol with Interrupts

-

Use a repeating patrol that can be interrupted by higher-priority events:

-
character Guard {
-    uses behaviors: [
-        {
-            tree: GuardCombat
-            when: threat_detected
-            priority: high
-        },
-        {
-            tree: GuardPatrol
-            priority: normal
-        }
-    ]
-}
-
-behavior GuardPatrol {
-    repeat {
-        then patrol_loop {
-            MoveTo(destination: "Waypoint1")
-            WaitAndScan(duration: 5s)
-            MoveTo(destination: "Waypoint2")
-            WaitAndScan(duration: 5s)
-        }
-    }
-}
-
-

The combat behavior preempts patrol when threats appear, then patrol resumes.

-

Character Architecture Patterns

-

Species + Templates Composition

-

Use species for identity and templates for capabilities:

-
// Species: What they ARE
-species Human { lifespan: 70 }
-species Elf { lifespan: 1000 }
-
-// Templates: What they HAVE
-template Warrior { strength: 10..20, weapon_skill: 0.5..1.0 }
-template Scholar { intelligence: 15..20, books_read: 50..500 }
-template Leader { charisma: 12..18, followers: 5..50 }
-
-// Characters: Combine both
-character Aragorn: Human from Warrior, Leader {
-    strength: 18
-    charisma: 17
-}
-
-character Elrond: Elf from Scholar, Leader {
-    intelligence: 20
-    charisma: 18
-}
-
-

Strict Templates for Schema Enforcement

-

Use strict templates when you need controlled, uniform entities:

-
template RecipeCard strict {
-    recipe_name: string
-    difficulty: Difficulty
-    prep_time_minutes: 10..180
-}
-
-// This works:
-character SourdoughRecipe from RecipeCard {
-    recipe_name: "Classic Sourdough"
-    difficulty: intermediate
-    prep_time_minutes: 120
-}
-
-// This would error (extra field not allowed):
-// character BadRecipe from RecipeCard {
-//     recipe_name: "Mystery Bread"
-//     difficulty: easy
-//     favorite_color: "blue"  // Error!
-// }
-
-

Template Inheritance Chains

-

Build template hierarchies for progressive specialization:

-
template Worker {
-    skill_level: 0.0..1.0
-    wage: 10..50
-}
-
-template SkilledWorker {
-    include Worker
-    specialization: "general"
-    tool_proficiency: 0.5..1.0
-}
-
-template MasterCraftsman {
-    include SkilledWorker
-    can_teach: true
-    reputation: 0.7..1.0
-}
-
-

Relationship Patterns

-

Bidirectional Perspective

-

Model relationships where each side sees things differently:

-
relationship MentorApprentice {
-    Master as mentor self {
-        patience: 0.7
-        investment_in_student: 0.9
-    } other {
-        sees_potential: 0.8
-        frustration_level: 0.3
-    }
-
-    Student as apprentice self {
-        dedication: 0.8
-        overwhelmed: 0.4
-    } other {
-        respect: 0.95
-        desire_to_impress: 0.9
-    }
-
-    bond: 0.75
-    years_together: 3
-}
-
-

Power Dynamic Pattern

-

Model unequal power relationships explicitly:

-
relationship Vassalage {
-    King as lord self {
-        authority: 1.0
-        grants: "protection"
-    } other {
-        trusts_vassal: 0.6
-    }
-
-    Knight as vassal self {
-        loyalty: 0.9
-        ambition: 0.4
-    } other {
-        respects_lord: 0.8
-        fears_lord: 0.3
-    }
-
-    bond: 0.7
-}
-
-

Relationship Network

-

Build social graphs with multiple overlapping relationships:

-
// Family
-relationship BakerMarriage { Martha as spouse, David as spouse, bond: 0.9 }
-relationship BakerParenting { Martha as parent, Tommy as child, bond: 0.95 }
-
-// Professional
-relationship BakerEmployment { Martha as employer, Elena as employee, bond: 0.8 }
-relationship GuildMembership { Martha as member, BakersGuild as org }
-
-// Social
-relationship BakerFriendship { Martha, Neighbor, bond: 0.6 }
-
-

Schedule Patterns

-

Base Schedule with Specializations

-
schedule BaseWorker {
-    block work { 09:00 - 17:00, action: work::standard }
-    block lunch { 12:00 - 13:00, action: social::lunch }
-}
-
-schedule EarlyBird extends BaseWorker {
-    block work { 05:00 - 13:00, action: work::early_shift }
-    block lunch { 11:00 - 12:00, action: social::lunch }
-}
-
-schedule NightOwl extends BaseWorker {
-    block work { 14:00 - 22:00, action: work::late_shift }
-    block lunch { 18:00 - 19:00, action: social::dinner }
-}
-
-

Seasonal Variation

-
schedule FarmSchedule {
-    block spring_work {
-        06:00 - 18:00
-        action: farming::plant
-        on season spring
-    }
-
-    block summer_work {
-        05:00 - 20:00
-        action: farming::tend
-        on season summer
-    }
-
-    block fall_work {
-        06:00 - 20:00
-        action: farming::harvest
-        on season fall
-    }
-
-    block winter_work {
-        08:00 - 16:00
-        action: farming::maintain
-        on season winter
-    }
-}
-
-

Life Arc Patterns

-

Progressive Development

-
life_arc CareerProgression {
-    state novice {
-        on enter { Character.title: "Apprentice" }
-        on experience > 100 -> intermediate
-    }
-
-    state intermediate {
-        on enter { Character.title: "Journeyman" }
-        on experience > 500 -> expert
-    }
-
-    state expert {
-        on enter { Character.title: "Master", Character.can_teach: true }
-    }
-}
-
-

Emotional State Machine

-
life_arc MoodSystem {
-    state neutral {
-        on provoked -> angry
-        on complimented -> happy
-        on tired -> sleepy
-    }
-
-    state angry {
-        on enter { Character.aggression: 0.9 }
-        on calmed_down -> neutral
-        on escalated -> furious
-    }
-
-    state furious {
-        on enter { Character.aggression: 1.0 }
-        on timeout_elapsed -> angry
-    }
-
-    state happy {
-        on enter { Character.gives_discounts: true }
-        on insulted -> neutral
-    }
-
-    state sleepy {
-        on enter { Character.responsiveness: 0.2 }
-        on woke_up -> neutral
-    }
-}
-
-

Project Organization Patterns

-

Schema / World Separation

-

Keep type definitions separate from instance data:

-
my-project/
-  schema/           # Types and templates (reusable)
-    core_enums.sb
-    templates.sb
-    beings.sb
-  world/            # Instances (specific to this story)
-    characters/
-    behaviors/
-    relationships/
-    locations/
-
-

Module per Domain

-

Group related declarations together:

-
world/
-  characters/
-    heroes.sb       # All hero characters
-    villains.sb     # All villain characters
-    npcs.sb         # Background characters
-  behaviors/
-    combat.sb       # Combat behaviors
-    social.sb       # Social behaviors
-    exploration.sb  # Exploration behaviors
-
-

Anti-Patterns to Avoid

-

Deep nesting: More than 4-5 levels of behavior tree nesting is hard to read. Use include to flatten.

-

God behaviors: One massive behavior tree doing everything. Break it into focused subtrees.

-

Deep species hierarchies: More than 2-3 levels of species includes is rarely needed. Use templates for variation.

-

Duplicated logic: If two behaviors share logic, extract it into a shared subtree.

-

Unnamed nodes: Always label composite nodes in behavior trees for readability.

-

Cross-References

- -

The SBIR Binary Format

-

SBIR (Storybook Intermediate Representation) is the compiled binary format produced by the Storybook compiler. It transforms human-readable .sb files into an optimized, machine-consumable format for simulation runtimes.

-

Compilation Pipeline

-
.sb files → Lexer → Parser → AST → Resolver → SBIR Binary
-
-
    -
  1. Lexer: Tokenizes raw text into tokens
  2. -
  3. Parser: Builds an Abstract Syntax Tree (AST) from tokens
  4. -
  5. Resolver: Validates, resolves cross-references, merges templates, and produces SBIR
  6. -
-

What SBIR Contains

-

SBIR represents the fully resolved state of a Storybook project:

-
    -
  • Characters: All fields resolved (species + templates merged, overrides applied)
  • -
  • Behaviors: Behavior trees with all subtree references inlined
  • -
  • Life Arcs: State machines with validated transitions
  • -
  • Schedules: Time blocks with resolved action references
  • -
  • Relationships: Participants with resolved entity references
  • -
  • Institutions: Fully resolved field sets
  • -
  • Locations: Fully resolved field sets
  • -
  • Species: Fully resolved inheritance chains
  • -
  • Enums: Complete variant lists
  • -
-

Resolution Process

-

Template Merging

-

When a character uses templates, SBIR contains the fully merged result:

-

Source:

-
species Human { lifespan: 70, speed: 1.0 }
-template Warrior { speed: 1.5, strength: 10 }
-
-character Conan: Human from Warrior {
-    strength: 20
-}
-
-

In SBIR, Conan’s fields are:

-
    -
  • lifespan: 70 (from Human)
  • -
  • speed: 1.5 (Warrior overrides Human)
  • -
  • strength: 20 (Conan overrides Warrior)
  • -
-

Cross-File Reference Resolution

-

SBIR resolves all use statements and qualified paths. A relationship referencing Martha in a different file is resolved to the concrete character definition.

-

Validation

-

Before producing SBIR, the resolver validates all constraints documented in Validation Rules:

-
    -
  • All references resolve to defined declarations
  • -
  • No circular dependencies
  • -
  • Type consistency
  • -
  • Domain constraints (bond ranges, schedule validity)
  • -
-

Design Goals

-

Compact: SBIR strips comments, whitespace, and redundant structure.

-

Self-contained: No external references – everything is resolved and inlined.

-

Fast to load: Simulation runtimes can load SBIR without re-parsing or re-resolving.

-

Validated: If SBIR was produced, the source was valid. Runtimes do not need to re-validate.

-

Usage

-

SBIR is consumed by simulation runtimes that drive character behavior, schedule execution, life arc transitions, and relationship queries. The specific binary format is implementation-defined and may evolve between versions.

-

For the current SBIR specification, see the SBIR v0.2.0 Spec.

-

Cross-References

- -

Integration Guide

-

This chapter covers how to integrate Storybook into larger systems – game engines, simulation frameworks, and custom applications.

-

Architecture Overview

-

Storybook operates in two phases:

-
    -
  1. Compile time: .sb files are parsed, validated, and compiled into SBIR
  2. -
  3. Runtime: A simulation engine consumes SBIR and drives character behavior
  4. -
-
                    Compile Time                    Runtime
-.sb files → [Storybook Compiler] → SBIR → [Simulation Engine] → Character Actions
-
-

The Storybook Compiler

-

The compiler is a Rust library and CLI tool that processes .sb files.

-

CLI Usage

-
# Compile a directory of .sb files
-storybook compile path/to/project/
-
-# Compile with output path
-storybook compile path/to/project/ -o output.sbir
-
-# Validate without producing output
-storybook check path/to/project/
-
-

As a Library

-

The compiler can be embedded as a Rust dependency:

-
#![allow(unused)]
-fn main() {
-use storybook::syntax::parse_file;
-use storybook::resolve::resolve_files;
-
-// Parse .sb files into ASTs
-let ast = parse_file(source_code)?;
-
-// Resolve across multiple files
-let resolved = resolve_files(vec![ast1, ast2, ast3])?;
-
-// Access resolved data
-for character in resolved.characters() {
-    println!("{}: {:?}", character.name, character.fields);
-}
-}
-

Key Types

-

The resolved output provides these primary types:

-
- - - - - - - - - - -
TypeDescription
ResolvedFileContainer for all resolved declarations
ResolvedCharacterCharacter with merged species/template fields
ResolvedBehaviorBehavior tree with resolved subtree references
ResolvedLifeArcState machine with validated transitions
ResolvedScheduleSchedule with resolved time blocks
ResolvedRelationshipRelationship with resolved participant references
ResolvedInstitutionInstitution with resolved fields
ResolvedLocationLocation with resolved fields
ResolvedSpeciesSpecies with resolved includes chain
ResolvedEnumEnum with variant list
-
-

Runtime Integration

-

Behavior Tree Execution

-

Runtimes are responsible for:

-
    -
  1. Tick-based evaluation: Call the behavior tree root each frame/tick
  2. -
  3. Action execution: Interpret action nodes (e.g., MoveTo, Attack)
  4. -
  5. Condition evaluation: Evaluate expression nodes against current state
  6. -
  7. Decorator state: Maintain timer/counter state for stateful decorators
  8. -
-

Life Arc Execution

-
    -
  1. Track the current state for each life arc instance
  2. -
  3. Evaluate transition conditions each tick
  4. -
  5. Execute on-enter actions when transitioning
  6. -
  7. Maintain state persistence across ticks
  8. -
-

Schedule Execution

-
    -
  1. Get the current simulation time
  2. -
  3. Find the matching schedule block (considering temporal constraints and recurrences)
  4. -
  5. Execute the associated behavior tree action
  6. -
-

Relationship Queries

-

Provide APIs for querying the relationship graph:

-
    -
  • Find all relationships for a character
  • -
  • Get bond strength between two entities
  • -
  • Query perspective fields (self/other)
  • -
-

LSP Integration

-

Storybook includes a Language Server Protocol (LSP) implementation for editor support:

-
    -
  • Hover information: Documentation for keywords and declarations
  • -
  • Go to definition: Navigate to declaration sources
  • -
  • Diagnostics: Real-time error reporting
  • -
  • Completions: Context-aware suggestions
  • -
-

The LSP server reuses the compiler’s parser and resolver, providing the same validation as the CLI.

-

Editor Setup

-

The Storybook LSP works with any editor that supports LSP:

-
    -
  • VS Code: Via the Storybook extension
  • -
  • Zed: Via the zed-storybook extension
  • -
  • Other editors: Any LSP-compatible editor
  • -
-

Tree-sitter Grammar

-

A Tree-sitter grammar is provided for syntax highlighting and structural queries:

-
tree-sitter-storybook/
-  grammar.js          # Grammar definition
-  src/                # Generated parser
-
-

The Tree-sitter grammar supports:

-
    -
  • Syntax highlighting in editors
  • -
  • Structural code queries
  • -
  • Incremental parsing for large files
  • -
-

File Organization for Integration

-

Organize your project to support both authoring and runtime consumption:

-
my-game/
-  storybook/              # Storybook source files
-    schema/
-      core_enums.sb
-      templates.sb
-      beings.sb
-    world/
-      characters/
-      behaviors/
-      relationships/
-  assets/
-    narrative.sbir        # Compiled output for runtime
-  src/
-    narrative_engine.rs   # Runtime that consumes SBIR
-
-

Cross-References

- -

Best Practices

-

This chapter compiles best practices for writing clear, maintainable, and effective Storybook code. These guidelines apply across all declaration types and project sizes.

-

Naming Conventions

-

Declarations

-

Use PascalCase for all declaration names:

-
character MasterBaker { }          // Good
-species DomesticCat { }            // Good
-behavior GuardPatrol { }           // Good
-
-character master_baker { }         // Avoid
-behavior guard-patrol { }         // Invalid (no hyphens)
-
-

Fields

-

Use snake_case for field names:

-
character Martha {
-    skill_level: 0.95            // Good
-    emotional_state: focused     // Good
-    years_experience: 22         // Good
-
-    skillLevel: 0.95             // Avoid (camelCase)
-}
-
-

Behavior Tree Labels

-

Use snake_case for node labels, with descriptive names:

-
choose survival_instinct {       // Good
-    then fight_response { }      // Good
-    then flight_response { }     // Good
-}
-
-choose s1 {                      // Avoid (meaningless)
-    then a { }                   // Avoid
-}
-
-

Enum Variants

-

Use PascalCase or snake_case consistently within an enum:

-
// PascalCase (good for short names)
-enum Size { Tiny, Small, Normal, Large, Huge }
-
-// snake_case (good for compound names)
-enum GovernmentStyle {
-    absolute_tyranny,
-    constitutional_monarchy,
-    direct_democracy
-}
-
-

File Organization

-

Separate Schema from World

-

Keep reusable type definitions separate from instance data:

-
project/
-  schema/           # Reusable across stories
-    core_enums.sb   # Enum definitions
-    templates.sb    # Template definitions
-    beings.sb       # Species definitions
-  world/            # Specific to this story
-    characters/     # Character instances
-    behaviors/      # Behavior trees
-    relationships/  # Relationship instances
-    locations/      # Location instances
-
-

One Concern per File

-

Group related declarations, but avoid putting unrelated things together:

-
// characters/bakery_staff.sb - Good: related characters together
-character Martha { }
-character Jane { }
-character Elena { }
-
-// everything.sb - Avoid: everything in one file
-character Martha { }
-behavior BakeRoutine { }
-schedule DailyRoutine { }
-relationship Partnership { }
-
-

Explicit Imports

-

Prefer explicit imports over wildcards:

-
// Good: clear what is being used
-use schema::core_enums::{SkillLevel, Specialty};
-use schema::beings::Human;
-
-// Avoid: unclear dependencies
-use schema::core_enums::*;
-use schema::beings::*;
-
-

Character Design

-

Use Species for Identity, Templates for Traits

-
// Species: ontological identity
-species Human { lifespan: 70 }
-
-// Templates: compositional traits
-template Warrior { strength: 10..20 }
-template Scholar { intelligence: 15..20 }
-
-// Character: combines identity and traits
-character Aragorn: Human from Warrior {
-    strength: 18
-}
-
-

Document with Prose Blocks

-
character Martha: Human {
-    age: 34
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at
-    age twelve. She now runs the most popular bakery in town.
-    ---
-
-    ---personality
-    Meticulous and patient, with an unwavering commitment to
-    quality. Tough but fair with her staff.
-    ---
-}
-
-

Prefer Flat Inheritance

-

Avoid deep species hierarchies. Two or three levels is usually enough:

-
// Good: shallow
-species Mammal { warm_blooded: true }
-species Human includes Mammal { sapient: true }
-
-// Avoid: too deep
-species Being { }
-species LivingBeing includes Being { }
-species Animal includes LivingBeing { }
-species Vertebrate includes Animal { }
-species Mammal includes Vertebrate { }
-species Human includes Mammal { }
-
-

Behavior Tree Design

-

Name Every Composite Node

-
// Good: self-documenting
-choose daily_priority {
-    then handle_emergency { }
-    then do_work { }
-    then relax { }
-}
-
-// Avoid: anonymous nodes
-choose {
-    then { }
-    then { }
-}
-
-

Keep Trees Shallow

-

Extract deep subtrees into separate behaviors:

-
// Good: flat with includes
-behavior Main {
-    choose mode {
-        include CombatBehavior
-        include ExplorationBehavior
-        include SocialBehavior
-    }
-}
-
-// Avoid: deeply nested
-behavior Main {
-    choose {
-        then { choose { then { choose { then { Action } } } } }
-    }
-}
-
-

Use Decorators for Control Flow

-
// Good: decorator handles timing
-cooldown(30s) { CastSpell }
-timeout(10s) { SolvePuzzle }
-retry(3) { PickLock }
-
-// Avoid: manual timing in actions
-CheckCooldownTimer
-IfCooldownReady { CastSpell }
-
-

Expression Writing

-

Use Parentheses for Clarity

-
// Good: explicit grouping
-on (health < 50 or is_poisoned) and has_antidote -> healing
-
-// Risky: relies on precedence knowledge
-on health < 50 or is_poisoned and has_antidote -> healing
-
-

Break Complex Conditions into Multiple Transitions

-
// Good: separate transitions, easy to read
-state combat {
-    on health < 20 and not has_potion -> desperate
-    on surrounded and not has_escape -> desperate
-    on enemy_count > 10 -> desperate
-}
-
-// Avoid: one massive condition
-state combat {
-    on (health < 20 and not has_potion) or (surrounded and not has_escape) or enemy_count > 10 -> desperate
-}
-
-

Use is for Enum Comparisons

-
// Good: reads naturally
-on status is active -> active_state
-on skill_level is master -> teach_others
-
-// Works but less readable
-on status == active -> active_state
-
-

Schedule Design

-

Use Named Blocks for Override Support

-
// Good: named blocks can be overridden
-schedule Base {
-    block work { 09:00 - 17:00, action: standard_work }
-}
-
-schedule Variant extends Base {
-    block work { 05:00 - 13:00, action: early_work }
-}
-
- -
schedule DailyRoutine {
-    // Morning
-    block wake { 06:00 - 07:00, action: morning_routine }
-    block breakfast { 07:00 - 08:00, action: eat }
-
-    // Work
-    block commute { 08:00 - 09:00, action: travel }
-    block work { 09:00 - 17:00, action: work }
-
-    // Evening
-    block leisure { 18:00 - 22:00, action: relax }
-    block sleep { 22:00 - 06:00, action: sleep }
-}
-
-

Relationship Design

-

Use Roles for Clarity

-
// Good: roles clarify the relationship
-relationship Marriage {
-    Martha as spouse
-    David as spouse
-    bond: 0.9
-}
-
-// Less clear without roles
-relationship Marriage {
-    Martha
-    David
-    bond: 0.9
-}
-
-

Use Perspectives for Asymmetry

-
// Good: captures different viewpoints
-relationship TeacherStudent {
-    Gandalf as teacher self { patience: 0.8 } other { potential: 0.9 }
-    Frodo as student self { motivation: 0.7 } other { admiration: 0.95 }
-    bond: 0.85
-}
-
-

General Principles

-
    -
  1. -

    Readability over brevity: Storybook code should read like a narrative, not a puzzle.

    -
  2. -
  3. -

    Explicit over implicit: Say what you mean. Use named nodes, explicit imports, and clear field names.

    -
  4. -
  5. -

    Flat over deep: Shallow hierarchies, short behavior trees, and focused files are easier to maintain.

    -
  6. -
  7. -

    Composition over inheritance: Prefer combining templates over building deep species hierarchies.

    -
  8. -
  9. -

    Document with prose: Prose blocks are a feature, not clutter. Use them to explain intent alongside data.

    -
  10. -
  11. -

    One concept per declaration: Each behavior tree, life arc, or schedule should have a single clear purpose.

    -
  12. -
-

Cross-References

- -

Baker Family Complete

-

This example demonstrates a complete Storybook project modeling Martha’s bakery and the people around it. It showcases all major language features working together.

-

Project Structure

-
baker-family/
-  schema/
-    core_enums.sb       # Enum definitions
-    templates.sb        # Reusable templates
-    beings.sb           # Species definitions
-  world/
-    characters/
-      martha.sb         # Martha, master baker
-      jane.sb           # Jane, pastry specialist
-      elena.sb          # Elena, apprentice
-      gregory.sb        # Gregory, regular customer
-      family.sb         # David, Tommy, Emma
-    behaviors/
-      bakery_behaviors.sb
-    relationships/
-      bakery_relationships.sb
-    locations/
-      bakery_places.sb
-    institutions/
-      bakery_institutions.sb
-    schedules/
-      bakery_schedules.sb
-
-

Schema Layer

-

Enums

-
// schema/core_enums.sb
-
-enum SkillLevel {
-    novice,
-    beginner,
-    intermediate,
-    advanced,
-    expert,
-    master
-}
-
-enum Specialty {
-    sourdough,
-    pastries,
-    cakes,
-    general,
-    bread
-}
-
-enum Confidence {
-    timid,
-    uncertain,
-    growing,
-    steady,
-    confident,
-    commanding
-}
-
-enum DayPart {
-    early_morning,
-    morning,
-    midday,
-    afternoon,
-    evening,
-    night
-}
-
-

Species

-
// schema/beings.sb
-
-species Human {
-    lifespan: 80
-
-    ---description
-    Bipedal mammals with complex language and tool use.
-    ---
-}
-
-species Cat {
-    lifespan: 15
-
-    ---description
-    Domestic cats often found in bakeries for pest control
-    and companionship.
-    ---
-}
-
-

Templates

-
// schema/templates.sb
-
-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
-}
-
-template BusinessOwner {
-    include SkilledWorker
-    revenue_monthly: 0..100000
-    employees: 0..20
-    years_in_business: 0..50
-}
-
-template Apprentice {
-    include SkilledWorker
-    skill_level: novice
-    confidence: timid
-    mentor: string
-    dedication: 0.0..1.0
-}
-
-

Characters

-

Martha

-
// world/characters/martha.sb
-
-use schema::core_enums::{SkillLevel, Specialty, Confidence};
-use schema::templates::{Baker, BusinessOwner};
-use schema::beings::Human;
-
-character Martha: Human from Baker, BusinessOwner {
-    uses behaviors: [
-        { tree: BakerMorningRoutine },
-        { tree: HandleEmergency, when: emergency_detected, priority: critical }
-    ]
-
-    age: 34
-    specialty: sourdough
-    skill_level: master
-    confidence: commanding
-    recipes_mastered: 85
-    years_experience: 22
-    sourdough_starter_health: 0.95
-
-    revenue_monthly: 12000
-    employees: 3
-    years_in_business: 8
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age twelve.
-    By twenty she had won regional competitions. At twenty-six she opened
-    her own bakery, which quickly became the most popular in town. Her
-    sourdough is legendary -- she maintains a starter that is fifteen
-    years old.
-    ---
-}
-
-life_arc MarthaCareerArc {
-    ---description
-    Tracks Martha's evolution from established baker to community leader.
-    ---
-
-    state running_bakery {
-        on enter {
-            Martha.confidence: commanding
-            Martha.skill_level: master
-        }
-        on employees > 5 -> expanding
-    }
-
-    state expanding {
-        on enter {
-            Martha.revenue_monthly: 20000
-        }
-        on second_location_opened -> community_leader
-    }
-
-    state community_leader {
-        on enter {
-            Martha.can_teach: true
-            Martha.mentors_count: 3
-        }
-
-        ---narrative
-        Martha's bakery has become a training ground for the next
-        generation of bakers. She sits on the guild board and her
-        sourdough recipe is studied at culinary schools.
-        ---
-    }
-}
-
-

Jane

-
// world/characters/jane.sb
-
-use schema::core_enums::{SkillLevel, Specialty, Confidence};
-use schema::templates::Baker;
-use schema::beings::Human;
-
-character Jane: Human from Baker {
-    age: 36
-    specialty: pastries
-    skill_level: expert
-    confidence: confident
-    recipes_mastered: 120
-    years_experience: 18
-    can_work_independently: true
-
-    ---backstory
-    Jane trained at a prestigious culinary school before joining
-    Martha's bakery as co-owner. Where Martha excels at bread, Jane
-    is a pastry artist. Her croissants draw customers from three
-    towns over.
-    ---
-
-    ---appearance
-    A focused woman with flour-dusted apron and steady hands.
-    Known for her intricate pastry decorations and precise
-    temperature control.
-    ---
-}
-
-

Elena

-
// world/characters/elena.sb
-
-use schema::core_enums::{SkillLevel, Confidence};
-use schema::templates::Apprentice;
-use schema::beings::Human;
-
-character Elena: Human from Apprentice {
-    age: 16
-    skill_level: novice
-    confidence: timid
-    mentor: "Martha"
-    dedication: 0.9
-    natural_talent: 0.8
-    recipes_mastered: 2
-
-    ---backstory
-    Elena comes from a family of farmers who could never afford to
-    buy bread from the bakery. When Martha offered her an apprenticeship,
-    she jumped at the chance to learn a trade.
-    ---
-}
-
-life_arc ElenaCareer {
-    ---description
-    Tracks Elena's progression from nervous apprentice to confident
-    master baker. Each state represents a key phase of her career.
-    ---
-
-    state early_apprentice {
-        on enter {
-            Elena.skill_level: novice
-            Elena.confidence: timid
-        }
-
-        on recipes_mastered > 5 -> growing_apprentice
-
-        ---narrative
-        Elena's hands shake as she measures flour. She checks the
-        recipe three times before adding each ingredient. Martha
-        patiently corrects her technique.
-        ---
-    }
-
-    state growing_apprentice {
-        on enter {
-            Elena.skill_level: beginner
-            Elena.confidence: uncertain
-        }
-
-        on recipes_mastered > 15 -> journeyman
-
-        ---narrative
-        The shaking stops. Elena can make basic breads without
-        looking at the recipe. She still doubts herself but
-        Martha's encouragement is taking root.
-        ---
-    }
-
-    state journeyman {
-        on enter {
-            Elena.skill_level: intermediate
-            Elena.confidence: growing
-            Elena.can_work_independently: true
-        }
-
-        on recipes_mastered > 30 -> senior_journeyman
-
-        ---narrative
-        Elena runs the morning shift alone while Martha handles
-        special orders. Customers start asking for "Elena's rolls."
-        She begins experimenting with her own recipes.
-        ---
-    }
-
-    state senior_journeyman {
-        on enter {
-            Elena.skill_level: advanced
-            Elena.confidence: steady
-        }
-
-        on recipes_mastered > 50 -> master
-
-        ---narrative
-        Elena develops her signature recipe: rosemary olive bread
-        that becomes the bakery's bestseller. She handles difficult
-        customers with grace and trains new helpers.
-        ---
-    }
-
-    state master {
-        on enter {
-            Elena.skill_level: master
-            Elena.confidence: commanding
-            Elena.can_teach: true
-        }
-
-        ---narrative
-        Master Baker Elena. She has earned it. The guild acknowledges
-        her mastery, and Martha beams with pride. Elena begins
-        mentoring her own apprentice.
-        ---
-    }
-}
-
-

Gregory

-
// world/characters/gregory.sb
-
-use schema::beings::Human;
-
-character Gregory: Human {
-    age: 68
-    occupation: "retired_teacher"
-    always_orders: "sourdough_loaf"
-    visits_daily: true
-    years_as_customer: 15
-    knows_everyone: true
-
-    ---backstory
-    Gregory has been buying Martha's bread every morning for
-    fifteen years. Their brief daily exchanges about the weather
-    and local gossip are a comforting routine for both of them.
-    ---
-}
-
-

Behaviors

-
// world/behaviors/bakery_behaviors.sb
-
-behavior BakerMorningRoutine {
-    ---description
-    Martha's morning routine: prepare dough step by step,
-    from mixing to shaping to baking.
-    ---
-
-    then morning_baking {
-        // Start with sourdough
-        then prepare_starter {
-            CheckStarter
-            FeedStarter
-            WaitForActivity
-        }
-
-        // Mix the dough
-        then mix_dough {
-            MeasureFlour
-            AddWater
-            IncorporateStarter
-        }
-
-        // Knead and shape
-        then shape_loaves {
-            KneadDough
-            FirstRise
-            ShapeLoaves
-        }
-
-        // Bake
-        then bake {
-            PreHeatOven
-            LoadLoaves
-            MonitorBaking
-        }
-    }
-}
-
-behavior CustomerServiceLoop {
-    ---description
-    The bakery's continuous customer service loop. Uses infinite
-    repeat decorator to serve customers throughout the day.
-    ---
-
-    repeat {
-        then service_cycle {
-            // Check for customers
-            choose service_mode {
-                then serve_waiting {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                }
-
-                then restock_display {
-                    if(display_low)
-                    FetchFromKitchen
-                    ArrangeOnShelves
-                }
-            }
-
-            // Process payment
-            CollectPayment
-            ThankCustomer
-
-            // Brief pause between customers
-            timeout(5s) {
-                CleanCounter
-            }
-
-            PrepareForNextCustomer
-        }
-    }
-}
-
-

Relationships

-
// world/relationships/bakery_relationships.sb
-
-relationship MarthaAndGregory {
-    Martha {
-        role: shopkeeper
-        values_loyalty: 0.9
-
-        ---perspective
-        Martha appreciates Gregory's unwavering loyalty. He has
-        been buying her sourdough loaf every morning for fifteen
-        years. Their brief daily exchanges about the weather and
-        local gossip are a comforting routine.
-        ---
-    }
-
-    Gregory {
-        role: regular_customer
-        always_orders: "sourdough_loaf"
-
-        ---perspective
-        Gregory considers Martha's bakery a cornerstone of his
-        daily routine. The bread is excellent, but it is the brief
-        human connection that keeps him coming back.
-        ---
-    }
-}
-
-relationship MentorApprentice {
-    Martha {
-        role: mentor
-        teaching_style: "patient"
-        investment: 0.9
-
-        ---perspective
-        Martha sees Elena as the daughter she might have had in
-        the trade. She recognizes the same passion she felt at
-        that age and pushes Elena harder because she knows the
-        talent is there. Every correction comes from love.
-        ---
-    }
-
-    Elena {
-        role: apprentice
-        dedication: 0.9
-        anxiety: 0.4
-
-        ---perspective
-        Elena idolizes Martha's skill but fears disappointing
-        her. Every morning she arrives thirty minutes early to
-        practice techniques before Martha gets in. She keeps a
-        notebook of every correction, reviewing them each night.
-        ---
-    }
-
-    bond: 0.85
-}
-
-relationship BakeryPartnership {
-    Martha {
-        role: co_owner
-        specialty: "bread"
-        handles_finances: true
-
-        ---perspective
-        Martha and Jane complement each other perfectly. Martha
-        handles the bread and business side while Jane creates
-        the pastries that draw customers in. Together they have
-        built something neither could alone.
-        ---
-    }
-
-    Jane {
-        role: co_owner
-        specialty: "pastries"
-        handles_creativity: true
-
-        ---perspective
-        Jane considers Martha the steady foundation of their
-        partnership. While Jane experiments and creates, Martha
-        ensures the bakery runs like clockwork. Their different
-        strengths make the bakery stronger.
-        ---
-    }
-
-    bond: 0.9
-}
-
-

Locations

-
// world/locations/bakery_places.sb
-
-location MarthasBakery {
-    type: "commercial"
-    established: "2018"
-    square_feet: 1200
-    has_kitchen: true
-    has_storefront: true
-    seating_capacity: 12
-
-    ---description
-    A warm, inviting bakery on Main Street. The aroma of fresh
-    bread wafts out the door every morning at 4 AM. Exposed brick
-    walls, a glass display case, and a view into the kitchen where
-    customers can watch the bakers at work.
-    ---
-}
-
-location FarmersMarket {
-    type: "outdoor_market"
-    operates_on: "saturday"
-    stalls: 30
-    foot_traffic: "high"
-
-    ---description
-    The weekly Saturday market where Martha sells her bread directly
-    to the community. Her stall is always the first to sell out.
-    ---
-}
-
-location BakeryKitchen {
-    type: "commercial_kitchen"
-    ovens: 3
-    prep_stations: 4
-    walk_in_cooler: true
-
-    ---description
-    The heart of the bakery. Three professional ovens line the back
-    wall, each at a different temperature for different breads. The
-    sourdough starter sits on a shelf near the warmest oven, bubbling
-    contentedly in its ceramic crock.
-    ---
-}
-
-

Institutions

-
// world/institutions/bakery_institutions.sb
-
-institution BakersGuild {
-    type: professional_guild
-    members: 45
-    founded: "1952"
-    meets_monthly: true
-
-    ---description
-    The local bakers' guild that sets quality standards, organizes
-    competitions, and mentors apprentices. Martha has been a board
-    member for three years.
-    ---
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Layered architecture: Schema (types) separated from world (instances)
  2. -
  3. Species + Templates: Human species combined with Baker and BusinessOwner templates
  4. -
  5. Rich behavior trees: Morning routine and customer service with choose, then, and repeat
  6. -
  7. Asymmetric relationships: Martha and Elena see their mentorship differently
  8. -
  9. Life arcs: Elena’s career journey modeled as a state machine
  10. -
  11. Prose everywhere: Every declaration includes narrative context
  12. -
-

Cross-References

- -

Day in the Life

-

This example models a complete day for a baker character, showing how schedules, behaviors, and life arcs work together to create a rich daily simulation.

-

The Baker

-
use schema::core_enums::{Season, DayOfWeek};
-use schema::beings::Human;
-use schema::templates::SkilledWorker;
-
-character Martha: Human from SkilledWorker {
-    age: 42
-    occupation: "Master Baker"
-    skill_level: 0.95
-    energy: 1.0
-    mood: 0.8
-
-    uses schedule: MarthaDailySchedule
-    uses behaviors: [
-        { tree: BakerRoutine, priority: normal },
-        { tree: HandleEmergency, when: emergency_detected, priority: critical }
-    ]
-
-    ---backstory
-    Martha has been baking since she was twelve, learning from her
-    grandmother. She now runs the most popular bakery in town and
-    is known for her sourdough bread and apple pastries.
-    ---
-}
-
-

The Schedule

-
schedule MarthaDailySchedule {
-    block wake_up {
-        04:00 - 04:30
-        action: routines::morning_wake
-    }
-
-    block early_baking {
-        04:30 - 07:00
-        action: baking::prepare_morning_goods
-    }
-
-    block open_shop {
-        07:00 - 07:15
-        action: shop::open_for_business
-    }
-
-    block morning_rush {
-        07:15 - 10:00
-        action: shop::serve_morning_customers
-    }
-
-    block midday_baking {
-        10:00 - 12:00
-        action: baking::prepare_afternoon_goods
-    }
-
-    block lunch_break {
-        12:00 - 13:00
-        action: social::lunch_with_family
-    }
-
-    block afternoon_sales {
-        13:00 - 16:00
-        action: shop::serve_afternoon_customers
-    }
-
-    block close_shop {
-        16:00 - 16:30
-        action: shop::close_for_day
-    }
-
-    block evening_prep {
-        16:30 - 17:30
-        action: baking::prepare_dough_for_tomorrow
-    }
-
-    block family_time {
-        18:00 - 21:00
-        action: social::family_evening
-    }
-
-    block sleep {
-        21:00 - 04:00
-        action: routines::sleep
-    }
-
-    // Saturday: Market day
-    recurs MarketDay on day saturday {
-        block market_prep {
-            03:00 - 05:00
-            action: baking::market_batch
-        }
-
-        block market_sales {
-            06:00 - 14:00
-            action: market::sell_at_stall
-        }
-
-        block market_cleanup {
-            14:00 - 15:00
-            action: market::pack_up
-        }
-    }
-
-    // Summer: Extended hours
-    block summer_afternoon {
-        13:00 - 18:00
-        action: shop::extended_summer_hours
-        on season summer
-    }
-}
-
-

Behaviors

-

Morning Routine

-
behavior BakerMorningRoutine {
-    then morning_sequence {
-        WakeUp
-        WashFace
-        DressInWorkClothes
-
-        // Check the sourdough starter
-        then check_starter {
-            ExamineStarter
-            if(starter_healthy) {
-                FeedStarter
-            }
-        }
-
-        WalkToKitchen
-        LightOven
-    }
-}
-
-

Baking Behavior

-
behavior BakerRoutine {
-    choose baking_priority {
-        // Handle special orders first
-        then special_orders {
-            if(has_special_orders)
-            then fill_order {
-                ReviewOrderDetails
-                GatherSpecialIngredients
-                PrepareSpecialItem
-                PackageForCustomer
-            }
-        }
-
-        // Regular daily baking
-        then daily_bread {
-            then sourdough {
-                MixDough(recipe: "sourdough", quantity: 10)
-                KneadDough(duration: 15m)
-                FirstRise(duration: 2h)
-                ShapLoaves
-                SecondRise(duration: 1h)
-                BakeLoaves(temperature: 230, duration: 35m)
-            }
-        }
-
-        // Pastries if time permits
-        then pastries {
-            succeed_always {
-                then apple_pastries {
-                    PrepareFillingApple
-                    RollPastryDough
-                    AssemblePastries
-                    BakePastries(temperature: 200, duration: 25m)
-                }
-            }
-        }
-    }
-}
-
-

Customer Service

-
behavior ServeCustomer {
-    then service_sequence {
-        GreetCustomer
-        if(customer_is_regular) {
-            RecallPreferences
-        }
-
-        choose service_type {
-            then take_order {
-                if(customer_knows_what_they_want)
-                AcceptOrder
-                PackageItem
-            }
-
-            then help_decide {
-                if(not customer_knows_what_they_want)
-                OfferRecommendation
-                ProvidesSample
-                AcceptOrder
-                PackageItem
-            }
-        }
-
-        CollectPayment
-        ThankCustomer
-    }
-}
-
-

Emergency Handling

-
behavior HandleEmergency {
-    choose emergency_type {
-        then oven_fire {
-            if(oven_overheating)
-            TurnOffOven
-            GrabFireExtinguisher
-            ExtinguishFire
-            AssessDamage
-        }
-
-        then ingredient_shortage {
-            if(critical_ingredient_missing)
-            CheckBackupSupply
-            choose procurement {
-                SendApprenticeToMarket
-                SubstituteIngredient
-                AdjustMenu
-            }
-        }
-
-        then equipment_failure {
-            if(equipment_broken)
-            StopProduction
-            AttemptQuickFix
-            choose fallback {
-                UseBackupEquipment
-                CallRepairPerson
-            }
-        }
-    }
-}
-
-

Life Arc: Career and Energy

-
life_arc MarthaEnergyLevel {
-    state rested {
-        on enter {
-            Martha.energy: 1.0
-            Martha.mood: 0.8
-        }
-        on energy < 0.5 -> tired
-    }
-
-    state tired {
-        on enter {
-            Martha.mood: 0.6
-        }
-        on energy < 0.2 -> exhausted
-        on energy > 0.7 -> rested
-    }
-
-    state exhausted {
-        on enter {
-            Martha.mood: 0.3
-            Martha.quality_output: 0.7
-        }
-        on energy > 0.5 -> tired
-    }
-}
-
-

Relationships

-
relationship MarthaAndApprentice {
-    Martha as mentor self {
-        patience: 0.8
-        investment: 0.9
-    } other {
-        sees_potential: 0.85
-    }
-
-    Elena as apprentice self {
-        dedication: 0.9
-        learning_rate: 0.7
-    } other {
-        respect: 0.95
-        admiration: 0.8
-    }
-
-    bond: 0.85
-    years_together: 2
-}
-
-relationship MarthaAndRegularCustomer {
-    Martha as shopkeeper
-    OldManGregory as regular_customer
-
-    bond: 0.7
-    years_known: 15
-    always_orders: "sourdough_loaf"
-
-    ---dynamics
-    Gregory has been buying Martha's bread every morning for
-    fifteen years. They exchange brief pleasantries about the
-    weather and local gossip. He is her most reliable customer.
-    ---
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Schedule-driven daily flow: Precise time blocks govern Martha’s entire day
  2. -
  3. Seasonal and weekly variations: Summer hours and Saturday market
  4. -
  5. Layered behaviors: Emergency behavior preempts normal routine via priority
  6. -
  7. Realistic action sequences: Baking modeled step by step with parameters
  8. -
  9. Energy management: Life arc tracks fatigue affecting mood and output quality
  10. -
  11. Social connections: Relationships with apprentice and customers add depth
  12. -
-

Cross-References

- -

Character Evolution

-

This example models a character who evolves through multiple life stages, demonstrating how life arcs, behavior trees, and templates work together to represent growth over time.

-

The Apprentice’s Journey

-

Elena starts as a nervous apprentice and grows into a confident master baker. Her evolution touches every aspect of her character: skills, personality, relationships, and daily routine.

-

Schema

-
enum SkillLevel { novice, beginner, intermediate, advanced, expert, master }
-
-enum Confidence { timid, uncertain, growing, steady, confident, commanding }
-
-template Apprentice {
-    skill_level: novice
-    confidence: timid
-    can_work_independently: false
-    recipes_mastered: 0..5
-}
-
-template Journeyman {
-    skill_level: intermediate
-    confidence: growing
-    can_work_independently: true
-    recipes_mastered: 10..30
-}
-
-template MasterBaker {
-    skill_level: master
-    confidence: commanding
-    can_work_independently: true
-    can_teach: true
-    recipes_mastered: 50..200
-}
-
-

The Character at Different Stages

-
// Elena starts as an apprentice
-character Elena: Human from Apprentice {
-    age: 16
-    natural_talent: 0.8
-    dedication: 0.9
-    recipes_mastered: 2
-    confidence: timid
-    mentor: Martha
-
-    ---backstory
-    Elena comes from a family of farmers who could never afford to
-    buy bread from the bakery. When Martha offered her an apprenticeship,
-    she jumped at the chance to learn a trade.
-    ---
-}
-
-

The Evolution Life Arc

-
life_arc ElenaCareer {
-    ---description
-    Tracks Elena's progression from nervous apprentice to
-    confident master baker over several years.
-    ---
-
-    state apprentice_early {
-        on enter {
-            Elena.skill_level: novice
-            Elena.confidence: timid
-            Elena.can_work_independently: false
-        }
-
-        on recipes_mastered > 5 -> apprentice_growing
-
-        ---narrative
-        Elena's hands shake as she measures flour. She checks the
-        recipe three times before adding each ingredient. Martha
-        patiently corrects her technique.
-        ---
-    }
-
-    state apprentice_growing {
-        on enter {
-            Elena.skill_level: beginner
-            Elena.confidence: uncertain
-        }
-
-        on recipes_mastered > 15 -> journeyman
-
-        ---narrative
-        The shaking stops. Elena can make basic breads without
-        looking at the recipe. She still doubts herself but
-        Martha's encouragement is taking root.
-        ---
-    }
-
-    state journeyman {
-        on enter {
-            Elena.skill_level: intermediate
-            Elena.confidence: growing
-            Elena.can_work_independently: true
-        }
-
-        on recipes_mastered > 30 and confidence is steady -> senior_journeyman
-
-        ---narrative
-        Elena runs the morning shift alone while Martha handles
-        special orders. Customers start asking for "Elena's rolls."
-        She begins experimenting with her own recipes.
-        ---
-    }
-
-    state senior_journeyman {
-        on enter {
-            Elena.skill_level: advanced
-            Elena.confidence: steady
-        }
-
-        on recipes_mastered > 50 and passed_master_trial -> master
-
-        ---narrative
-        Elena develops her signature recipe: rosemary olive bread
-        that becomes the bakery's bestseller. She handles difficult
-        customers with grace and trains new helpers.
-        ---
-    }
-
-    state master {
-        on enter {
-            Elena.skill_level: master
-            Elena.confidence: commanding
-            Elena.can_teach: true
-        }
-
-        ---narrative
-        Master Baker Elena. She has earned it. The guild acknowledges
-        her mastery, and Martha beams with pride. Elena begins
-        mentoring her own apprentice.
-        ---
-    }
-}
-
-

Evolving Behaviors

-

Elena’s behavior changes as she progresses:

-
// Early apprentice: hesitant, checks everything
-behavior Elena_ApprenticeEarly {
-    then cautious_baking {
-        CheckRecipeThreeTimes
-        MeasureCarefully
-        AskMarthaForConfirmation
-        ProceedSlowly
-        CheckResultAnxiously
-    }
-}
-
-// Growing apprentice: more confident
-behavior Elena_ApprenticeGrowing {
-    then competent_baking {
-        ReviewRecipe
-        MeasureIngredients
-        MixWithConfidence
-        choose problem_handling {
-            then handle_alone {
-                if(confidence > 0.4)
-                AssessSituation
-                ApplyLearning
-            }
-            AskMarthaForHelp
-        }
-    }
-}
-
-// Journeyman: independent and creative
-behavior Elena_Journeyman {
-    choose work_mode {
-        then creative_mode {
-            if(inspiration_high)
-            ExperimentWithRecipe
-            TasteTest
-            if(result_good) {
-                RecordNewRecipe
-            }
-        }
-
-        then production_mode {
-            ExecuteRecipeFromMemory
-            MonitorOvenTimings
-            ManageMultipleBatches
-        }
-
-        then teaching_mode {
-            if(helper_present)
-            DemonstrateTeechnique
-            ObserveHelper
-            ProvideGentleFeedback
-        }
-    }
-}
-
-// Master: leadership and mentoring
-behavior Elena_Master {
-    choose master_activity {
-        then mentor_apprentice {
-            if(apprentice_needs_guidance)
-            AssessApprenticeProgress
-            DesignLearningChallenge
-            ObserveAndFeedback
-        }
-
-        then innovate {
-            if(creative_energy_high)
-            ResearchNewTechniques
-            ExperimentWithIngredients
-            DocumentFindings
-        }
-
-        then lead_production {
-            PlanDailyProduction
-            DelegateToTeam
-            QualityCheckResults
-        }
-    }
-}
-
-

Evolving Relationships

-

The mentor relationship changes as Elena grows:

-
// Early apprenticeship
-relationship EarlyMentorship {
-    Martha as mentor self {
-        patience: 0.9
-        teaching_intensity: 0.8
-    } other {
-        sees_potential: 0.8
-        reminds_her_of_herself: true
-    }
-
-    Elena as apprentice self {
-        gratitude: 1.0
-        anxiety: 0.7
-    } other {
-        admiration: 0.95
-        intimidated: 0.5
-    }
-
-    bond: 0.6
-}
-
-// Later: colleagues and friends
-relationship MaturePartnership {
-    Martha as senior_partner self {
-        pride_in_elena: 0.95
-        ready_to_step_back: 0.6
-    } other {
-        sees_equal: 0.8
-        trusts_judgment: 0.9
-    }
-
-    Elena as junior_partner self {
-        confidence: 0.85
-        gratitude: 0.9
-    } other {
-        respect: 0.95
-        sees_as_mother_figure: 0.7
-    }
-
-    bond: 0.95
-}
-
-

Evolving Schedules

-

Elena’s schedule changes as she takes on more responsibility:

-
// Apprentice schedule: supervised hours
-schedule ElenaApprentice {
-    block arrive {
-        06:00 - 06:15
-        action: routines::arrive_early
-    }
-
-    block learn_and_assist {
-        06:15 - 14:00
-        action: baking::assist_martha
-    }
-
-    block cleanup_duty {
-        14:00 - 15:00
-        action: shop::cleanup
-    }
-
-    block study {
-        15:00 - 16:00
-        action: learning::study_recipes
-    }
-}
-
-// Master schedule: leadership hours
-schedule ElenaMaster extends ElenaApprentice {
-    block arrive {
-        04:00 - 04:15
-        action: routines::open_bakery
-    }
-
-    block learn_and_assist {
-        04:15 - 12:00
-        action: baking::lead_production
-    }
-
-    block cleanup_duty {
-        12:00 - 13:00
-        action: social::lunch_with_team
-    }
-
-    block study {
-        13:00 - 15:00
-        action: baking::mentor_apprentice
-    }
-
-    block business {
-        15:00 - 17:00
-        action: management::business_planning
-    }
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Life arcs as character development: Elena’s career progression modeled as states
  2. -
  3. Evolving behaviors: Different behavior trees for each stage of growth
  4. -
  5. Changing relationships: The mentor dynamic shifts from dependency to partnership
  6. -
  7. Schedule evolution: Responsibilities grow with skill level
  8. -
  9. Narrative prose: Each life arc state tells a story about who Elena is becoming
  10. -
  11. Template progression: Templates define the capability profile at each stage
  12. -
-

Cross-References

- -

Multi-Character Interactions

-

This example models a complex social scene: a busy Saturday morning at Martha’s bakery. Multiple characters interact simultaneously with interlocking behaviors, relationships, and a shared location buzzing with activity.

-

The Setting

-
enum RushLevel { calm, busy, hectic, overwhelming }
-enum ServiceMode { normal, rush, emergency }
-
-location BakeryStorefront {
-    rush_level: busy
-    current_time: 07:30
-    customers_waiting: 8
-    display_items_remaining: 45
-    oven_batches_in_progress: 3
-    coffee_machine_running: true
-
-    ---description
-    Saturday morning at Martha's bakery. The line stretches out
-    the door. The display case gleams with fresh bread, pastries,
-    and Elena's famous rosemary olive rolls. The air is warm with
-    the smell of baking and the hum of conversation.
-    ---
-
-    ---atmosphere
-    This is the bakery at its best and most stressful. Every
-    Saturday brings the regulars, the farmers' market overflow,
-    and tourists who heard about Martha's sourdough. The whole
-    team works in concert to keep up.
-    ---
-}
-
-institution SaturdayMorningCrew {
-    type: work_team
-    purpose: serve_customers_and_bake
-    members: 4
-    coordination_level: 0.9
-
-    ---description
-    The Saturday crew operates like a well-oiled machine. Martha
-    runs the kitchen, Jane handles pastries, Elena manages the
-    front counter, and Gregory -- the loyal regular -- unofficially
-    helps direct the line.
-    ---
-}
-
-

The Characters

-
use schema::core_enums::{SkillLevel, Confidence, Specialty};
-use schema::templates::{Baker, BusinessOwner, Apprentice};
-use schema::beings::Human;
-
-character Martha: Human from Baker, BusinessOwner {
-    age: 34
-    specialty: sourdough
-    skill_level: master
-    confidence: commanding
-    energy: 0.8
-    stress_level: 0.4
-    loaves_baked_today: 24
-    orders_pending: 6
-
-    ---personality
-    Calm under pressure. Martha thrives on Saturday mornings --
-    the rush brings out her best. She coordinates the team with
-    quiet efficiency, stepping in wherever needed while keeping
-    the ovens running on schedule.
-    ---
-}
-
-character Jane: Human from Baker {
-    age: 36
-    specialty: pastries
-    skill_level: expert
-    confidence: confident
-    energy: 0.9
-    creative_mode: true
-    pastries_decorated_today: 18
-
-    ---personality
-    Jane works in focused silence during the rush. Her hands
-    move with precision, piping decorations and assembling
-    layered pastries. She communicates with Martha through
-    glances and nods -- years of partnership have made words
-    unnecessary.
-    ---
-}
-
-character Elena: Human from Apprentice {
-    age: 17
-    skill_level: intermediate
-    confidence: growing
-    energy: 1.0
-    customers_served_today: 32
-    mistakes_today: 1
-
-    ---personality
-    Elena has grown into the front-counter role. She remembers
-    regulars' names and orders, handles complaints with grace,
-    and only calls Martha when truly stuck. The nervous girl
-    who started a year ago is barely recognizable.
-    ---
-}
-
-character Gregory: Human {
-    age: 68
-    role: "regular_customer"
-    visits_today: 1
-    helping_with_line: true
-    knows_everyone: true
-
-    ---personality
-    Gregory arrives at exactly 7:15 every Saturday. He buys
-    his sourdough loaf, then lingers near the door, chatting
-    with other customers and unofficially managing the line.
-    He considers this his contribution to the bakery.
-    ---
-}
-
-

Interlocking Behaviors

-

Martha’s Behavior

-
behavior Martha_SaturdayMorning {
-    ---description
-    Martha's Saturday morning routine: managing the kitchen,
-    coordinating the team, and keeping the ovens running.
-    ---
-
-    repeat {
-        choose saturday_priority {
-            // Check ovens first (highest priority)
-            then oven_management {
-                if(oven_timer_near_done)
-                CheckOvenTemperature
-                RemoveFinishedBatch
-                LoadNextBatch
-                SetTimer
-            }
-
-            // Handle special orders
-            then special_orders {
-                if(has_special_orders)
-                choose order_type {
-                    PrepareWeddingCake
-                    BoxCustomOrder
-                    DecorateSpecialLoaf
-                }
-            }
-
-            // Support Elena at counter
-            then help_counter {
-                if(elena_needs_help)
-                choose counter_support {
-                    AnswerCustomerQuestion
-                    HandleComplaint
-                    ProcessLargeOrder
-                }
-            }
-
-            // Coordinate with Jane
-            then coordinate_pastries {
-                if(display_items_remaining < 10)
-                SignalJaneToRestockPastries
-                RearrangeDisplay
-            }
-
-            // Default: knead next batch
-            then prep_dough {
-                MixNextBatch
-                KneadDough
-                ShapeLoaves
-            }
-        }
-    }
-}
-
-

Jane’s Behavior

-
behavior Jane_SaturdayMorning {
-    repeat {
-        choose jane_priority {
-            // Restock display when signaled
-            then restock_pastries {
-                if(martha_signaled_restock)
-                PlateFinishedPastries
-                CarryToDisplay
-                ArrangeAttractively
-            }
-
-            // Decorate current batch
-            then decorating {
-                if(has_undecorated_pastries)
-                PipeIcing
-                AddGarnish
-                InspectQuality
-            }
-
-            // Start new pastry batch
-            then new_batch {
-                if(pastry_dough_ready)
-                RollPastryDough
-                CutShapes
-                AddFilling
-                PlaceOnBakingSheet
-            }
-
-            // Prepare specialty items
-            then specialty_items {
-                if(specialty_order_pending)
-                ReviewOrderNotes
-                SelectPremiumIngredients
-                CraftSpecialtyItem
-            }
-        }
-    }
-}
-
-

Elena’s Behavior

-
behavior Elena_SaturdayCounter {
-    choose counter_state {
-        // Serve waiting customers
-        then serve_customer {
-            if(customer_waiting)
-            then service_sequence {
-                GreetCustomer
-                if(customer_is_regular) {
-                    RecallPreferences
-                }
-
-                choose order_handling {
-                    then quick_order {
-                        if(customer_knows_what_they_want)
-                        AcceptOrder
-                        PackageItem
-                    }
-
-                    then help_decide {
-                        if(not customer_knows_what_they_want)
-                        OfferRecommendation
-                        OfferSample
-                        AcceptOrder
-                        PackageItem
-                    }
-                }
-
-                CollectPayment
-                ThankCustomer
-            }
-        }
-
-        // Handle problems
-        then handle_issue {
-            if(customer_has_complaint)
-            choose resolution {
-                then resolve_alone {
-                    if(confidence > 0.5)
-                    ListenCarefully
-                    OfferSolution
-                    ApplyResolution
-                }
-
-                then escalate {
-                    if(confidence <= 0.5)
-                    AcknowledgeProblem
-                    CallMarthaForHelp
-                }
-            }
-        }
-
-        // Manage the line
-        then manage_queue {
-            if(line_length > 5)
-            AnnounceWaitTime
-            SuggestPopularItems
-        }
-    }
-}
-
-

Gregory’s Behavior

-
behavior Gregory_SaturdayVisit {
-    then saturday_routine {
-        // Arrive and order
-        then arrival {
-            EnterBakery
-            GreetElena
-            OrderSourdoughLoaf
-            PayExactChange
-        }
-
-        // Linger and help
-        choose lingering_activity {
-            then manage_line {
-                if(line_is_long)
-                DirectNewCustomersToEndOfLine
-                ChatWithWaitingCustomers
-                RecommendPopularItems
-            }
-
-            then catch_up {
-                if(sees_familiar_face)
-                GreetNeighbor
-                ExchangeLocalNews
-                DiscussWeather
-            }
-
-            then observe_elena {
-                if(elena_handling_difficult_customer)
-                StandNearbyForMoralSupport
-                NodEncouragingly
-            }
-        }
-
-        // Eventually leave
-        then departure {
-            WaveToMartha
-            SayGoodbyeToElena
-            ExitWithBread
-        }
-    }
-}
-
-

Relationships

-
relationship BakeryPartnership {
-    Martha {
-        role: co_owner
-        coordination: 1.0
-        handles_bread: true
-
-        ---perspective
-        Martha and Jane communicate without words during the rush.
-        A glance toward the display case means "we're running low."
-        A nod means "I'll handle it." Years of working side by side
-        have created an effortless rhythm.
-        ---
-    }
-
-    Jane {
-        role: co_owner
-        coordination: 1.0
-        handles_pastries: true
-
-        ---perspective
-        Jane trusts Martha's judgment completely during the Saturday
-        rush. If Martha signals, Jane reprioritizes. If Jane needs
-        oven time, Martha adjusts. They are two halves of a single
-        well-run kitchen.
-        ---
-    }
-
-    bond: 0.95
-}
-
-relationship TeamAndApprentice {
-    Martha as mentor
-    Jane as senior_colleague
-    Elena as apprentice
-
-    bond: 0.8
-
-    ---dynamics
-    Elena looks up to both Martha and Jane, but in different ways.
-    Martha teaches her the fundamentals -- technique, discipline,
-    consistency. Jane shows her the creative side -- decoration,
-    presentation, flavor combinations. Together they are shaping
-    Elena into a complete baker.
-    ---
-}
-
-relationship GregoryAtTheBakery {
-    Gregory {
-        role: loyal_customer
-        attachment: 0.9
-        unofficial_helper: true
-
-        ---perspective
-        The bakery is Gregory's third place -- not home, not the
-        library where he used to teach, but the warm space where
-        he belongs. He has watched Elena grow from a nervous girl
-        to a confident young woman. He is proud, though he would
-        never say so directly.
-        ---
-    }
-
-    Elena {
-        role: counter_staff
-        fondness: 0.8
-        sees_as: "grandfather_figure"
-
-        ---perspective
-        Elena looks forward to Gregory's arrival every morning.
-        His exact-change payment and dry humor are a reliable
-        anchor in the chaos of the morning rush.
-        ---
-    }
-
-    bond: 0.7
-}
-
-

The Saturday Schedule

-
schedule SaturdayRush {
-    block early_prep {
-        03:00 - 06:00
-        action: baking::saturday_batch
-    }
-
-    block opening {
-        06:00 - 06:15
-        action: shop::open_doors
-    }
-
-    block morning_rush {
-        06:15 - 11:00
-        action: shop::saturday_rush_service
-    }
-
-    block midday_restock {
-        11:00 - 12:00
-        action: baking::midday_supplemental
-    }
-
-    block afternoon_wind_down {
-        12:00 - 14:00
-        action: shop::afternoon_sales
-    }
-
-    block close_and_clean {
-        14:00 - 15:00
-        action: shop::saturday_cleanup
-    }
-}
-
-

Life Arc: Elena’s Saturday Confidence

-
life_arc ElenaSaturdayGrowth {
-    state nervous_start {
-        on enter {
-            Elena.confidence: uncertain
-            Elena.energy: 1.0
-        }
-        on customers_served_today > 5 -> finding_rhythm
-
-        ---narrative
-        The first few customers are always the hardest. Elena
-        fumbles with the register, second-guesses prices, and
-        looks to Martha for confirmation. But each successful
-        transaction builds her up.
-        ---
-    }
-
-    state finding_rhythm {
-        on enter {
-            Elena.confidence: growing
-        }
-        on customers_served_today > 15 -> in_the_zone
-
-        ---narrative
-        Something clicks. Elena stops thinking about each step
-        and starts flowing. She remembers Mrs. Patterson's usual
-        order before she says it. She bags the croissants without
-        looking.
-        ---
-    }
-
-    state in_the_zone {
-        on enter {
-            Elena.confidence: confident
-        }
-        on handled_complaint_alone -> proud_moment
-        on energy < 0.3 -> running_on_fumes
-
-        ---narrative
-        Elena is running the counter like she was born to it.
-        Gregory gives her a quiet nod of approval from his spot
-        by the door. She barely notices -- she is too busy being
-        competent.
-        ---
-    }
-
-    state proud_moment {
-        on enter {
-            Elena.confidence: confident
-            Elena.self_respect: 0.9
-        }
-
-        ---narrative
-        A customer complained about a stale roll. Elena apologized,
-        replaced it with a fresh one, and offered a free cookie.
-        The customer left smiling. Elena handled it alone, without
-        calling Martha. She stands a little taller afterward.
-        ---
-    }
-
-    state running_on_fumes {
-        on enter {
-            Elena.energy: 0.2
-            Elena.confidence: uncertain
-        }
-        on break_taken -> finding_rhythm
-
-        ---narrative
-        The rush has been going for four hours. Elena's smile
-        is getting harder to maintain. Martha notices and sends
-        her to the back for a five-minute break and a pastry.
-        ---
-    }
-}
-
-

Key Takeaways

-

This example demonstrates:

-
    -
  1. Multiple characters with interlocking behaviors: Martha, Jane, Elena, and Gregory react to each other
  2. -
  3. Character coordination: Martha and Jane operate as a seamless team
  4. -
  5. Asymmetric group dynamics: Gregory is an unofficial helper, Elena is growing into her role
  6. -
  7. Location as context: The busy bakery storefront defines the scene
  8. -
  9. Institution modeling: The Saturday crew as a coordinated work team
  10. -
  11. Visitor arc: Elena’s confidence through the Saturday rush modeled as a life arc
  12. -
  13. Rich prose: Every character and relationship includes narrative perspective
  14. -
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/09-overview.html b/docs/book/reference/09-overview.html deleted file mode 100644 index 3a5e101..0000000 --- a/docs/book/reference/09-overview.html +++ /dev/null @@ -1,409 +0,0 @@ - - - - - - Language Overview - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Language Overview

-
-

The Storybook language enables narrative simulation through structured declarations of characters, behaviors, relationships, and events.

-
-

Philosophy

-

Storybook is a domain-specific language for narrative simulation, influenced by:

-
    -
  • Rust: Strong typing, explicit declarations, and clear ownership semantics
  • -
  • C#: Object-oriented patterns with declarative syntax
  • -
  • Python: Readable, accessible syntax that prioritizes clarity
  • -
-

The language balances technical precision with narrative expressiveness, making it accessible to storytellers while maintaining the rigor developers need.

-

Design Principles

-

1. Code as Narrative

-

Named nodes and prose blocks let code read like stories:

-
behavior Baker_MorningRoutine {
-    choose daily_priority {
-        then prepare_sourdough { ... }
-        then serve_customers { ... }
-        then restock_display { ... }
-    }
-}
-
-

2. Explicit is Better Than Implicit

-

Every declaration is self-documenting:

-
    -
  • Character fields show what defines them
  • -
  • Behavior trees show decision structures
  • -
  • Relationships name their participants
  • -
-

3. Progressive Disclosure

-

Simple cases are simple, complex cases are possible:

-
    -
  • Basic characters need just a name and fields
  • -
  • Templates enable inheritance and reuse
  • -
  • Advanced features (state machines, decorators) available when needed
  • -
-

4. Semantic Validation

-

The compiler catches narrative errors:

-
    -
  • Bond values must be 0.0..1.0
  • -
  • Schedule blocks can’t overlap
  • -
  • Life arc transitions must reference valid states
  • -
-

Language Structure

-

Declaration Types

-

Storybook has 10 top-level declaration types:

-
- - - - - - - - - - -
DeclarationPurposeExample
characterDefine entities with traits and behaviorsA baker with skills and schedule
templateReusable patterns with rangesA generic NPC template
behaviorDecision trees for actionsHow a character responds to events
life_arcState machines for life stagesApprentice → Baker → Master
scheduleTime-based activitiesDaily routine from 6am to 10pm
relationshipConnections between entitiesParent-child with bond values
institutionOrganizations and groupsA bakery with employees
locationPlaces with propertiesThe town square
speciesType definitions with traitsHuman vs Cat vs Rabbit
enumNamed value setsEmotionalState options
-
-

Value Types

-

Fields can contain:

-
    -
  • Primitives: 42, 3.14, "text", true
  • -
  • Time: 08:30:00, 14:15
  • -
  • Duration: 2h30m, 45s
  • -
  • Ranges: 20..40 (for templates)
  • -
  • Identifiers: OtherCharacter, path::to::Thing
  • -
  • Lists: [1, 2, 3]
  • -
  • Objects: { field: value }
  • -
  • Prose blocks: ---tag\nMulti-line\ntext\n---
  • -
-

Expression Language

-

Conditions and queries use:

-
    -
  • Comparisons: age > 18, energy <= 0.5
  • -
  • Equality: status is active, ready is true
  • -
  • Logic: tired and hungry, rich or lucky, not ready
  • -
  • Field access: self.health, other.bond
  • -
  • Quantifiers: forall x in children: x.happy
  • -
-

Compilation Model

-

Source → AST → SBIR → Runtime

-
.sb files → Parser → Abstract Syntax Tree → Resolver → SBIR Binary
-
-

SBIR (Storybook Intermediate Representation) is a compact binary format that:

-
    -
  • Resolves all cross-file references
  • -
  • Validates semantic constraints
  • -
  • Optimizes for simulation runtime
  • -
-

Validation Layers

-
    -
  1. Lexical: Valid tokens and syntax
  2. -
  3. Syntactic: Correct grammar structure
  4. -
  5. Semantic: Type checking, reference resolution
  6. -
  7. Domain: Narrative constraints (bond ranges, schedule overlaps)
  8. -
-

File Organization

-

Project Structure

-
my-storybook/
-├── characters/
-│   ├── baker.sb
-│   └── family.sb
-├── behaviors/
-│   └── daily_routine.sb
-├── world/
-│   ├── locations.sb
-│   └── institutions.sb
-└── schema/
-    ├── species.sb
-    └── templates.sb
-
-

Import System

-

Use use statements to reference definitions from other files:

-
use schema::species::Human;
-use schema::templates::Adult;
-
-character Baker: Human from Adult {
-    // ...
-}
-
-

Resolution order:

-
    -
  1. Same file
  2. -
  3. Explicitly imported
  4. -
  5. Error if not found
  6. -
-

Quick Reference

-

Character Declaration

-
character Name: Species from Template {
-    field: value
-    field: value
-    ---prose_tag
-    Text content
-    ---
-}
-
-

Behavior Tree

-
behavior Name {
-    choose label {           // Selector
-        then label { ... }   // Sequence
-        if (condition)       // Condition
-        ActionName          // Action
-        include path        // Subtree
-    }
-}
-
-

Life Arc

-
life_arc Name {
-    state StateName {
-        on condition -> NextState
-    }
-}
-
-

Schedule

-
schedule Name {
-    08:00 -> 12:00: activity { }
-    12:00 -> 13:00: lunch { }
-}
-
-

Relationship

-
relationship Name {
-    Person1 as role
-    Person2 as role
-    bond: 0.85
-}
-
-

Next Steps

-

Dive deeper into each declaration type:

- -
-

Philosophy Note: Storybook treats narrative as data. Characters aren’t objects with methods - they’re declarations of traits, connected by behaviors and relationships. This separation enables rich analysis, modification, and simulation of narrative worlds.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/10-characters.html b/docs/book/reference/10-characters.html deleted file mode 100644 index 5c658bc..0000000 --- a/docs/book/reference/10-characters.html +++ /dev/null @@ -1,611 +0,0 @@ - - - - - - Characters - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Characters

-

Characters are the primary entities in Storybook—the people, creatures, and beings that inhabit your world. Each character has a set of attributes that define who they are, what they can do, and how they relate to the world around them.

-

Syntax

-
<character-decl> ::= "character" <identifier> <species-clause>? <template-clause>? <body>
-
-<species-clause> ::= ":" <qualified-path>
-
-<template-clause> ::= "from" <qualified-path> ("," <qualified-path>)*
-
-<body> ::= "{" <body-item>* "}"
-
-<body-item> ::= <field>
-              | <uses-behaviors>
-              | <uses-schedule>
-
-<uses-behaviors> ::= "uses" "behaviors" ":" <behavior-link-list>
-
-<uses-schedule> ::= "uses" ("schedule" | "schedules") ":" (<qualified-path> | <schedule-list>)
-
-<behavior-link-list> ::= "[" <behavior-link> ("," <behavior-link>)* "]"
-
-<behavior-link> ::= "{" <behavior-link-field>* "}"
-
-<behavior-link-field> ::= "tree" ":" <qualified-path>
-                        | "when" ":" <expression>
-                        | "priority" ":" ("low" | "normal" | "high" | "critical")
-
-<schedule-list> ::= "[" <qualified-path> ("," <qualified-path>)* "]"
-
-<field> ::= <identifier> ":" <value>
-
-<value> ::= <literal>
-          | <qualified-path>
-          | <list>
-          | <object>
-          | <prose-block>
-          | <override>
-
-<prose-block> ::= "---" <identifier> <content> "---"
-
-

Components

-

Name

-

The character’s identifier. Must be unique within its scope and follow standard identifier rules (alphanumeric + underscore, cannot start with digit).

-

Species (Optional)

-

The species clause (: SpeciesName) defines what the character fundamentally is. This is distinct from templates, which define what attributes they have.

-
    -
  • Purpose: Ontological typing—what kind of being this is
  • -
  • Validation: Must reference a defined species declaration
  • -
  • Single inheritance: A character can only have one species
  • -
  • Default behavior: Species fields are inherited automatically
  • -
-

Example:

-
character Martha: Human {
-    age: 34
-}
-
-

Template Inheritance (Optional)

-

The template clause (from Template1, Template2) specifies templates from which the character inherits fields. Templates provide reusable attribute sets.

-
    -
  • Purpose: Compositional inheritance—mix-and-match capabilities and traits
  • -
  • Multiple inheritance: Characters can inherit from multiple templates
  • -
  • Merge semantics: Fields from later templates override earlier ones
  • -
  • Override allowed: Character fields override all inherited fields
  • -
-

Example:

-
character Martha: Human from Baker, BusinessOwner {
-    specialty: "sourdough"
-}
-
-

Fields

-

Fields define the character’s attributes using the standard field syntax. All value types are supported.

-

Common field categories:

-
    -
  • Physical traits: height, weight, age, eye_color
  • -
  • Personality: confidence, patience, dedication
  • -
  • Professional: skill_level, specialty, recipes_mastered
  • -
  • State tracking: energy, mood, orders_today
  • -
  • Capabilities: can_teach, can_work_independently
  • -
-

Prose Blocks

-

Characters can contain multiple prose blocks for narrative content. Common tags:

-
    -
  • ---backstory: Character history and origin
  • -
  • ---appearance: Physical description
  • -
  • ---personality: Behavioral traits and quirks
  • -
  • ---motivation: Goals and desires
  • -
  • ---secrets: Hidden information
  • -
-

Prose blocks are narrative-only and do not affect simulation logic.

-

Behavior Integration

-

Characters can link to behavior trees using the uses behaviors clause.

-
character Guard {
-    uses behaviors: [
-        {
-            tree: combat::patrol_route
-            priority: normal
-        },
-        {
-            tree: combat::engage_intruder
-            when: threat_detected
-            priority: high
-        }
-    ]
-}
-
-

Each behavior link includes:

-
    -
  • tree: Qualified path to the behavior tree (required)
  • -
  • when: Condition expression for activation (optional)
  • -
  • priority: Execution priority (optional, default: normal)
  • -
-

See Behavior Trees for details on behavior tree syntax and semantics.

-

Schedule Integration

-

Characters can follow schedules using the uses schedule or uses schedules clause.

-
character Baker {
-    uses schedule: BakerySchedule
-}
-
-character Innkeeper {
-    uses schedules: [WeekdaySchedule, WeekendSchedule]
-}
-
-
    -
  • Single schedule: uses schedule: ScheduleName
  • -
  • Multiple schedules: uses schedules: [Schedule1, Schedule2]
  • -
-

The runtime selects the appropriate schedule based on temporal constraints. See Schedules for composition and selection semantics.

-

Species vs. Templates

-

The distinction between species (:) and templates (from) reflects ontological vs. compositional typing:

-
- - - - - -
FeatureSpecies (:)Templates (from)
SemanticsWhat the character isWhat the character has
CardinalityExactly oneZero or more
Example: Human, : Dragonfrom Warrior, Mage
PurposeFundamental natureReusable trait sets
OverrideCan override species fieldsCan override template fields
-
-

Example showing both:

-
species Dragon {
-    max_lifespan: 1000
-    can_fly: true
-}
-
-template Hoarder {
-    treasure_value: 0..1000000
-    greed_level: 0.0..1.0
-}
-
-template Ancient {
-    age: 500..1000
-    wisdom: 0.8..1.0
-}
-
-character Smaug: Dragon from Hoarder, Ancient {
-    age: 850
-    treasure_value: 500000
-    greed_level: 0.95
-}
-
-

Field Resolution Order

-

When a character inherits from species and templates, fields are resolved in this order (later overrides earlier):

-
    -
  1. Species fields (base ontology)
  2. -
  3. Template fields (left to right in from clause)
  4. -
  5. Character fields (highest priority)
  6. -
-

Example:

-
species Human {
-    lifespan: 80
-    speed: 1.0
-}
-
-template Warrior {
-    speed: 1.5
-    strength: 10
-}
-
-template Berserker {
-    speed: 2.0
-    strength: 15
-}
-
-character Conan: Human from Warrior, Berserker {
-    strength: 20
-}
-
-// Resolved fields:
-// lifespan: 80     (from Human)
-// speed: 2.0       (Berserker overrides Warrior overrides Human)
-// strength: 20     (character overrides Berserker)
-
-

Validation Rules

-

The Storybook compiler enforces these validation rules:

-
    -
  1. Unique names: Character names must be unique within their module
  2. -
  3. Species exists: If specified, the species must reference a defined species declaration
  4. -
  5. Templates exist: All templates in the from clause must reference defined template declarations
  6. -
  7. No circular inheritance: Templates cannot form circular dependency chains
  8. -
  9. Field type consistency: Field values must match expected types from species/templates
  10. -
  11. Reserved fields: Cannot use reserved keywords as field names
  12. -
  13. Behavior trees exist: All behavior tree references must resolve to defined behavior declarations
  14. -
  15. Schedules exist: All schedule references must resolve to defined schedule declarations
  16. -
  17. Prose tag uniqueness: Each prose tag can appear at most once per character
  18. -
-

Examples

-

Basic Character

-
character SimpleMerchant {
-    name: "Gregor"
-    occupation: "Fish Merchant"
-    wealth: 50
-
-    ---personality
-    A straightforward fish seller at the market. Honest, hardworking,
-    and always smells faintly of mackerel.
-    ---
-}
-
-

Character with Species

-
character Martha: Human {
-    age: 34
-    skill_level: 0.95
-    specialty: "sourdough"
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age
-    twelve. She now runs the most popular bakery in town.
-    ---
-}
-
-

Character with Template Inheritance

-
character Jane: Human from Baker, PastrySpecialist {
-    age: 36
-    specialty: "pastries"
-    recipes_mastered: 120
-
-    years_experience: 18
-    can_teach: true
-
-    ---appearance
-    A focused woman with flour-dusted apron and steady hands.
-    Known for her intricate pastry decorations and precise
-    temperature control.
-    ---
-}
-
-

Character with All Features

-
character CityGuard: Human from CombatTraining, LawEnforcement {
-    age: 30
-    rank: "Sergeant"
-
-    // Physical traits
-    height: 175
-    strength: 12
-
-    // Equipment
-    has_weapon: true
-    armor_level: 2
-
-    // Behavior integration
-    uses behaviors: [
-        {
-            tree: guards::patrol_route
-            priority: normal
-        },
-        {
-            tree: guards::engage_hostile
-            when: threat_detected
-            priority: high
-        },
-        {
-            tree: guards::sound_alarm
-            when: emergency
-            priority: critical
-        }
-    ]
-
-    // Schedule integration
-    uses schedules: [guards::day_shift, guards::night_shift]
-
-    ---backstory
-    A veteran of the city watch, now responsible for training new recruits
-    while maintaining order in the merchant district.
-    ---
-
-    ---personality
-    Gruff exterior with a hidden soft spot for street children. Follows
-    the rules but knows when to look the other way.
-    ---
-}
-
-

Character with Overrides

-
template WeaponUser {
-    damage: 5..15
-    accuracy: 0.7
-}
-
-character MasterSwordsman: Human from WeaponUser {
-    // Override template range with specific value
-    damage: 15
-    accuracy: 0.95
-
-    // Add character-specific fields
-    signature_move: "Whirlwind Strike"
-}
-
-

Use Cases

-

Protagonist Definition

-

Define rich, dynamic protagonists with complex attributes:

-
character Elena: Human from Scholar, Diplomat {
-    age: 28
-    intelligence: 18
-    charisma: 16
-
-    languages_known: ["Common", "Elvish", "Draconic"]
-    books_read: 347
-
-    current_quest: "Broker peace between warring kingdoms"
-
-    ---backstory
-    Raised in the Grand Library, Elena discovered ancient texts that
-    hinted at a forgotten alliance between humans and dragons. She now
-    seeks to revive that alliance to end the current war.
-    ---
-}
-
-

NPC Templates

-

Create diverse NPCs from templates:

-
template Villager {
-    occupation: "Farmer"
-    wealth: 10..50
-    disposition: 0.0..1.0  // 0=hostile, 1=friendly
-}
-
-character Oswald: Human from Villager {
-    occupation: "Blacksmith"
-    wealth: 45
-    disposition: 0.8
-}
-
-character Mildred: Human from Villager {
-    occupation: "Baker"
-    wealth: 35
-    disposition: 0.95
-}
-
-

Ensemble Casts

-

Define multiple related characters:

-
template BakeryStaff {
-    punctuality: 0.5..1.0
-    teamwork: 0.5..1.0
-}
-
-template Apprentice {
-    skill_level: 0.0..0.5
-    dedication: 0.5..1.0
-}
-
-character Elena: Human from BakeryStaff, Apprentice {
-    age: 16
-    natural_talent: 0.8
-    dedication: 0.9
-
-    ---backstory
-    Elena comes from a family of farmers who could never afford to
-    buy bread from the bakery. When Martha offered her an apprenticeship,
-    she jumped at the chance to learn a trade.
-    ---
-}
-
-

Cross-References

- - -
    -
  • Instantiation: Characters are concrete instances; they cannot be instantiated further
  • -
  • Composition: Prefer template composition over deep species hierarchies
  • -
  • Modularity: Characters can reference behaviors and schedules from other modules
  • -
  • Narrative-driven: Use prose blocks to embed storytelling directly with data
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/11-behavior-trees.html b/docs/book/reference/11-behavior-trees.html deleted file mode 100644 index c9626cd..0000000 --- a/docs/book/reference/11-behavior-trees.html +++ /dev/null @@ -1,883 +0,0 @@ - - - - - - Behavior Trees - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Behavior Trees

-

Behavior trees define the decision-making logic for characters, institutions, and other entities. They model how an entity chooses actions, responds to conditions, and adapts to its environment. Storybook uses behavior trees for character AI, NPC routines, and complex reactive behavior.

-

What is a Behavior Tree?

-

A behavior tree is a hierarchical structure that executes from root to leaves, making decisions based on success/failure of child nodes:

-
    -
  • Composite nodes (choose, then) have multiple children and control flow
  • -
  • Condition nodes (if, when) test predicates
  • -
  • Action nodes execute concrete behaviors
  • -
  • Decorator nodes (repeat, invert, timeout, etc.) modify child behavior
  • -
  • Subtree nodes (include) reference other behavior trees
  • -
-

Behavior trees are evaluated every tick (frame), flowing through the tree from root to leaves until a node returns success or failure.

-

Syntax

-
<behavior-decl> ::= "behavior" <identifier> <body>
-
-<body> ::= "{" <prose-blocks>* <behavior-node> "}"
-
-<behavior-node> ::= <selector>
-                  | <sequence>
-                  | <condition>
-                  | <action>
-                  | <decorator>
-                  | <subtree>
-
-<selector> ::= "choose" <label>? "{" <behavior-node>+ "}"
-
-<sequence> ::= "then" <label>? "{" <behavior-node>+ "}"
-
-<condition> ::= ("if" | "when") "(" <expression> ")"
-
-<action> ::= <identifier> ( "(" <param-list> ")" )?
-
-<param-list> ::= <field> ("," <field>)*
-
-<decorator> ::= <decorator-type> ("(" <params> ")")? "{" <behavior-node> "}"
-
-<subtree> ::= "include" <qualified-path>
-
-<label> ::= <identifier>
-
-

Composite Nodes

-

Selector: choose

-

A selector tries its children in order until one succeeds. Returns success if any child succeeds, failure if all fail.

-

Execution:

-
    -
  1. Try first child
  2. -
  3. If succeeds -> return success
  4. -
  5. If fails -> try next child
  6. -
  7. If all fail -> return failure
  8. -
-

Use case: “Try A, if that fails try B, if that fails try C…”

-
behavior GuardBehavior {
-    choose guard_actions {
-        AttackIntruder      // Try first
-        SoundAlarm          // If attack fails, sound alarm
-        FleeInPanic         // If alarm fails, flee
-    }
-}
-
-

Named selectors:

-
choose service_options {
-    then serve_regular {
-        CustomerIsWaiting
-        TakeOrder
-    }
-
-    then restock_display {
-        DisplayIsLow
-        FetchFromKitchen
-    }
-}
-
-

Labels are optional but recommended for complex trees–they improve readability and debugging.

-

Sequence: then

-

A sequence runs its children in order until one fails. Returns success only if all children succeed, failure if any fails.

-

Execution:

-
    -
  1. Run first child
  2. -
  3. If fails -> return failure
  4. -
  5. If succeeds -> run next child
  6. -
  7. If all succeed -> return success
  8. -
-

Use case: “Do A, then B, then C… all must succeed”

-
behavior BrewingSequence {
-    then brew_potion {
-        GatherIngredients   // Must succeed
-        MixIngredients      // Then this must succeed
-        Boil                // Then this must succeed
-        BottlePotion        // Finally this
-    }
-}
-
-

Named sequences:

-
then prepare_sourdough {
-    MixDough
-    KneadDough
-    ShapeLoaves
-}
-
-

Nesting Composites

-

Composite nodes can nest arbitrarily deep:

-
behavior ComplexAI {
-    choose root_decision {
-        // Combat branch
-        then engage_combat {
-            if(enemy_nearby)
-            choose combat_tactics {
-                AttackWithSword
-                AttackWithMagic
-                DefendAndWait
-            }
-        }
-
-        // Exploration branch
-        then explore_area {
-            if(safe)
-            choose exploration_mode {
-                SearchForTreasure
-                MapTerritory
-                Rest
-            }
-        }
-
-        // Default: Idle
-        Idle
-    }
-}
-
-

Condition Nodes

-

Conditions test expressions and return success/failure based on the result.

-

if vs. when

-

Both are semantically identical–use whichever reads better in context:

-
behavior Example {
-    choose options {
-        // "if" for state checks
-        then branch_a {
-            if(player_nearby)
-            Attack
-        }
-
-        // "when" for event-like conditions
-        then branch_b {
-            when(alarm_triggered)
-            Flee
-        }
-    }
-}
-
-

Condition Syntax

-
if(health < 20)                          // Comparison
-when(is_hostile)                         // Boolean field
-if(distance > 10 and has_weapon)         // Logical AND
-when(not is_stunned or is_enraged)       // Logical OR with NOT
-
-

See Expression Language for complete expression syntax.

-

Action Nodes

-

Actions are leaf nodes that execute concrete behaviors. They reference action implementations in the runtime.

-

Basic Actions

-
behavior SimpleActions {
-    then do_things {
-        MoveForward
-        TurnLeft
-        Attack
-    }
-}
-
-

Actions with Parameters

-

Actions can have named parameters using parenthesis syntax:

-
behavior ParameterizedActions {
-    then patrol {
-        MoveTo(destination: "Waypoint1", speed: 1.5)
-        WaitFor(duration: 5s)
-        MoveTo(destination: "Waypoint2", speed: 1.5)
-    }
-}
-
-

Parameter passing:

-
    -
  • Parameters are passed as fields (name: value)
  • -
  • All value types supported
  • -
  • Runtime validates parameter types
  • -
-
behavior RichParameters {
-    then complex_action {
-        CastSpell(spell: "Fireball", target: enemy_position, power: 75, multicast: false)
-        Heal(amount: 50, target: self)
-    }
-}
-
-

Decorator Nodes

-

Decorators wrap a single child node and modify its behavior. See Decorators for complete reference.

-

Common Decorators

-
behavior DecoratorExamples {
-    choose {
-        // Repeat infinitely
-        repeat {
-            PatrolRoute
-        }
-
-        // Repeat exactly 3 times
-        repeat(3) {
-            CheckDoor
-        }
-
-        // Repeat 2 to 5 times
-        repeat(2..5) {
-            SearchArea
-        }
-
-        // Invert success/failure
-        invert {
-            IsEnemyNearby  // Returns success if enemy NOT nearby
-        }
-
-        // Retry up to 5 times on failure
-        retry(5) {
-            OpenLockedDoor
-        }
-
-        // Timeout after 10 seconds
-        timeout(10s) {
-            SolveComplexPuzzle
-        }
-
-        // Cooldown: only run once per 30 seconds
-        cooldown(30s) {
-            FireCannon
-        }
-
-        // If: only run if condition true
-        if(health > 50) {
-            AggressiveAttack
-        }
-
-        // Always succeed regardless of child result
-        succeed_always {
-            AttemptOptionalTask
-        }
-
-        // Always fail regardless of child result
-        fail_always {
-            ImpossipleTask
-        }
-    }
-}
-
-

Subtree References

-

The include keyword references another behavior tree, enabling modularity and reuse.

-

Basic Subtree

-
behavior PatrolRoute {
-    then patrol {
-        MoveTo(destination: "Waypoint1")
-        MoveTo(destination: "Waypoint2")
-        MoveTo(destination: "Waypoint3")
-    }
-}
-
-behavior GuardBehavior {
-    choose guard_ai {
-        then combat {
-            if(enemy_nearby)
-            include combat::engage
-        }
-
-        include PatrolRoute  // Reuse patrol behavior
-    }
-}
-
-

Qualified Subtree References

-
behavior ComplexAI {
-    choose ai_modes {
-        include behaviors::combat::melee
-        include behaviors::combat::ranged
-        include behaviors::exploration::search
-        include behaviors::social::greet
-    }
-}
-
-

Named Nodes

-

Both composite nodes (choose, then) can have optional labels:

-
behavior NamedNodeExample {
-    choose daily_priority {                  // Named selector
-        then handle_special_orders {         // Named sequence
-            CheckOrderQueue
-            PrepareSpecialIngredients
-            BakeSpecialItem
-        }
-
-        choose regular_work {               // Named selector
-            then morning_bread {             // Named sequence
-                MixSourdough
-                BakeLoaves
-            }
-        }
-    }
-}
-
-

Benefits:

-
    -
  • Readability: Tree structure is self-documenting
  • -
  • Debugging: Named nodes appear in execution traces
  • -
  • Narrative: Labels can be narrative (“handle_special_orders” vs. anonymous node)
  • -
-

Guidelines:

-
    -
  • Use labels for important structural nodes
  • -
  • Use descriptive, narrative names
  • -
  • Omit labels for trivial nodes
  • -
-

Complete Examples

-

Simple Guard AI

-
behavior GuardPatrol {
-    choose guard_logic {
-        // Combat if enemy nearby
-        then combat_mode {
-            if(enemy_nearby and has_weapon)
-            Attack
-        }
-
-        // Sound alarm if see intruder
-        then alarm_mode {
-            if(intruder_detected)
-            SoundAlarm
-        }
-
-        // Default: Patrol
-        then patrol_mode {
-            include PatrolRoute
-        }
-    }
-}
-
-

Complex NPC Behavior

-
behavior Innkeeper_DailyRoutine {
-    ---description
-    The innkeeper's behavior throughout the day. Uses selectors for
-    decision-making and sequences for multi-step actions.
-    ---
-
-    choose daily_activity {
-        // Morning: Prepare for opening
-        then morning_prep {
-            when(time_is_morning)
-            then prep_sequence {
-                UnlockDoor
-                LightFireplace
-                PrepareBreakfast
-                WaitForGuests
-            }
-        }
-
-        // Day: Serve customers
-        then day_service {
-            when(time_is_daytime)
-            choose service_mode {
-                // Serve customer if present
-                then serve {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                    ServeMeal
-                    CollectPayment
-                }
-
-                // Restock if needed
-                then restock {
-                    if(inventory_low)
-                    ReplenishInventory
-                }
-
-                // Default: Clean
-                CleanTables
-            }
-        }
-
-        // Night: Close up
-        then evening_close {
-            when(time_is_evening)
-            then close_sequence {
-                DismissRemainingGuests
-                LockDoor
-                CountMoney
-                GoToBed
-            }
-        }
-    }
-}
-
-

Morning Baking Routine

-
behavior Baker_MorningRoutine {
-    ---description
-    Martha's morning routine: prepare dough step by step,
-    from mixing to shaping to baking.
-    ---
-
-    then morning_baking {
-        // Start with sourdough
-        then prepare_starter {
-            CheckStarter
-            FeedStarter
-            WaitForActivity
-        }
-
-        // Mix the dough
-        then mix_dough {
-            MeasureFlour
-            AddWater
-            IncorporateStarter
-        }
-
-        // Knead and shape
-        then shape_loaves {
-            KneadDough
-            FirstRise
-            ShapeLoaves
-        }
-
-        // Bake
-        then bake {
-            PreHeatOven
-            LoadLoaves
-            MonitorBaking
-        }
-    }
-}
-
-

Repeating Behavior

-
behavior Bakery_CustomerServiceLoop {
-    ---description
-    The bakery's continuous customer service loop. Uses infinite
-    repeat decorator to serve customers throughout the day.
-    ---
-
-    repeat {
-        then service_cycle {
-            // Check for customers
-            choose service_mode {
-                then serve_waiting {
-                    if(customer_waiting)
-                    GreetCustomer
-                    TakeOrder
-                }
-
-                then restock_display {
-                    if(display_low)
-                    FetchFromKitchen
-                    ArrangeOnShelves
-                }
-            }
-
-            // Process payment
-            CollectPayment
-            ThankCustomer
-
-            // Brief pause between customers
-            timeout(5s) {
-                CleanCounter
-            }
-
-            PrepareForNextCustomer
-        }
-    }
-}
-
-

Retry Logic for Delicate Recipes

-
behavior Baker_DelicatePastry {
-    ---description
-    Elena attempting a delicate pastry recipe that requires
-    precise technique. Uses retry decorator for persistence.
-    ---
-
-    choose baking_strategy {
-        // Try when conditions are right
-        then attempt_pastry {
-            if(oven_at_temperature)
-            // Try up to 3 times
-            retry(3) {
-                then make_pastry {
-                    RollDoughThin
-                    ApplyFilling
-                    FoldAndSeal
-                    CheckForLeaks
-                }
-            }
-        }
-
-        // If oven not ready, prepare meanwhile
-        then prepare_meanwhile {
-            if(not oven_at_temperature)
-            then prep_sequence {
-                PrepareIngredients
-                MixFilling
-                ChillDough
-            }
-        }
-    }
-}
-
-

Integration with Characters

-

Characters link to behaviors using the uses behaviors clause:

-
character Guard {
-    uses behaviors: [
-        {
-            tree: guards::patrol_route
-            priority: normal
-        },
-        {
-            tree: guards::engage_hostile
-            when: threat_detected
-            priority: high
-        },
-        {
-            tree: guards::sound_alarm
-            when: emergency
-            priority: critical
-        }
-    ]
-}
-
-

Behavior selection:

-
    -
  • Multiple behaviors evaluated by priority (critical > high > normal > low)
  • -
  • Conditions (when clause) gate behavior activation
  • -
  • Higher-priority behaviors preempt lower-priority ones
  • -
-

See Characters for complete behavior linking syntax.

-

Execution Semantics

-

Tick-Based Evaluation

-

Behavior trees execute every “tick” (typically once per frame):

-
    -
  1. Start at root node
  2. -
  3. Traverse down to leaves based on composite logic
  4. -
  5. Execute leaf nodes (conditions, actions)
  6. -
  7. Return success/failure up the tree
  8. -
  9. Repeat next tick
  10. -
-

Node Return Values

-

Every node returns one of:

-
    -
  • Success: Node completed successfully
  • -
  • Failure: Node failed
  • -
  • Running: Node still executing (async action)
  • -
-

Stateful vs. Stateless

-
    -
  • Stateless nodes: Evaluate fresh every tick (conditions, simple actions)
  • -
  • Stateful nodes: Maintain state across ticks (decorators, long actions)
  • -
-

Example of stateful behavior:

-
behavior LongAction {
-    timeout(30s) {           // Stateful: tracks elapsed time
-        ComplexCalculation   // May take multiple ticks
-    }
-}
-
-

Validation Rules

-
    -
  1. At least one node: Behavior body must contain at least one node
  2. -
  3. Composite children: choose and then require at least one child
  4. -
  5. Decorator child: Decorators require exactly one child
  6. -
  7. Action exists: Action names must reference registered actions in runtime
  8. -
  9. Subtree exists: include must reference a defined behavior declaration
  10. -
  11. Expression validity: Condition expressions must be well-formed
  12. -
  13. Duration format: Decorator durations must be valid (e.g., 5s, 10m)
  14. -
  15. Unique labels: Node labels (if used) should be unique within their parent
  16. -
  17. Parameter types: Action parameters must match expected types
  18. -
-

Best Practices

-

1. Prefer Shallow Trees

-

Avoid:

-
choose {
-    then { then { then { then { Action } } } }  // Too deep!
-}
-
-

Prefer:

-
choose root {
-    include combat_tree
-    include exploration_tree
-    include social_tree
-}
-
-

2. Use Named Nodes for Clarity

-

Avoid:

-
choose {
-    then {
-        IsHungry
-        FindFood
-        Eat
-    }
-    Wander
-}
-
-

Prefer:

-
choose survival {
-    then eat_if_hungry {
-        IsHungry
-        FindFood
-        Eat
-    }
-    Wander
-}
-
-

3. Subtrees for Reusability

-

Avoid: Duplicating logic across behaviors

-

Prefer:

-
behavior Combat_Common {
-    then attack_sequence {
-        DrawWeapon
-        Approach
-        Strike
-    }
-}
-
-behavior Warrior {
-    include Combat_Common
-}
-
-behavior Guard {
-    include Combat_Common
-}
-
-

4. Decorators for Timing

-

Avoid: Manual timing in actions

-

Prefer:

-
timeout(10s) {
-    ComplexTask
-}
-
-cooldown(30s) {
-    SpecialAbility
-}
-
-

5. Guard for Preconditions

-

Avoid:

-
then problematic {
-    ExpensiveAction  // Always runs even if inappropriate
-}
-
-

Prefer:

-
if(can_afford_action) {
-    ExpensiveAction  // Only runs when condition passes
-}
-
-

Cross-References

- - -
    -
  • Reactive AI: Behavior trees continuously react to changing conditions
  • -
  • Hierarchical decision-making: Composite nodes create decision hierarchies
  • -
  • Modularity: Subtrees enable behavior reuse and composition
  • -
  • Narrative-driven design: Named nodes make behavior trees readable as stories
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/12-decorators.html b/docs/book/reference/12-decorators.html deleted file mode 100644 index 4f5682f..0000000 --- a/docs/book/reference/12-decorators.html +++ /dev/null @@ -1,837 +0,0 @@ - - - - - - Decorators - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Decorators

-

Decorators are special nodes that wrap a single child and modify its execution behavior. They enable timing control, retry logic, conditional execution, and result inversion without modifying the child node itself.

-

What Are Decorators?

-

Decorators sit between a parent and child node, transforming the child’s behavior:

-
Parent
-  └─ Decorator
-       └─ Child
-
-

The decorator intercepts the child’s execution, potentially:

-
    -
  • Repeating it multiple times
  • -
  • Timing it out
  • -
  • Inverting its result
  • -
  • Guarding its execution
  • -
  • Forcing a specific result
  • -
-

Decorator Types

-

Storybook provides 10 decorator types:

-
- - - - - - - - - - -
DecoratorPurposeExample
repeatLoop infinitelyrepeat { Patrol }
repeat(N)Loop N timesrepeat(3) { Check }
repeat(min..max)Loop min to max timesrepeat(2..5) { Search }
invertFlip success/failureinvert { IsEnemy }
retry(N)Retry on failure (max N times)retry(5) { Open }
timeout(duration)Fail after durationtimeout(10s) { Solve }
cooldown(duration)Run at most once per durationcooldown(30s) { Fire }
if(condition)Only run if condition trueif(health > 50) { Attack }
succeed_alwaysAlways return successsucceed_always { Try }
fail_alwaysAlways return failurefail_always { Test }
-
-

Syntax

-
<decorator> ::= <repeat-decorator>
-              | <invert-decorator>
-              | <retry-decorator>
-              | <timeout-decorator>
-              | <cooldown-decorator>
-              | <if-decorator>
-              | <force-result-decorator>
-
-<repeat-decorator> ::= "repeat" <repeat-spec>? "{" <behavior-node> "}"
-
-<repeat-spec> ::= "(" <number> ")"
-                | "(" <number> ".." <number> ")"
-
-<invert-decorator> ::= "invert" "{" <behavior-node> "}"
-
-<retry-decorator> ::= "retry" "(" <number> ")" "{" <behavior-node> "}"
-
-<timeout-decorator> ::= "timeout" "(" <duration-literal> ")" "{" <behavior-node> "}"
-
-<cooldown-decorator> ::= "cooldown" "(" <duration-literal> ")" "{" <behavior-node> "}"
-
-<if-decorator> ::= "if" "(" <expression> ")" "{" <behavior-node> "}"
-
-<force-result-decorator> ::= ("succeed_always" | "fail_always") "{" <behavior-node> "}"
-
-<duration-literal> ::= <number> ("s" | "m" | "h" | "d")
-
-

Repeat Decorators

-

Infinite Repeat: repeat

-

Loops the child infinitely. The child is re-executed immediately after completing (success or failure).

-
behavior InfinitePatrol {
-    repeat {
-        PatrolRoute
-    }
-}
-
-

Execution:

-
    -
  1. Run child
  2. -
  3. Child completes (success or failure)
  4. -
  5. Immediately run child again
  6. -
  7. Go to step 2 (forever)
  8. -
-

Use cases:

-
    -
  • Perpetual patrols
  • -
  • Endless background processes
  • -
  • Continuous monitoring
  • -
-

Warning: Infinite loops never return to parent. Ensure they’re appropriate for your use case.

-

Repeat N Times: repeat N

-

Repeats the child exactly N times, then returns success.

-
behavior CheckThreeTimes {
-    repeat(3) {
-        CheckDoor
-    }
-}
-
-

Execution:

-
    -
  1. Counter = 0
  2. -
  3. Run child
  4. -
  5. Counter++
  6. -
  7. If counter < N, go to step 2
  8. -
  9. Return success
  10. -
-

Use cases:

-
    -
  • Fixed iteration counts
  • -
  • “Try three times then give up”
  • -
  • Deterministic looping
  • -
-

Repeat Range: repeat min..max

-

Repeats the child between min and max times. At runtime, a specific count is selected within the range.

-
behavior SearchRandomly {
-    repeat(2..5) {
-        SearchArea
-    }
-}
-
-

Execution:

-
    -
  1. Select count C randomly from [min, max]
  2. -
  3. Repeat child C times (as in repeat N)
  4. -
-

Use cases:

-
    -
  • Variable behavior
  • -
  • Procedural variation
  • -
  • Non-deterministic actions
  • -
-

Validation:

-
    -
  • min ≥ 0
  • -
  • max ≥ min
  • -
  • Both must be integers
  • -
-

Invert Decorator

-

Inverts the child’s return value: success becomes failure, failure becomes success.

-
behavior AvoidEnemies {
-    invert {
-        IsEnemyNearby  // Success if NOT nearby
-    }
-}
-
-

Truth table:

-
- - - -
Child returnsDecorator returns
SuccessFailure
FailureSuccess
RunningRunning (unchanged)
-
-

Use cases:

-
    -
  • Negating conditions (“if NOT X”)
  • -
  • Inverting success criteria
  • -
  • Converting “found” to “not found”
  • -
-

Example:

-
behavior SafeExploration {
-    choose safe_actions {
-        // Only explore if NOT dangerous
-        then explore {
-            invert { IsDangerous }
-            ExploreArea
-        }
-
-        // Default: Stay put
-        Wait
-    }
-}
-
-

Retry Decorator

-

Retries the child up to N times on failure. Returns success if any attempt succeeds, failure if all N attempts fail.

-
behavior PersistentDoor {
-    retry(5) {
-        OpenLockedDoor
-    }
-}
-
-

Execution:

-
    -
  1. Attempts = 0
  2. -
  3. Run child
  4. -
  5. If child succeeds → return success
  6. -
  7. If child fails: -
      -
    • Attempts++
    • -
    • If attempts < N, go to step 2
    • -
    • Else return failure
    • -
    -
  8. -
-

Use cases:

-
    -
  • Unreliable actions (lockpicking, persuasion)
  • -
  • Network/resource operations
  • -
  • Probabilistic success
  • -
-

Example with context:

-
behavior Thief_PickLock {
-    then attempt_entry {
-        // Try to pick lock (may fail)
-        retry(3) {
-            PickLock
-        }
-
-        // If succeeded, enter
-        EnterBuilding
-
-        // If failed after 3 tries, give up
-    }
-}
-
-

Validation:

-
    -
  • N must be ≥ 1
  • -
-

Timeout Decorator

-

Fails the child if it doesn’t complete within the specified duration.

-
behavior TimeLimitedPuzzle {
-    timeout(30s) {
-        SolvePuzzle
-    }
-}
-
-

Execution:

-
    -
  1. Start timer
  2. -
  3. Run child each tick
  4. -
  5. If child completes before timeout → return child’s result
  6. -
  7. If timer expires → return failure (interrupt child)
  8. -
-

Use cases:

-
    -
  • Time-limited actions
  • -
  • Preventing infinite loops
  • -
  • Enforcing deadlines
  • -
-

Duration formats:

-
    -
  • 5s - 5 seconds
  • -
  • 10m - 10 minutes
  • -
  • 2h - 2 hours
  • -
  • 3d - 3 days
  • -
-

Example:

-
behavior QuickDecision {
-    choose timed_choice {
-        // Give AI 5 seconds to find optimal move
-        timeout(5s) {
-            CalculateOptimalStrategy
-        }
-
-        // Fallback: Use simple heuristic
-        UseQuickHeuristic
-    }
-}
-
-

Notes:

-
    -
  • Timer starts when decorator is first entered
  • -
  • Timer resets if decorator exits and re-enters
  • -
  • Child node should handle interruption gracefully
  • -
-

Cooldown Decorator

-

Prevents the child from running more than once per cooldown period. Fails immediately if called within cooldown.

-
behavior SpecialAbility {
-    cooldown(30s) {
-        FireCannon
-    }
-}
-
-

Execution:

-
    -
  1. Check last execution time
  2. -
  3. If (current_time - last_time) < cooldown → return failure
  4. -
  5. Else: -
      -
    • Run child
    • -
    • Record current_time as last_time
    • -
    • Return child’s result
    • -
    -
  6. -
-

Use cases:

-
    -
  • Rate-limiting abilities
  • -
  • Resource cooldowns (spells, items)
  • -
  • Preventing spam
  • -
-

Example:

-
behavior Mage_SpellCasting {
-    choose spells {
-        // Fireball: 10 second cooldown
-        cooldown(10s) {
-            CastFireball
-        }
-
-        // Lightning: 5 second cooldown
-        cooldown(5s) {
-            CastLightning
-        }
-
-        // Basic attack: No cooldown
-        MeleeAttack
-    }
-}
-
-

State management:

-
    -
  • Cooldown state persists across behavior tree ticks
  • -
  • Each cooldown decorator instance has independent state
  • -
  • Cooldown timers are per-entity (not global)
  • -
-

If Decorator

-

Only runs the child if the condition is true. Fails immediately if condition is false.

-
behavior ConditionalAttack {
-    if(health > 50) {
-        AggressiveAttack
-    }
-}
-
-

Execution:

-
    -
  1. Evaluate condition expression
  2. -
  3. If true → run child and return its result
  4. -
  5. If false → return failure (do not run child)
  6. -
-

Use cases:

-
    -
  • Preconditions (“only if X”)
  • -
  • Resource checks (“only if have mana”)
  • -
  • Safety checks (“only if safe”)
  • -
-

Expression syntax: -See Expression Language for complete syntax.

-

Examples:

-
behavior GuardedActions {
-    choose options {
-        // Only attack if have weapon and enemy close
-        if(has_weapon and distance < 10) {
-            Attack
-        }
-
-        // Only heal if health below 50%
-        if(health < (max_health * 0.5)) {
-            Heal
-        }
-
-        // Only flee if outnumbered
-        if(enemy_count > ally_count) {
-            Flee
-        }
-    }
-}
-
-

Comparison with bare if conditions:

-
// Using bare 'if' condition (checks every tick, no body)
-then approach_and_attack {
-    if(enemy_nearby)
-    Approach
-    Attack
-}
-
-// Using 'if' decorator with body (precondition check, fails fast)
-if(enemy_nearby) {
-    then do_attack {
-        Approach
-        Attack
-    }
-}
-
-

The if decorator with a body is more efficient for gating expensive subtrees.

-

Force Result Decorators

-

succeed_always

-

Always returns success, regardless of child’s actual result.

-
behavior TryOptionalTask {
-    succeed_always {
-        AttemptBonus  // Even if fails, we don't care
-    }
-}
-
-

Use cases:

-
    -
  • Optional tasks that shouldn’t block progress
  • -
  • Logging/monitoring actions
  • -
  • Best-effort operations
  • -
-

Example:

-
behavior QuestSequence {
-    then main_quest {
-        TalkToNPC
-
-        // Try to find secret, but don't fail quest if not found
-        succeed_always {
-            SearchForSecretDoor
-        }
-
-        ReturnToQuestGiver
-    }
-}
-
-

fail_always

-

Always returns failure, regardless of child’s actual result.

-
behavior TestFailure {
-    fail_always {
-        AlwaysSucceedsAction  // But we force it to fail
-    }
-}
-
-

Use cases:

-
    -
  • Testing/debugging
  • -
  • Forcing alternative paths
  • -
  • Disabling branches temporarily
  • -
-

Example:

-
behavior UnderConstruction {
-    choose abilities {
-        // Temporarily disabled feature
-        fail_always {
-            NewExperimentalAbility
-        }
-
-        // Fallback to old ability
-        ClassicAbility
-    }
-}
-
-

Combining Decorators

-

Decorators can nest to create complex behaviors:

-
behavior ComplexPattern {
-    // Repeat 3 times, each with 10 second timeout
-    repeat(3) {
-        timeout(10s) {
-            SolveSubproblem
-        }
-    }
-}
-
-

More complex nesting:

-
behavior ResilientAction {
-    // If: Only if health > 30
-    if(health > 30) {
-        // Timeout: Must complete in 20 seconds
-        timeout(20s) {
-            // Retry: Try up to 5 times
-            retry(5) {
-                // Cooldown: Can only run once per minute
-                cooldown(1m) {
-                    PerformComplexAction
-                }
-            }
-        }
-    }
-}
-
-

Execution order: Outside → Inside

-
    -
  1. If checks condition
  2. -
  3. Timeout starts timer
  4. -
  5. Retry begins first attempt
  6. -
  7. Cooldown checks last execution time
  8. -
  9. Child action runs
  10. -
-

Duration Syntax

-

Timeout and cooldown decorators use duration literals:

-
<duration-literal> ::= <number> <unit>
-
-<unit> ::= "s"    // seconds
-         | "m"    // minutes
-         | "h"    // hours
-         | "d"    // days
-
-<number> ::= <digit>+
-
-

Examples:

-
    -
  • 5s - 5 seconds
  • -
  • 30s - 30 seconds
  • -
  • 2m - 2 minutes
  • -
  • 10m - 10 minutes
  • -
  • 1h - 1 hour
  • -
  • 24h - 24 hours
  • -
  • 7d - 7 days
  • -
-

Validation:

-
    -
  • Number must be positive integer
  • -
  • No compound durations (use 120s not 2m if runtime expects seconds)
  • -
  • No fractional units (1.5m not allowed; use 90s)
  • -
-

Comparison Table

-
- - - - - - - - - - -
DecoratorAffects SuccessAffects FailureAffects RunningStateful
repeatRepeatRepeatWaitYes (counter)
repeat NRepeatRepeatWaitYes (counter)
repeat min..maxRepeatRepeatWaitYes (counter)
invert→ Failure→ SuccessUnchangedNo
retry N→ SuccessRetry or failWaitYes (attempts)
timeout dur→ Success→ Success→ Failure if expiredYes (timer)
cooldown dur→ Success→ Success→ SuccessYes (last time)
if(expr)→ Success→ Success→ SuccessNo
succeed_always→ Success→ Success→ SuccessNo
fail_always→ Failure→ Failure→ FailureNo
-
-

Stateful decorators maintain state across ticks. Stateless decorators evaluate fresh every tick.

-

Validation Rules

-
    -
  1. Child required: All decorators must have exactly one child node
  2. -
  3. Repeat count: repeat N requires N ≥ 0
  4. -
  5. Repeat range: repeat min..max requires 0 ≤ min ≤ max
  6. -
  7. Retry count: retry N requires N ≥ 1
  8. -
  9. Duration positive: Timeout/cooldown durations must be > 0
  10. -
  11. Duration format: Must match <number><unit> (e.g., 10s, 5m)
  12. -
  13. Guard expression: Guard condition must be valid expression
  14. -
  15. No empty decorators: repeat { } is invalid (missing child)
  16. -
-

Use Cases by Category

-

Timing Control

-
    -
  • timeout: Prevent infinite loops, enforce time limits
  • -
  • cooldown: Rate-limit abilities, prevent spam
  • -
  • repeat: Continuous processes, patrols
  • -
-

Reliability

-
    -
  • retry: Handle unreliable actions, probabilistic success
  • -
  • if: Precondition checks, resource validation
  • -
  • succeed_always: Optional tasks, best-effort
  • -
-

Logic Control

-
    -
  • invert: Negate conditions, flip results
  • -
  • fail_always: Disable branches, testing
  • -
-

Iteration

-
    -
  • repeat N: Fixed loops, deterministic behavior
  • -
  • repeat min..max: Variable loops, procedural variation
  • -
-

Best Practices

-

1. Use Guards for Expensive Checks

-

Avoid:

-
then expensive {
-    if(complex_condition)
-    ExpensiveOperation
-}
-
-

Prefer:

-
if(complex_condition) {
-    ExpensiveOperation  // Only runs if condition passes
-}
-
-

2. Combine Timeout with Retry

-

Avoid: Infinite retry loops

-

Prefer:

-
timeout(30s) {
-    retry(5) {
-        UnreliableAction
-    }
-}
-
-

3. Use Cooldowns for Rate Limiting

-

Avoid: Manual timing in actions

-

Prefer:

-
cooldown(10s) {
-    FireCannon
-}
-
-

4. Invert for Readable Conditions

-

Avoid:

-
choose options {
-    then branch_a {
-        if(not is_dangerous)
-        Explore
-    }
-}
-
-

Prefer:

-
choose options {
-    then branch_a {
-        invert { IsDangerous }
-        Explore
-    }
-}
-
-

5. succeed_always for Optional Tasks

-

Avoid:

-
then quest {
-    MainTask
-    choose optional {
-        BonusTask
-        DoNothing  // Awkward fallback
-    }
-    NextTask
-}
-
-

Prefer:

-
then quest {
-    MainTask
-    succeed_always { BonusTask }  // Try bonus, don't fail quest
-    NextTask
-}
-
-

Cross-References

- - -
    -
  • Composability: Decorators can nest for complex control flow
  • -
  • Separation of concerns: Decorators handle control flow, children handle logic
  • -
  • State management: Stateful decorators (repeat, retry, timeout, cooldown) persist across ticks
  • -
  • Performance: Guards prevent unnecessary child execution
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/13-life-arcs.html b/docs/book/reference/13-life-arcs.html deleted file mode 100644 index 5225985..0000000 --- a/docs/book/reference/13-life-arcs.html +++ /dev/null @@ -1,845 +0,0 @@ - - - - - - Life Arcs - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Life Arcs

-

Life arcs are state machines that model how characters or other entities evolve over time. They define discrete states and the conditions under which an entity transitions between states. Life arcs capture character development, quest progress, relationship phases, and any other finite-state processes.

-

What is a Life Arc?

-

A life arc is a finite state machine (FSM) composed of:

-
    -
  • States: Discrete phases or modes (e.g., “happy”, “angry”, “sleeping”)
  • -
  • Transitions: Conditional edges between states (e.g., “when health < 20, go to ‘fleeing’”)
  • -
  • On-enter actions: Field updates that occur when entering a state
  • -
-
[State A] --condition--> [State B] --condition--> [State C]
-    |                         |                       |
- on enter                  on enter                on enter
- (set fields)              (set fields)            (set fields)
-
-

Life arcs run continuously, evaluating transitions every tick and moving between states as conditions become true.

-

Syntax

-
<life-arc-decl> ::= "life_arc" <identifier> <body>
-
-<body> ::= "{" <prose-blocks>* <state>+ "}"
-
-<state> ::= "state" <identifier> "{" <state-body>* "}"
-
-<state-body> ::= <on-enter-block>
-               | <transition>
-               | <prose-block>
-
-<on-enter-block> ::= "on" "enter" "{" <field>+ "}"
-
-<transition> ::= "on" <expression> "->" <identifier>
-
-<prose-block> ::= "---" <identifier> <content> "---"
-
-

States

-

A state represents a discrete phase in an entity’s lifecycle.

-

Basic State

-
life_arc SimpleArc {
-    state idle {
-        ---narrative
-        The character is doing nothing, waiting for something to happen.
-        ---
-    }
-
-    state active {
-        ---narrative
-        The character is engaged in their primary activity.
-        ---
-    }
-}
-
-

State Names

-

State names are identifiers that must be unique within the life arc. Use descriptive names:

-
    -
  • Good: idle, combat, sleeping, enlightened
  • -
  • Avoid: state1, s, temp
  • -
-

On-Enter Actions

-

When entering a state, the on enter block updates entity fields.

-

Syntax

-
state state_name {
-    on enter {
-        EntityName.field_name: value
-        EntityName.other_field: other_value
-    }
-}
-
-

Examples

-
life_arc CharacterMood {
-    state happy {
-        on enter {
-            Martha.emotional_state: "happy"
-            Martha.energy: 100
-        }
-    }
-
-    state tired {
-        on enter {
-            Martha.emotional_state: "exhausted"
-            Martha.energy: 20
-        }
-    }
-}
-
-

Field Update Semantics

-
    -
  • Target: EntityName.field_name must reference an existing character/entity
  • -
  • Value: Any valid value type
  • -
  • Effect: Field is set to the specified value when state is entered
  • -
  • Timing: Happens immediately upon transition to the state
  • -
-

Multiple Field Updates

-
state exhausted_baker {
-    on enter {
-        Martha.energy: 0.1
-        Martha.mood: "stressed"
-        Martha.quality_output: 0.7
-        Martha.needs_break: true
-    }
-
-    ---narrative
-    After a sixteen-hour shift during the harvest festival,
-    Martha's hands are shaking. She knows her bread quality is
-    suffering and reluctantly steps away from the oven.
-    ---
-}
-
-

Transitions

-

Transitions define conditional edges between states. When a transition’s condition becomes true, the state machine moves to the target state.

-

Syntax

-
state source_state {
-    on condition_expression -> target_state
-    on another_condition -> another_target
-}
-
-

Basic Transitions

-
life_arc Combat {
-    state fighting {
-        on health < 20 -> fleeing
-        on enemy_defeated -> victorious
-    }
-
-    state fleeing {
-        on safe_distance_reached -> idle
-    }
-
-    state victorious {
-        on celebration_complete -> idle
-    }
-
-    state idle {}
-}
-
-

Expression Conditions

-

Transitions use the full expression language:

-

Comparisons:

-
on health < 20 -> low_health
-on distance > 100 -> far_away
-on count == 0 -> empty
-
-

Boolean fields:

-
on is_hostile -> combat
-on completed -> done
-on not ready -> waiting
-
-

Logical operators:

-
on health < 20 and not has_potion -> desperate
-on is_day or is_lit -> visible
-
-

Complex conditions:

-
on (health < 50 and enemy_count > 3) or surrounded -> retreat
-on forall e in enemies: e.defeated -> victory
-
-

Multiple Transitions

-

A state can have multiple outgoing transitions:

-
state monitoring {
-    on status is "active" -> active_state
-    on status is "inactive" -> inactive_state
-    on status is "error" -> error_state
-    on shutdown_requested -> shutting_down
-}
-
-

Evaluation order:

-
    -
  • Transitions are evaluated in declaration order (top to bottom)
  • -
  • First transition with a true condition is taken
  • -
  • If no conditions are true, state remains unchanged
  • -
-

Self-Transitions

-

A state can transition to itself:

-
state patrolling {
-    on enemy_spotted -> combat
-    on checkpoint_reached -> patrolling  // Reset patrol state
-}
-
-

Complete Examples

-

Elena’s Career Journey

-
life_arc ElenaCareer {
-    ---description
-    Tracks Elena's progression from nervous apprentice to confident
-    master baker. Each state represents a key phase of her career.
-    ---
-
-    state early_apprentice {
-        on enter {
-            Elena.skill_level: novice
-            Elena.confidence: timid
-        }
-
-        on recipes_mastered > 5 -> growing_apprentice
-
-        ---narrative
-        Elena's hands shake as she measures flour. She checks the
-        recipe three times before adding each ingredient. Martha
-        patiently corrects her technique.
-        ---
-    }
-
-    state growing_apprentice {
-        on enter {
-            Elena.skill_level: beginner
-            Elena.confidence: uncertain
-        }
-
-        on recipes_mastered > 15 -> journeyman
-
-        ---narrative
-        The shaking stops. Elena can make basic breads without
-        looking at the recipe. She still doubts herself but
-        Martha's encouragement is taking root.
-        ---
-    }
-
-    state journeyman {
-        on enter {
-            Elena.skill_level: intermediate
-            Elena.confidence: growing
-            Elena.can_work_independently: true
-        }
-
-        on recipes_mastered > 30 -> senior_journeyman
-
-        ---narrative
-        Elena runs the morning shift alone while Martha handles
-        special orders. Customers start asking for "Elena's rolls."
-        She begins experimenting with her own recipes.
-        ---
-    }
-
-    state senior_journeyman {
-        on enter {
-            Elena.skill_level: advanced
-            Elena.confidence: steady
-        }
-
-        on recipes_mastered > 50 -> master
-
-        ---narrative
-        Elena develops her signature recipe: rosemary olive bread
-        that becomes the bakery's bestseller. She handles difficult
-        customers with grace and trains new helpers.
-        ---
-    }
-
-    state master {
-        on enter {
-            Elena.skill_level: master
-            Elena.confidence: commanding
-            Elena.can_teach: true
-        }
-
-        ---narrative
-        Master Baker Elena. She has earned it. The guild acknowledges
-        her mastery, and Martha beams with pride. Elena begins
-        mentoring her own apprentice.
-        ---
-    }
-}
-
-

Quest Progress

-
life_arc HeroQuest {
-    state not_started {
-        on talked_to_elder -> received_quest
-    }
-
-    state received_quest {
-        on enter {
-            Hero.quest_active: true
-            Hero.quest_step: 0
-        }
-
-        on found_first_artifact -> collecting
-    }
-
-    state collecting {
-        on enter {
-            Hero.quest_step: 1
-        }
-
-        on artifact_count == 3 -> returning
-        on failed_trial -> failed
-    }
-
-    state returning {
-        on enter {
-            Hero.quest_step: 2
-        }
-
-        on reached_elder -> completed
-    }
-
-    state completed {
-        on enter {
-            Hero.quest_active: false
-            Hero.quest_completed: true
-            Hero.reputation: 100
-        }
-
-        ---narrative
-        The hero returns triumphant, artifacts in hand. The elder
-        bestows great rewards and the village celebrates.
-        ---
-    }
-
-    state failed {
-        on enter {
-            Hero.quest_active: false
-            Hero.quest_failed: true
-        }
-
-        on retry_accepted -> received_quest
-    }
-}
-
-

Name Checker (Equality Examples)

-
life_arc NameCheck {
-    state checking {
-        on name is "Martha" -> found_martha
-        on name is "Jane" -> found_jane
-    }
-
-    state found_martha {
-        on ready -> checking
-    }
-
-    state found_jane {
-        on ready -> checking
-    }
-}
-
-

Status Monitor

-
life_arc StatusMonitor {
-    state monitoring {
-        on status is active -> active_state
-        on status is inactive -> inactive_state
-        on status is error -> error_state
-    }
-
-    state active_state {
-        on enter {
-            System.led_color: "green"
-        }
-
-        on status is inactive -> inactive_state
-        on status is error -> error_state
-    }
-
-    state inactive_state {
-        on enter {
-            System.led_color: "yellow"
-        }
-
-        on status is active -> active_state
-        on status is error -> error_state
-    }
-
-    state error_state {
-        on enter {
-            System.led_color: "red"
-            System.alarm: true
-        }
-
-        on error_cleared -> monitoring
-    }
-}
-
-

Character Mood Swings

-
life_arc MoodSwings {
-    state neutral {
-        on provoked -> angry
-        on complimented -> happy
-        on tired -> sleepy
-    }
-
-    state angry {
-        on enter {
-            Character.aggression: 0.9
-            Character.willingness_to_talk: 0.1
-        }
-
-        on calmed_down -> neutral
-        on escalated -> furious
-    }
-
-    state furious {
-        on enter {
-            Character.aggression: 1.0
-            Character.will_attack: true
-        }
-
-        on timeout_elapsed -> angry
-        on apologized_to -> neutral
-    }
-
-    state happy {
-        on enter {
-            Character.aggression: 0.0
-            Character.willingness_to_talk: 1.0
-            Character.gives_discounts: true
-        }
-
-        on insulted -> neutral
-        on bored -> neutral
-    }
-
-    state sleepy {
-        on enter {
-            Character.responsiveness: 0.2
-        }
-
-        on woke_up -> neutral
-        on fell_asleep -> sleeping
-    }
-
-    state sleeping {
-        on enter {
-            Character.responsiveness: 0.0
-            Character.is_vulnerable: true
-        }
-
-        on woke_up -> neutral
-    }
-}
-
-

Execution Semantics

-

Tick-Based Evaluation

-

Life arcs evaluate transitions every “tick” (typically once per frame):

-
    -
  1. Current state: Start in the current state
  2. -
  3. Evaluate transitions: Check each outgoing transition’s condition (in order)
  4. -
  5. First true transition: Take the first transition with a true condition
  6. -
  7. Enter new state: Execute the new state’s on enter block
  8. -
  9. Repeat next tick
  10. -
-

Transition Priority

-

When multiple transitions could fire, the first one in declaration order is taken:

-
state combat {
-    on health < 10 -> desperate       // Checked first
-    on health < 50 -> defensive       // Checked second
-    on surrounded -> retreat          // Checked third
-}
-
-

If health is 5, only desperate transition fires (even though defensive condition is also true).

-

State Persistence

-

The current state persists across ticks until a transition fires.

-
state waiting {
-    on signal_received -> active
-}
-
-

The entity remains in waiting state indefinitely until signal_received becomes true.

-

On-Enter Execution

-

on enter blocks execute once when entering the state, not every tick:

-
state combat {
-    on enter {
-        Character.weapon_drawn: true  // Runs once when entering combat
-    }
-}
-
-

Validation Rules

-
    -
  1. At least one state: Life arc must contain at least one state
  2. -
  3. Unique state names: State names must be unique within the life arc
  4. -
  5. Valid transitions: Transition targets must reference defined states
  6. -
  7. No orphan states: All states should be reachable (warning, not error)
  8. -
  9. Expression validity: Transition conditions must be well-formed expressions
  10. -
  11. Field targets: On-enter field updates must reference valid entities/fields
  12. -
  13. No cyclic immediate transitions: Avoid transitions that fire immediately in a loop
  14. -
-

Design Patterns

-

1. Hub-and-Spoke

-

A central “hub” state with transitions to specialized states:

-
life_arc HubPattern {
-    state idle {
-        on combat_triggered -> combat
-        on quest_accepted -> questing
-        on entered_shop -> shopping
-    }
-
-    state combat {
-        on combat_ended -> idle
-    }
-
-    state questing {
-        on quest_completed -> idle
-    }
-
-    state shopping {
-        on left_shop -> idle
-    }
-}
-
-

2. Linear Progression

-

States form a linear sequence (quests, tutorials):

-
life_arc Tutorial {
-    state intro {
-        on clicked_start -> movement
-    }
-
-    state movement {
-        on moved_forward -> combat
-    }
-
-    state combat {
-        on defeated_enemy -> inventory
-    }
-
-    state inventory {
-        on opened_inventory -> complete
-    }
-
-    state complete {}
-}
-
-

3. Cyclic States

-

States form a cycle (day/night, seasons):

-
life_arc DayNightCycle {
-    state dawn {
-        on hour >= 8 -> day
-    }
-
-    state day {
-        on hour >= 18 -> dusk
-    }
-
-    state dusk {
-        on hour >= 20 -> night
-    }
-
-    state night {
-        on hour >= 6 -> dawn
-    }
-}
-
-

4. Hierarchical (Simulated)

-

Use multiple life arcs for hierarchical state:

-
// Top-level life arc
-life_arc CharacterState {
-    state alive {
-        on health <= 0 -> dead
-    }
-
-    state dead {}
-}
-
-// Nested life arc (only active when alive)
-life_arc CombatState {
-    state idle {
-        on enemy_nearby -> combat
-    }
-
-    state combat {
-        on enemy_defeated -> idle
-    }
-}
-
-

Best Practices

-

1. Use Descriptive State Names

-

Avoid:

-
state s1 { ... }
-state s2 { ... }
-
-

Prefer:

-
state waiting_for_player { ... }
-state engaged_in_combat { ... }
-
-

2. Add Narrative Prose Blocks

-
state master_baker {
-    ---narrative
-    Master Baker Elena. She has earned it. The guild acknowledges
-    her mastery, and Martha beams with pride. Elena begins
-    mentoring her own apprentice.
-    ---
-}
-
-

3. Order Transitions by Priority

-
state health_check {
-    on health <= 0 -> dead          // Most urgent
-    on health < 20 -> critical      // Very urgent
-    on health < 50 -> wounded       // Moderate
-}
-
-

4. Avoid Orphan States

-

Ensure all states are reachable from the initial state.

-

Avoid:

-
life_arc Broken {
-    state start {
-        on ready -> middle
-    }
-
-    state middle {
-        on done -> end
-    }
-
-    state unreachable {}  // No transition leads here!
-
-    state end {}
-}
-
-

5. Use On-Enter for State Initialization

-
state combat {
-    on enter {
-        Character.weapon_drawn: true
-        Character.combat_stance: "aggressive"
-        Character.target: nearest_enemy
-    }
-}
-
-

Cross-References

- - -
    -
  • Finite State Machines (FSM): Life arcs are FSMs
  • -
  • Character development: Track character growth over time
  • -
  • Quest states: Model quest progression
  • -
  • Mood systems: Model emotional states
  • -
  • Lifecycle modeling: Birth, growth, aging, death
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/14-schedules.html b/docs/book/reference/14-schedules.html deleted file mode 100644 index 5eb9795..0000000 --- a/docs/book/reference/14-schedules.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - Schedules - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Schedules

-

Schedules define time-based routines for characters and institutions. They specify what activities occur during specific time ranges, support seasonal variations, recurring events, and template composition. Schedules enable rich temporal behavior from simple daily routines to complex year-long patterns.

-

What is a Schedule?

-

A schedule is a collection of time blocks that define activities throughout a day, week, season, or year:

-
    -
  • Blocks: Time ranges (e.g., 06:00 - 14:00) with associated activities/behaviors
  • -
  • Temporal constraints: When blocks apply (season, day of week, month)
  • -
  • Recurrence patterns: Repeating events (e.g., “Market Day every Earthday”)
  • -
  • Composition: Schedules can extend and override other schedules
  • -
-
Schedule: BakerySchedule
-├─ Block: 06:00 - 08:00 → prepare_dough
-├─ Block: 08:00 - 14:00 → serve_customers
-├─ Recurrence: Market Day (on Earthday) → special_market_hours
-└─ Extends: BaseBusiness (inherits closing hours)
-
-

Syntax

-
<schedule-decl> ::= "schedule" <identifier> <extends-clause>? <body>
-
-<extends-clause> ::= "extends" <identifier>
-
-<body> ::= "{" <schedule-item>* "}"
-
-<schedule-item> ::= <schedule-block>
-                  | <recurrence-pattern>
-
-<schedule-block> ::= "block" <block-name>? "{" <block-content>+ "}"
-
-<block-name> ::= <identifier>
-
-<block-content> ::= <time-range>
-                  | "action" ":" <qualified-path>
-                  | <temporal-constraint>
-                  | <field>
-
-<time-range> ::= <time> "-" <time>
-
-<temporal-constraint> ::= "on" <temporal-spec>
-
-<temporal-spec> ::= "season" <identifier>
-                  | "day" <identifier>
-                  | "month" <identifier>
-                  | "dates" <string> ".." <string>
-
-<recurrence-pattern> ::= "recurs" <identifier> <temporal-constraint> "{" <schedule-block>+ "}"
-
-

Schedule Blocks

-

A schedule block defines an activity during a specific time range.

-

Basic Block

-
schedule SimpleBaker {
-    block {
-        06:00 - 14:00
-        action: baking::prepare_and_sell
-    }
-}
-
-

Named Block

-

Named blocks support the override system:

-
schedule BakeryBase {
-    block work {
-        09:00 - 17:00
-        action: baking::standard_work
-    }
-}
-
-schedule EarlyBaker extends BakeryBase {
-    block work {  // Override by name
-        05:00 - 13:00
-        action: baking::early_shift
-    }
-}
-
-

Block Content

-

Blocks can contain:

-
    -
  1. Time range (required): HH:MM - HH:MM
  2. -
  3. Action (optional): Behavior tree reference
  4. -
  5. Temporal constraint (optional): When the block applies
  6. -
  7. Fields (optional): Additional metadata
  8. -
-
schedule CompleteBlock {
-    block morning_work {
-        06:00 - 12:00
-        action: work::morning_routine
-        on season summer
-        location: "Outdoor Market"
-    }
-}
-
-

Time Ranges

-

Time ranges use 24-hour clock format.

-

Syntax

-
HH:MM - HH:MM
-
-
    -
  • HH: Hour (00-23)
  • -
  • MM: Minute (00-59)
  • -
  • Optional seconds: HH:MM:SS - HH:MM:SS
  • -
-

Examples

-
schedule Examples {
-    block early { 05:00 - 08:00, action: prep }
-    block midday { 12:00 - 13:00, action: lunch }
-    block late { 20:00 - 23:59, action: closing }
-}
-
-

Overnight Ranges

-

Blocks can span midnight:

-
schedule NightShift {
-    block night_work {
-        22:00 - 06:00  // 10 PM to 6 AM next day
-        action: security::patrol
-    }
-}
-
-

The system interprets this as 22:00-24:00 (day 1) + 00:00-06:00 (day 2).

-

Actions

-

The action field links a schedule block to a behavior tree.

-

Syntax

-
action: <qualified-path>
-
-

Examples

-
schedule BakerSchedule {
-    block morning {
-        05:00 - 08:00
-        action: baking::prepare_dough
-    }
-
-    block sales {
-        08:00 - 14:00
-        action: baking::serve_customers
-    }
-
-    block cleanup {
-        14:00 - 15:00
-        action: baking::close_shop
-    }
-}
-
-

Qualified Paths

-

Actions can reference behaviors from other modules:

-
schedule GuardSchedule {
-    block patrol {
-        08:00 - 16:00
-        action: behaviors::guards::patrol_route
-    }
-
-    block training {
-        16:00 - 18:00
-        action: combat::training::drills
-    }
-}
-
-

Temporal Constraints

-

Temporal constraints specify when a block applies (season, day of week, month, date range).

-

Season Constraint

-
schedule SeasonalHours {
-    block summer_hours {
-        06:00 - 20:00
-        action: work::long_day
-        on season summer
-    }
-
-    block winter_hours {
-        07:00 - 18:00
-        action: work::short_day
-        on season winter
-    }
-}
-
-

Season values are defined by enums in your storybook:

-
enum Season {
-    spring
-    summer
-    fall
-    winter
-}
-
-

Day of Week Constraint

-
schedule WeeklyPattern {
-    block weekday_work {
-        09:00 - 17:00
-        action: work::standard
-        on day monday  // Also: tuesday, wednesday, thursday, friday, saturday, sunday
-    }
-
-    block weekend_rest {
-        10:00 - 16:00
-        action: leisure::relax
-        on day saturday
-    }
-}
-
-

Day values are typically defined by a DayOfWeek enum:

-
enum DayOfWeek {
-    monday
-    tuesday
-    wednesday
-    thursday
-    friday
-    saturday
-    sunday
-}
-
-

Month Constraint

-
schedule AnnualPattern {
-    block harvest {
-        06:00 - 20:00
-        action: farming::harvest_crops
-        on month october
-    }
-
-    block spring_planting {
-        07:00 - 19:00
-        action: farming::plant_seeds
-        on month april
-    }
-}
-
-

Date Range Constraint

-
schedule TouristSeason {
-    block high_season {
-        08:00 - 22:00
-        action: tourism::busy_service
-        on dates "Jun 1" .. "Sep 1"
-    }
-}
-
-

Note: Date format is implementation-specific. Check your runtime for supported formats.

-

Recurrence Patterns

-

Recurrence patterns define recurring events that modify the schedule.

-

Syntax

-
recurs EventName on <temporal-constraint> {
-    <schedule-block>+
-}
-
-

Examples

-

Weekly Recurring Event

-
schedule MarketSchedule {
-    // Regular daily hours
-    block work {
-        08:00 - 17:00
-        action: shop::regular_sales
-    }
-
-    // Market day every saturday
-    recurs MarketDay on day saturday {
-        block setup {
-            06:00 - 08:00
-            action: market::setup_stall
-        }
-
-        block busy_market {
-            08:00 - 18:00
-            action: market::busy_sales
-        }
-
-        block teardown {
-            18:00 - 20:00
-            action: market::pack_up
-        }
-    }
-}
-
-

Monthly Recurring Event

-
schedule TownSchedule {
-    recurs CouncilMeeting on month first_monday {
-        block meeting {
-            18:00 - 21:00
-            action: governance::council_session
-        }
-    }
-}
-
-

Seasonal Recurring Event

-
schedule FarmSchedule {
-    recurs SpringPlanting on season spring {
-        block planting {
-            06:00 - 18:00
-            action: farming::plant_all_fields
-        }
-    }
-
-    recurs FallHarvest on season fall {
-        block harvest {
-            06:00 - 20:00
-            action: farming::harvest_all_crops
-        }
-    }
-}
-
-

Schedule Composition

-

Schedules can extend other schedules using extends, inheriting and overriding blocks.

-

Extends Clause

-
schedule Base {
-    block work {
-        09:00 - 17:00
-        action: work::standard
-    }
-}
-
-schedule Extended extends Base {
-    block work {  // Override inherited block
-        05:00 - 13:00
-        action: work::early_shift
-    }
-}
-
-

Override Semantics

-

When extending a schedule:

-
    -
  1. Named blocks with matching names override base blocks
  2. -
  3. Unnamed blocks are appended
  4. -
  5. Time range can change
  6. -
  7. Action can change
  8. -
  9. Constraints can be added/changed
  10. -
-

Multiple Levels

-
schedule BaseWork {
-    block work {
-        09:00 - 17:00
-        action: work::standard
-    }
-}
-
-schedule BakerWork extends BaseWork {
-    block work {
-        05:00 - 13:00  // Earlier hours
-        action: baking::work
-    }
-}
-
-schedule MasterBaker extends BakerWork {
-    block work {
-        03:00 - 11:00  // Even earlier!
-        action: baking::master_work
-    }
-
-    block teaching {
-        14:00 - 16:00
-        action: baking::teach_apprentice
-    }
-}
-
-

Resolution:

-
    -
  • work block: 03:00-11:00 with baking::master_work (MasterBaker overrides BakerWork overrides BaseWork)
  • -
  • teaching block: 14:00-16:00 with baking::teach_apprentice (from MasterBaker)
  • -
-

Complete Examples

-

Simple Daily Schedule

-
schedule SimpleFarmer {
-    block sleep {
-        22:00 - 05:00
-        action: rest::sleep
-    }
-
-    block morning_chores {
-        05:00 - 08:00
-        action: farming::feed_animals
-    }
-
-    block fieldwork {
-        08:00 - 17:00
-        action: farming::tend_crops
-    }
-
-    block evening_chores {
-        17:00 - 19:00
-        action: farming::evening_tasks
-    }
-
-    block leisure {
-        19:00 - 22:00
-        action: social::family_time
-    }
-}
-
-

Seasonal Variation

-
schedule SeasonalBaker {
-    block summer_work {
-        06:00 - 20:00
-        action: baking::long_shift
-        on season summer
-    }
-
-    block winter_work {
-        07:00 - 18:00
-        action: baking::short_shift
-        on season winter
-    }
-
-    block spring_work {
-        06:30 - 19:00
-        action: baking::medium_shift
-        on season spring
-    }
-
-    block fall_work {
-        06:30 - 19:00
-        action: baking::medium_shift
-        on season fall
-    }
-}
-
-

Weekly Pattern with Recurrence

-
schedule InnkeeperSchedule {
-    // Weekday routine
-    block weekday_service {
-        08:00 - 22:00
-        action: inn::regular_service
-        on day monday  // Repeat for each weekday
-    }
-
-    block weekday_service {
-        08:00 - 22:00
-        action: inn::regular_service
-        on day tuesday
-    }
-
-    // ... (wednesday, thursday, friday)
-
-    // Weekend hours
-    block weekend_service {
-        10:00 - 24:00
-        action: inn::busy_service
-        on day saturday
-    }
-
-    block weekend_service {
-        10:00 - 24:00
-        action: inn::busy_service
-        on day sunday
-    }
-
-    // Weekly market day
-    recurs MarketDay on day wednesday {
-        block market_prep {
-            06:00 - 08:00
-            action: inn::prepare_market_goods
-        }
-
-        block market_rush {
-            08:00 - 16:00
-            action: inn::market_day_chaos
-        }
-    }
-}
-
-

Extended Schedule

-
schedule BaseShopkeeper {
-    block open {
-        09:00 - 17:00
-        action: shop::standard_hours
-    }
-}
-
-schedule BlacksmithSchedule extends BaseShopkeeper {
-    block open {  // Override
-        06:00 - 18:00  // Longer hours
-        action: smithing::work
-    }
-
-    block forge_heat {  // New block
-        05:00 - 06:00
-        action: smithing::heat_forge
-    }
-}
-
-

Complex Year-Round Schedule

-
schedule MasterBakerYear {
-    // Daily base pattern
-    block prep {
-        04:00 - 06:00
-        action: baking::prepare
-    }
-
-    block baking {
-        06:00 - 10:00
-        action: baking::bake
-    }
-
-    block sales {
-        10:00 - 16:00
-        action: baking::serve
-    }
-
-    block cleanup {
-        16:00 - 17:00
-        action: baking::clean
-    }
-
-    // Seasonal variations
-    block summer_hours {
-        10:00 - 20:00  // Extended sales
-        action: baking::busy_summer
-        on season summer
-    }
-
-    // Weekly market
-    recurs MarketDay on day saturday {
-        block market_prep {
-            02:00 - 04:00
-            action: baking::market_prep
-        }
-
-        block market_sales {
-            08:00 - 18:00
-            action: baking::market_rush
-        }
-    }
-
-    // Annual events
-    recurs HarvestFestival on dates "Sep 20" .. "Sep 25" {
-        block festival {
-            06:00 - 23:00
-            action: baking::festival_mode
-        }
-    }
-}
-
-

Integration with Characters

-

Characters link to schedules using the uses schedule clause:

-
character Martha {
-    uses schedule: BakerySchedule
-}
-
-

Multiple schedules:

-
character Innkeeper {
-    uses schedules: [WeekdaySchedule, WeekendSchedule]
-}
-
-

See Characters for complete integration syntax.

-

Execution Semantics

-

Time-Based Selection

-

At any given time, the runtime:

-
    -
  1. Evaluates temporal constraints: Which blocks apply right now?
  2. -
  3. Selects matching block: First block whose time range and constraint match
  4. -
  5. Executes action: Runs the associated behavior tree
  6. -
  7. Repeats next tick
  8. -
-

Priority Order

-

When multiple blocks could apply:

-
    -
  1. Recurrences take priority over regular blocks
  2. -
  3. Constraints filter blocks (season, day, month)
  4. -
  5. Time ranges must overlap current time
  6. -
  7. First match wins (declaration order)
  8. -
-

Block Overlap

-

Blocks can overlap in time. The runtime selects the first matching block.

-

Example:

-
schedule Overlapping {
-    block general {
-        08:00 - 17:00
-        action: work::general
-    }
-
-    block specialized {
-        10:00 - 12:00  // Overlaps with general
-        action: work::specialized
-        on day wednesday
-    }
-}
-
-

On Wednesday at 11:00, specialized block is selected (more specific constraint).

-

Validation Rules

-
    -
  1. Time format: Times must be valid HH:MM or HH:MM:SS (24-hour)
  2. -
  3. Time order: Start time must be before end time (unless spanning midnight)
  4. -
  5. Extends exists: If using extends, base schedule must be defined
  6. -
  7. No circular extends: Cannot form circular dependency chains
  8. -
  9. Named blocks unique: Block names must be unique within a schedule
  10. -
  11. Action exists: Action references must resolve to defined behaviors
  12. -
  13. Constraint values: Temporal constraint values must reference defined enums
  14. -
  15. Recurrence names unique: Recurrence names must be unique within a schedule
  16. -
-

Best Practices

-

1. Use Named Blocks for Overrides

-

Avoid:

-
schedule Extended extends Base {
-    block { 05:00 - 13:00, action: work }  // Appends instead of overriding
-}
-
-

Prefer:

-
schedule Extended extends Base {
-    block work { 05:00 - 13:00, action: early_work }  // Overrides by name
-}
-
- -
schedule DailyRoutine {
-    // Sleep blocks
-    block night_sleep { 22:00 - 05:00, action: sleep }
-
-    // Morning blocks
-    block wake_up { 05:00 - 06:00, action: morning_routine }
-    block breakfast { 06:00 - 07:00, action: eat_breakfast }
-
-    // Work blocks
-    block commute { 07:00 - 08:00, action: travel_to_work }
-    block work { 08:00 - 17:00, action: work }
-}
-
-

3. Use Recurrences for Special Events

-

Avoid: Duplicating blocks manually

-

Prefer:

-
recurs MarketDay on day saturday {
-    block market { 08:00 - 16:00, action: market_work }
-}
-
-

4. Extend for Variations

-

Avoid: Duplicating entire schedules

-

Prefer:

-
schedule WorkerBase { ... }
-schedule EarlyWorker extends WorkerBase { ... }
-schedule NightWorker extends WorkerBase { ... }
-
-

5. Use Temporal Constraints for Clarity

-
block summer_hours {
-    06:00 - 20:00
-    action: long_shift
-    on season summer  // Explicit and readable
-}
-
-

Cross-References

- - -
    -
  • Time-based AI: Schedules drive time-dependent behavior
  • -
  • Template inheritance: extends enables schedule reuse
  • -
  • Temporal constraints: Filter blocks by season, day, month
  • -
  • Recurrence patterns: Define repeating events
  • -
  • Composition: Build complex schedules from simple parts
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/15-relationships.html b/docs/book/reference/15-relationships.html deleted file mode 100644 index 8ae67d0..0000000 --- a/docs/book/reference/15-relationships.html +++ /dev/null @@ -1,836 +0,0 @@ - - - - - - Relationships - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Relationships

-

Relationships define connections between characters, institutions, and other entities. They capture social bonds, power dynamics, emotional ties, and interactive patterns. Relationships can be symmetric (friendship) or asymmetric (parent-child), and support bidirectional perspectives where each participant has different fields.

-

What is a Relationship?

-

A relationship connects two or more participants and describes:

-
    -
  • Participants: The entities involved (characters, institutions)
  • -
  • Roles: Optional labels (parent, employer, spouse)
  • -
  • Shared fields: Properties of the relationship itself (bond strength, duration)
  • -
  • Perspective fields: How each participant views the relationship (self/other blocks)
  • -
-
Relationship: ParentChild
-├─ Participant: Martha (as parent)
-│   ├─ self: { responsibility: 1.0, protective: 0.9 }
-│   └─ other: { dependent: 0.8 }
-├─ Participant: Tommy (as child)
-└─ Shared: { bond: 0.9, years_together: 8 }
-
-

Syntax

-
<relationship-decl> ::= "relationship" <identifier> <body>
-
-<body> ::= "{" <participant>+ <field>* "}"
-
-<participant> ::= <qualified-path> <role-clause>? <perspective-blocks>?
-
-<role-clause> ::= "as" <identifier>
-
-<perspective-blocks> ::= "self" "{" <field>* "}" "other" "{" <field>* "}"
-                       | "self" "{" <field>* "}"
-                       | "other" "{" <field>* "}"
-
-<field> ::= <identifier> ":" <value>
-
-

Basic Relationships

-

Simple Two-Party Relationship

-
relationship Friendship {
-    Martha
-    Gregory
-    bond: 0.8
-    years_known: 15
-}
-
-

Semantics:

-
    -
  • Two participants: Martha and Gregory
  • -
  • Shared field: bond (strength of friendship)
  • -
  • Shared field: years_known (duration)
  • -
-

Multi-Party Relationship

-
relationship Family {
-    Martha
-    David
-    Tommy
-    Elena
-
-    household: "Baker Residence"
-    family_bond: 0.95
-}
-
-

Relationships can have any number of participants.

-

Roles

-

Roles label a participant’s function in the relationship.

-

Syntax

-
ParticipantName as role_name
-
-

Examples

-
relationship Marriage {
-    Martha as spouse
-    David as spouse
-
-    bond: 0.9
-    anniversary: "2015-06-20"
-}
-
-
relationship ParentChild {
-    Martha as parent
-    Tommy as child
-
-    bond: 0.95
-    guardianship: true
-}
-
-
relationship EmployerEmployee {
-    Martha as employer
-    Elena as employee
-
-    workplace: "Martha's Bakery"
-    salary: 45000
-}
-
-

Role Semantics

-
    -
  • Labels: Roles are descriptive labels, not types
  • -
  • Multiple roles: Same person can have different roles in different relationships
  • -
  • Optional: Roles are optional—participants can be unnamed
  • -
  • Flexibility: No predefined role vocabulary—use what makes sense
  • -
-

Perspective Fields (Self/Other Blocks)

-

Perspective fields specify how each participant views the relationship. They enable asymmetric, bidirectional relationships.

-

Syntax

-
ParticipantName as role self {
-    // Fields describing this participant's perspective
-} other {
-    // Fields describing how this participant views others
-}
-
-

Self Block

-

The self block contains fields about how the participant experiences the relationship:

-
relationship ParentChild {
-    Martha as parent self {
-        responsibility: 1.0
-        protective: 0.9
-        anxiety_level: 0.6
-    }
-    Tommy as child
-}
-
-

Martha’s perspective:

-
    -
  • responsibility: She feels 100% responsible
  • -
  • protective: She’s highly protective (90%)
  • -
  • anxiety_level: Moderate anxiety about parenting
  • -
-

Other Block

-

The other block contains fields about how the participant views the other participants:

-
relationship ParentChild {
-    Martha as parent self {
-        responsibility: 1.0
-    } other {
-        dependent: 0.8      // She sees Tommy as 80% dependent
-        mature_for_age: 0.7  // She thinks he's fairly mature
-    }
-    Tommy as child
-}
-
-

Both Blocks

-
relationship EmployerEmployee {
-    Martha as employer self {
-        authority: 0.9
-        stress: 0.6
-    } other {
-        respect: 0.8
-        trust: 0.85
-    }
-    Elena as employee
-}
-
-

Martha’s perspective:

-
    -
  • Self: She has high authority (90%), moderate stress (60%)
  • -
  • Other: She respects Elena (80%), trusts her (85%)
  • -
-

Asymmetric Relationships

-

Different participants can have different perspective fields:

-
relationship TeacherStudent {
-    Gandalf as teacher self {
-        patience: 0.8
-        wisdom_to_impart: 1.0
-    } other {
-        potential: 0.9
-        ready_to_learn: 0.6
-    }
-
-    Frodo as student self {
-        eager_to_learn: 0.7
-        overwhelmed: 0.5
-    } other {
-        admiration: 0.95
-        intimidated: 0.4
-    }
-
-    bond: 0.85
-}
-
-

Gandalf’s view:

-
    -
  • He’s patient (80%), has much wisdom to share
  • -
  • Sees Frodo as having high potential but only moderately ready
  • -
-

Frodo’s view:

-
    -
  • He’s eager but overwhelmed
  • -
  • Deeply admires Gandalf, slightly intimidated
  • -
-

Shared Fields

-

Fields declared at the relationship level (not in self/other blocks) are shared among all participants.

-
relationship Friendship {
-    Martha
-    Gregory
-
-    bond: 0.8           // Shared: mutual bond strength
-    years_known: 15     // Shared: how long they've known each other
-    shared_routines: 3  // Shared: number of daily routines
-}
-
-

Common shared fields:

-
    -
  • bond: Relationship strength (0.0 to 1.0)
  • -
  • years_known: Duration of relationship
  • -
  • trust: Mutual trust level
  • -
  • commitment: Commitment to the relationship
  • -
  • compatibility: How well they get along
  • -
-

Prose Blocks

-

Relationships can include prose blocks for narrative context.

-
relationship MarthaAndGregory {
-    Martha {
-        role: shopkeeper
-        values_loyalty: 0.9
-
-        ---perspective
-        Martha appreciates Gregory's unwavering loyalty. He has
-        been buying her sourdough loaf every morning for fifteen
-        years. Their brief daily exchanges about the weather and
-        local gossip are a comforting routine.
-        ---
-    }
-
-    Gregory {
-        role: regular_customer
-        always_orders: "sourdough_loaf"
-
-        ---perspective
-        Gregory considers Martha's bakery a cornerstone of his
-        daily routine. The bread is excellent, but it is the brief
-        human connection that keeps him coming back.
-        ---
-    }
-}
-
-

Common prose tags:

-
    -
  • ---perspective: How a participant views the relationship
  • -
  • ---history: Background of the relationship
  • -
  • ---dynamics: How the relationship functions
  • -
  • ---notes: Design or development notes
  • -
-

Note: In this syntax, perspective fields are inside participant blocks (not separate self/other blocks).

-

Complete Examples

-

Simple Friendship

-
relationship Friendship {
-    Martha
-    NeighborBaker
-
-    bond: 0.6
-    years_known: 10
-}
-
-

Marriage with Roles

-
relationship Marriage {
-    Martha as spouse
-    David as spouse
-
-    bond: 0.9
-    anniversary: "2015-06-20"
-    children: 2
-}
-
-

Parent-Child with Perspectives

-
relationship ParentChild {
-    Martha as parent self {
-        responsibility: 1.0
-        protective: 0.9
-        anxiety_level: 0.6
-    } other {
-        dependent: 0.8
-        mature_for_age: 0.7
-    }
-
-    Tommy as child self {
-        seeks_independence: 0.7
-        appreciates_parent: 0.9
-    } other {
-        feels_understood: 0.6
-        wants_more_freedom: 0.8
-    }
-
-    bond: 0.95
-    years_together: 8
-}
-
-

Employer-Employee

-
relationship EmployerEmployee {
-    Martha as employer self {
-        authority: 0.9
-        satisfaction_with_employee: 0.85
-    } other {
-        respect: 0.8
-        trust: 0.85
-    }
-
-    Elena as employee self {
-        job_satisfaction: 0.8
-        career_growth: 0.7
-    } other {
-        respects_boss: 0.9
-        appreciates_flexibility: 0.95
-    }
-
-    workplace: "Martha's Bakery"
-    salary: 45000
-    employment_start: "2023-01-15"
-}
-
-

Complex Multi-Perspective

-
relationship MentorApprentice {
-    Martha {
-        role: mentor
-        teaching_style: "patient"
-        investment: 0.9
-
-        ---perspective
-        Martha sees Elena as the daughter she might have had in
-        the trade. She recognizes the same passion she felt at
-        that age and pushes Elena harder because she knows the
-        talent is there. Every correction comes from love.
-        ---
-    }
-
-    Elena {
-        role: apprentice
-        dedication: 0.9
-        anxiety: 0.4
-
-        ---perspective
-        Elena idolizes Martha's skill but fears disappointing
-        her. Every morning she arrives thirty minutes early to
-        practice techniques before Martha gets in. She keeps a
-        notebook of every correction, reviewing them each night.
-
-        "I want to be half as good as her someday" -- this quiet
-        ambition drives everything Elena does.
-        ---
-    }
-
-    bond: 0.85
-}
-
-

Business Rivalry

-
relationship BakeryRivalry {
-    Martha {
-        role: established_baker
-        aware_of_competition: true
-        respects_rival: 0.6
-
-        ---perspective
-        Martha views the new bakery across town as healthy
-        competition. She respects their pastry work but knows
-        her sourdough is unmatched. The rivalry pushes her to
-        keep innovating.
-        ---
-    }
-
-    RivalBaker {
-        role: newcomer
-        wants_to_surpass: true
-        studies_martha: 0.8
-
-        ---perspective
-        The rival baker moved to town specifically because of
-        Martha's reputation. They study her techniques, buy her
-        bread to analyze it, and dream of the day a customer
-        chooses their loaf over Martha's sourdough.
-        ---
-    }
-
-    bond: 0.3
-}
-
-

Multi-Party Family

-
relationship BakerFamily {
-    Martha as parent
-    David as parent
-    Tommy as child
-    Elena as child
-
-    household: "Baker Residence"
-    family_bond: 0.95
-    dinner_time: 18:00
-
-    ---dynamics
-    A loving queer family running a bakery together. Martha and
-    David met at culinary school, married, and adopted Tommy and
-    Elena. The whole family works at the bakery on weekends.
-    ---
-}
-
-

Co-Owners Partnership

-
relationship BakeryPartnership {
-    Martha {
-        role: co_owner
-        specialty: "bread"
-        handles_finances: true
-
-        ---perspective
-        Martha and Jane complement each other perfectly. Martha
-        handles the bread and business side while Jane creates
-        the pastries that draw customers in. Together they have
-        built something neither could alone.
-        ---
-    }
-
-    Jane {
-        role: co_owner
-        specialty: "pastries"
-        handles_creativity: true
-
-        ---perspective
-        Jane considers Martha the steady foundation of their
-        partnership. While Jane experiments and creates, Martha
-        ensures the bakery runs like clockwork. Their different
-        strengths make the bakery stronger.
-        ---
-    }
-
-    bond: 0.9
-}
-
-

Participant Types

-

Participants can be:

-
    -
  1. Characters: Most common
  2. -
  3. Institutions: Organizations in relationships
  4. -
  5. Locations: Less common, but valid (e.g., “GuardianOfPlace”)
  6. -
-
relationship GuildMembership {
-    Elena as member
-    BakersGuild as organization
-
-    membership_since: "2023-01-01"
-    standing: "good"
-    dues_paid: true
-}
-
-

Field Resolution

-

When a relationship is resolved, fields are merged:

-
    -
  1. Relationship shared fields apply to all participants
  2. -
  3. Participant self blocks apply to that participant
  4. -
  5. Participant other blocks describe how that participant views others
  6. -
-

Example:

-
relationship Example {
-    Martha as friend self {
-        loyalty: 0.9
-    } other {
-        trust: 0.8
-    }
-    Gregory as friend
-
-    bond: 0.85
-}
-
-

Resolution:

-
    -
  • Martha gets: loyalty: 0.9 (from self), trust: 0.8 (towards Gregory, from other), bond: 0.85 (shared)
  • -
  • Gregory gets: bond: 0.85 (shared)
  • -
  • Relationship gets: bond: 0.85
  • -
-

Validation Rules

-
    -
  1. At least two participants: Relationships require ≥2 participants
  2. -
  3. Participants exist: All participant names must reference defined entities
  4. -
  5. Unique participant names: Each participant appears at most once
  6. -
  7. Field type consistency: Fields must have valid value types
  8. -
  9. No circular relationships: Avoid infinite relationship chains (warning)
  10. -
  11. Self/other completeness: If using self/other, both blocks should be present (best practice)
  12. -
-

Use Cases

-

Social Networks

-
relationship BakerFriendship {
-    Martha
-    Gregory
-    bond: 0.8
-}
-
-relationship SupplierPartnership {
-    Martha
-    Farmer_Jenkins
-    bond: 0.7
-}
-
-relationship BakeryRivalry {
-    Martha
-    RivalBaker
-    bond: 0.2
-    competitive: true
-}
-
-

Family Structures

-
relationship ParentChild {
-    Martha as parent
-    Tommy as child
-    bond: 0.95
-}
-
-relationship Siblings {
-    Tommy as older_sibling
-    Elena as younger_sibling
-    bond: 0.85
-    rivalry: 0.3
-}
-
-

Power Dynamics

-
relationship Vassalage {
-    King as lord self {
-        grants: "protection"
-        expects: "loyalty"
-    } other {
-        trusts: 0.6
-    }
-
-    Knight as vassal self {
-        swears: "fealty"
-        expects: "land"
-    } other {
-        respects: 0.9
-    }
-
-    oath_date: "1205-03-15"
-}
-
-

Asymmetric Awareness

-
relationship StalkingVictim {
-    Stalker as pursuer self {
-        obsession: 0.95
-        distance_maintained: 50  // meters
-    } other {
-        believes_unnoticed: true
-    }
-
-    Victim as unaware_target self {
-        awareness: 0.0
-    }
-
-    danger_level: 0.8
-}
-
-

Best Practices

-

1. Use Descriptive Relationship Names

-

Avoid:

-
relationship R1 { ... }
-relationship MarthaGregory { ... }
-
-

Prefer:

-
relationship Friendship { ... }
-relationship ParentChild { ... }
-relationship MentorApprentice { ... }
-
-

2. Use Roles for Clarity

-
relationship Marriage {
-    Martha as spouse
-    David as spouse
-}
-
-

Better than:

-
relationship Marriage {
-    Martha
-    David
-}
-
-

3. Shared Fields for Mutual Properties

-
relationship Partnership {
-    Martha
-    Jane
-
-    bond: 0.9           // Mutual bond
-    years_together: 5   // Shared history
-}
-
-

4. Self/Other for Perspectives

-
relationship TeacherStudent {
-    Teacher as mentor self {
-        patience: 0.8
-    } other {
-        potential: 0.9
-    }
-
-    Student as learner self {
-        motivation: 0.7
-    } other {
-        admiration: 0.95
-    }
-}
-
-

5. Prose Blocks for Rich Context

-
relationship ComplexDynamic {
-    Martha { ... }
-    Jane { ... }
-
-    ---dynamics
-    Their relationship is characterized by mutual respect but
-    divergent goals. Martha focuses on traditional bread while Jane
-    pushes for experimental pastries, creating creative tension.
-    ---
-}
-
-

Cross-References

- - -
    -
  • Bidirectional modeling: self/other blocks enable asymmetric perspectives
  • -
  • Social simulation: Relationships drive character interactions
  • -
  • Narrative depth: Prose blocks embed storytelling in relationship data
  • -
  • Power dynamics: Roles and perspective fields model hierarchies
  • -
  • Emotional bonds: Bond strength and trust metrics quantify connections
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/16-other-declarations.html b/docs/book/reference/16-other-declarations.html deleted file mode 100644 index 5b73c1f..0000000 --- a/docs/book/reference/16-other-declarations.html +++ /dev/null @@ -1,1005 +0,0 @@ - - - - - - Other Declarations - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Other Declarations

-

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.

-
-

Templates

-

Templates are reusable field sets that characters inherit using the from keyword. Unlike species (which define what an entity is), templates define what an entity has—capabilities, traits, and characteristics.

-

Syntax

-
<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>
-
-

Basic Template

-
template Warrior {
-    strength: 10..20
-    dexterity: 8..15
-    weapon_proficiency: 0.7..1.0
-}
-
-

Characters inheriting this template get these fields with values selected from the specified ranges.

-

Template Includes

-

Templates can include other templates to compose functionality:

-
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
-}
-
-

Semantics:

-
    -
  • include SkilledWorker brings in all fields from that template
  • -
  • Fields are merged left-to-right (later overrides earlier)
  • -
  • Transitive includes supported
  • -
  • Multiple includes allowed: include A, B, C
  • -
-

Range Values

-

Templates can specify ranges for procedural variation:

-
template Villager {
-    age: 18..65
-    wealth: 10..100
-    height: 150.0..190.0
-    disposition: 0.0..1.0
-}
-
-

Range syntax:

-
    -
  • Integer ranges: min..max (inclusive)
  • -
  • Float ranges: min..max (inclusive)
  • -
  • Both bounds must be same type
  • -
  • min ≤ max required
  • -
-

When a character uses this template, the runtime selects specific values within each range.

-

Strict Mode

-

Strict templates enforce that characters using them can only have fields defined in the template:

-
template RecipeCard strict {
-    include SkilledWorker
-
-    recipe_name: string
-    difficulty: Difficulty
-    prep_time_minutes: 10..180
-    requires_starter: false
-}
-
-

Strict semantics:

-
    -
  • Characters using strict templates cannot add extra fields
  • -
  • All template fields must be present in the character
  • -
  • Enables type safety for well-defined schemas
  • -
  • Use for controlled domains (game cards, rigid categories)
  • -
-

Non-strict (default):

-
template Flexible {
-    base_stat: 10
-}
-
-character Custom from Flexible {
-    base_stat: 15      // Override
-    extra_field: 42    // Allowed in non-strict
-}
-
-

Strict:

-
template Rigid strict {
-    required_stat: 10
-}
-
-character Constrained from Rigid {
-    required_stat: 15  // OK: Override
-    extra_field: 42    // ERROR: Not allowed in strict template
-}
-
-

Resource Linking in Templates

-

Templates can link to behaviors and schedules (v0.2.0+):

-
template BakeryStaffMember
-    uses behaviors: DailyBakingRoutine, CustomerService
-    uses schedule: BakerySchedule
-{
-    include SkilledWorker
-
-    on_shift: true
-    orders_completed: 0..1000
-    current_station: 0..4
-}
-
-

Characters inheriting this template automatically get the linked behaviors and schedule.

-

Templates vs. Species

-
- - - - - -
AspectTemplates (from)Species (:)
SemanticsWhat entity hasWhat entity is
CardinalityMultiple inheritanceSingle inheritance
RangesAllowedNot allowed
Strict modeSupportedNot supported
Use caseCompositional traitsOntological identity
-
-

Example combining both:

-
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
-}
-
-

Validation Rules

-
    -
  1. Includes exist: All included templates must be defined
  2. -
  3. No circular includes: Cannot form cycles
  4. -
  5. Range validity: min ≤ max for all ranges
  6. -
  7. Strict enforcement: Strict templates reject extra fields in characters
  8. -
  9. Resource links valid: Behavior/schedule references must resolve
  10. -
-
-

Institutions

-

Institutions define organizations, groups, and systems—entities that function like characters but represent collectives rather than individuals.

-

Syntax

-
<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>* "}"
-
-

Basic Institution

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1450-03-15"
-    reputation: 0.85
-}
-
-

Institutions with Fields

-
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.
-    ---
-}
-
-

Resource Linking

-

Institutions can use behaviors and schedules:

-
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.
-    ---
-}
-
-

Prose Blocks

-

Institutions support rich narrative documentation:

-
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.
-    ---
-}
-
-

Use Cases

-
    -
  • Organizations: Guilds, companies, governments
  • -
  • Systems: Magical systems, physical laws, economies
  • -
  • Social structures: Families, tribes, castes
  • -
  • Abstract entities: Dream logic, fate, chaos
  • -
-

Validation Rules

-
    -
  1. Unique names: Institution names must be unique
  2. -
  3. Resource links valid: Behaviors/schedules must exist
  4. -
  5. Field types: All fields must have valid values
  6. -
-
-

Locations

-

Locations define places in your world—rooms, buildings, cities, landscapes, or abstract spaces.

-

Syntax

-
<location-decl> ::= "location" <identifier> <body>
-
-<body> ::= "{" <field>* <prose-block>* "}"
-
-

Basic Location

-
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.
-    ---
-}
-
-

Location with Structure

-
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.
-    ---
-}
-
-

Geographic Hierarchy

-

Locations can reference other locations:

-
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.
-    ---
-}
-
-

Location with State

-
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.
-    ---
-}
-
-

Use Cases

-
    -
  • Physical places: Cities, buildings, rooms
  • -
  • Geographic features: Mountains, rivers, forests
  • -
  • Abstract spaces: Dream realms, pocket dimensions
  • -
  • Game boards: Arenas, dungeons, maps
  • -
-

Validation Rules

-
    -
  1. Unique names: Location names must be unique
  2. -
  3. Field types: All fields must have valid values
  4. -
  5. References valid: Location references (like part_of) should resolve
  6. -
-
-

Species

-

Species define the fundamental ontological categories of beings. A species represents what an entity is at its core—human, dragon, sentient tree, animated playing card.

-

Syntax

-
<species-decl> ::= "species" <identifier> <includes-clause>? <body>
-
-<includes-clause> ::= "includes" <identifier> ("," <identifier>)*
-
-<body> ::= "{" <field>* <prose-block>* "}"
-
-

Basic Species

-
species Human {
-    lifespan: 70
-
-    ---description
-    Bipedal mammals with complex language and tool use.
-    Highly variable in cultures and capabilities.
-    ---
-}
-
-

Species with Includes

-

Species can include other species for composition:

-
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.
-    ---
-}
-
-

Field Resolution with Includes

-

When a species includes others, fields are merged in declaration order:

-
    -
  1. Base species (leftmost in includes)
  2. -
  3. Middle species
  4. -
  5. Rightmost species
  6. -
  7. Current species (highest priority)
  8. -
-

Example:

-
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)
-
-

Species vs. Templates

-
- - - - - -
AspectSpecies (:)Templates (from)
Question“What is it?”“What traits does it have?”
CardinalityOne per characterZero or more
Inheritanceincludes (species → species)Characters inherit from templates
VariationConcrete defaultsRanges allowed
Examplespecies Humantemplate Warrior
-
-

When to use species:

-
species Dragon {
-    lifespan: 1000
-    can_fly: true
-    breathes_fire: true
-}
-
-character Smaug: Dragon {
-    age: 850  // Smaug IS a Dragon
-}
-
-

When to use templates:

-
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
-}
-
-

Design Pattern: Prefer Composition Over Deep Hierarchies

-

Avoid:

-
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!
-
-

Prefer:

-
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 { ... }
-
-

Validation Rules

-
    -
  1. Unique names: Species names must be unique
  2. -
  3. No circular includes: Cannot form cycles
  4. -
  5. Includes exist: All included species must be defined
  6. -
  7. Field types: All fields must have valid values
  8. -
-
-

Enums

-

Enums define controlled vocabularies—fixed sets of named values. They enable type-safe categorization and validation.

-

Syntax

-
<enum-decl> ::= "enum" <identifier> "{" <variant>+ "}"
-
-<variant> ::= <identifier> ","?
-
-

Basic Enum

-
enum Size {
-    tiny,
-    small,
-    normal,
-    large,
-    huge
-}
-
-

Using Enums

-

Enums are used as field values throughout the system:

-
character Martha: Human {
-    skill_level: master     // References SkillLevel enum
-    specialty: sourdough    // References Specialty enum
-}
-
-

Common Enum Patterns

-

Emotional States:

-
enum EmotionalState {
-    curious,
-    frightened,
-    confused,
-    brave,
-    angry,
-    melancholy,
-    amused
-}
-
-

Card Suits:

-
enum CardSuit {
-    hearts,
-    diamonds,
-    clubs,
-    spades
-}
-
-enum CardRank {
-    two, three, four, five, six, seven, eight, nine, ten,
-    knave, queen, king
-}
-
-

Time States:

-
enum TimeState {
-    normal,
-    frozen,
-    reversed,
-    accelerated
-}
-
-

Government Types:

-
enum GovernmentType {
-    monarchy,
-    democracy,
-    anarchy,
-    tyranny,
-    oligarchy
-}
-
-enum GovernmentStyle {
-    absolute_tyranny,
-    benevolent_dictatorship,
-    constitutional_monarchy,
-    direct_democracy,
-    representative_democracy
-}
-
-

Calendar Enums (Configurable)

-

Define custom calendars for your world:

-
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
-}
-
-

Custom calendars:

-
enum EightSeasons {
-    deep_winter,
-    late_winter,
-    early_spring,
-    late_spring,
-    early_summer,
-    late_summer,
-    early_fall,
-    late_fall
-}
-
-

Validation Integration

-

Enums enable compile-time validation:

-
enum Size {
-    tiny, small, normal, large, huge
-}
-
-character Martha {
-    skill_level: medium  // ERROR: 'medium' not in SkillLevel enum
-}
-
-

Use Cases

-
    -
  • Controlled vocabularies: Prevent typos and invalid values
  • -
  • Schema constraints: Temporal systems, card decks, status types
  • -
  • Type safety: Catch errors at compile time
  • -
  • Documentation: Enumerate all valid options
  • -
-

Validation Rules

-
    -
  1. Unique enum names: Enum names must be unique
  2. -
  3. Unique variants: Variant names must be unique within the enum
  4. -
  5. Non-empty: Enums must have at least one variant
  6. -
  7. Valid identifiers: Variants must follow identifier rules
  8. -
-
-

Use Statements

-

Use statements import definitions from other files, enabling modular organization and code reuse.

-

Syntax

-
<use-decl> ::= "use" <use-path> <use-kind>
-
-<use-path> ::= <identifier> ("::" <identifier>)*
-
-<use-kind> ::= ";"                                   // Single import
-             | "::{" <identifier> ("," <identifier>)* "}" ";"  // Grouped import
-             | "::*" ";"                             // Wildcard import
-
-

Single Import

-
use schema::beings::Human;
-
-

Imports the Human species from schema/beings.sb.

-

Grouped Import

-
use schema::core_enums::{Size, EmotionalState};
-
-

Imports multiple items from the same module.

-

Wildcard Import

-
use schema::beings::*;
-
-

Imports all public items from schema/beings.sb.

-

Qualified Paths

-

Module structure:

-
examples/alice-in-wonderland/
-├─ schema/
-│   ├─ core_enums.sb
-│   ├─ templates.sb
-│   └─ beings.sb
-└─ world/
-    ├─ characters/
-    │   └─ alice.sb
-    └─ locations/
-        └─ wonderland_places.sb
-
-

In martha.sb:

-
use schema::core_enums::{SkillLevel, Specialty};
-use schema::templates::Baker;
-use schema::beings::Human;
-
-character Martha: Human from Baker {
-    skill_level: master
-    specialty: sourdough
-}
-
-

Path Resolution

-
    -
  1. Relative to file’s module path: Imports are resolved relative to the current file’s location
  2. -
  3. Module hierarchy: schema::beings maps to schema/beings.sb
  4. -
  5. Transitive imports: Imported modules can themselves import others
  6. -
-

Common Patterns

-

Schema organization:

-
// 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};
-
-

Template composition:

-
// In schema/templates.sb
-template SkilledWorker { ... }
-template Baker {
-    include SkilledWorker
-    ...
-}
-
-// In world/characters/martha.sb
-use schema::templates::Baker;
-
-

Cross-file references:

-
// In world/characters/martha.sb
-character Martha { ... }
-
-// In world/relationships/bakery.sb
-use world::characters::Martha;
-
-relationship MarthaAndJane {
-    Martha
-    Jane
-}
-
-

Validation Rules

-
    -
  1. Path exists: Imported paths must reference defined modules/items
  2. -
  3. No circular imports: Modules cannot form circular dependency chains
  4. -
  5. Valid identifiers: All path segments must be valid identifiers
  6. -
  7. Grouped import validity: All items in {} must exist
  8. -
-

Best Practices

-

1. Group related imports:

-
use schema::core_enums::{SkillLevel, Specialty, Confidence};
-use schema::beings::{Human, Cat};
-
-

2. Explicit over wildcard:

-
// Prefer:
-use schema::core_enums::{SkillLevel, Specialty};
-
-// Over:
-use schema::core_enums::*;  // Imports everything
-
-

3. Organize by hierarchy:

-
// Schema imports first
-use schema::core_enums::SkillLevel;
-use schema::templates::Baker;
-
-// Then world imports
-use world::characters::Martha;
-
-

4. Use qualified paths for clarity:

-
character Elena: Human from Baker, Apprentice {
-    // Human is species (from schema::beings)
-    // Baker, Apprentice are templates (from schema::templates)
-}
-
-
-

Cross-References

- - -
    -
  • Modularity: Use statements enable file organization
  • -
  • Composition: Templates provide trait-based composition
  • -
  • Type safety: Enums prevent invalid values
  • -
  • World-building: Locations and institutions model environments
  • -
  • Ontology: Species define entity essence
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/16a-locations.html b/docs/book/reference/16a-locations.html deleted file mode 100644 index 19466d2..0000000 --- a/docs/book/reference/16a-locations.html +++ /dev/null @@ -1,477 +0,0 @@ - - - - - - Locations - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Locations

-

Locations define places in your world – rooms, buildings, cities, landscapes, or abstract spaces. They provide spatial context for characters, events, and narratives.

-
-

Syntax

-
<location-decl> ::= "location" <identifier> "{" <field>* <prose-block>* "}"
-
-

A location declaration consists of:

-
    -
  • The location keyword
  • -
  • A unique name (identifier)
  • -
  • A body block containing fields and optional prose blocks
  • -
-

Locations are one of the simpler declaration types – they hold fields and prose blocks but do not support resource linking (uses behaviors / uses schedule) like characters or institutions.

-
-

Basic Location

-

The simplest location has a name and descriptive fields:

-
location BakersBakery {
-    type: bakery
-    capacity: 30
-    address: "14 Main Street"
-    open_hours: "06:00-18:00"
-}
-
-

Fields can use any value type: integers, floats, strings, booleans, enums, lists, ranges, and durations.

-
-

Fields

-

Location fields describe properties of the place:

-
location BakerHome {
-    type: residence
-    bedrooms: 3
-    has_garden: true
-    garden_size_sqft: 450.0
-    residents: ["Martha", "David", "Jane"]
-    comfort_level: 0.85
-}
-
-

Common Field Patterns

-
- - - - - -
FieldTypeDescription
typeenum/identifierCategory of the place
capacityintegerHow many can be in this place
sizeenum/floatPhysical size
coordinatesinteger/floatPosition in a world map
accessiblebooleanWhether characters can enter
-
-

These are conventions, not enforced schema. You define whatever fields are meaningful for your world.

-
-

Prose Blocks

-

Locations support prose blocks for rich narrative content. Prose blocks are delimited by ---tag markers:

-
location BakersBakery {
-    type: bakery
-    capacity: 30
-
-    ---description
-    A warm, inviting bakery on Main Street. The smell of fresh bread
-    wafts out the door every morning at dawn. Martha has run the shop
-    for fifteen years, and the locals consider it the heart of the
-    neighborhood.
-    ---
-
-    ---atmosphere
-    Flour dust catches the light from tall windows. A display case
-    holds rows of golden pastries. Behind the counter, the kitchen
-    hums with activity from 4 AM onward.
-    ---
-}
-
-

Prose block rules:

-
    -
  • Start with ---tag_name on its own line
  • -
  • Content is free-form text (Markdown supported)
  • -
  • End with --- on its own line
  • -
  • The tag name becomes the key for retrieval
  • -
  • Multiple prose blocks per location are allowed
  • -
  • Each tag must be unique within the location
  • -
-
-

Ranges

-

Locations can use range values for procedural variation:

-
location MarketSquare {
-    type: outdoor_market
-    stalls: 10..25
-    daily_visitors: 50..200
-    noise_level: 0.4..0.9
-}
-
-

When instantiated, values are selected from within the specified range. This is useful for locations that should vary across simulation runs.

-
-

Lists

-

Locations can hold list values:

-
location BakersBakery {
-    type: bakery
-    products: ["sourdough", "croissants", "rye bread", "cinnamon rolls"]
-    equipment: ["stone oven", "mixing station", "proofing cabinet"]
-}
-
-
-

Referencing Other Entities

-

Location fields can reference other declarations by name:

-
location BakersBakery {
-    type: bakery
-    owner: Martha
-    neighborhood: MainStreet
-    part_of: TownCenter
-}
-
-

These are identifier references – they are not validated as cross-references at parse time, but the resolver checks that referenced names exist in the name table.

-
-

Nested Structure with Fields

-

You can model spatial hierarchy using fields:

-
location BakersBakery {
-    type: bakery
-    parent: MainStreet
-
-    // Zones within the bakery
-    has_kitchen: true
-    has_storefront: true
-    has_storage_room: true
-
-    // Dimensions
-    total_sqft: 1200
-    kitchen_sqft: 600
-    storefront_sqft: 400
-    storage_sqft: 200
-}
-
-location MainStreet {
-    type: street
-    parent: TownCenter
-    length_meters: 500
-    shops: 12
-}
-
-location TownCenter {
-    type: district
-    population: 2000
-}
-
-

There is no built-in parent-child relationship for locations – you model hierarchy through conventional field names like part_of, parent, or contains.

-
-

Location with Enum Fields

-

Use enums for type-safe categorization:

-
enum PlaceType {
-    residence, shop, workshop, office,
-    park, street, square, church
-}
-
-enum Accessibility {
-    public, private, restricted, members_only
-}
-
-location BakersBakery {
-    type: shop
-    accessibility: public
-    capacity: 30
-}
-
-location BakerHome {
-    type: residence
-    accessibility: private
-    capacity: 8
-}
-
-
-

Complete Example: Baker Family Locations

-
use schema::enums::{PlaceType, Accessibility};
-
-location BakersBakery {
-    type: shop
-    accessibility: public
-    owner: Martha
-    address: "14 Main Street"
-    capacity: 30
-    employees: 4
-    established: "2011"
-    specialty: "artisan sourdough"
-    daily_output_loaves: 80..120
-
-    ---description
-    Martha Baker's artisan bakery, known throughout town for its
-    sourdough and pastries. The shop opens at 6 AM sharp, and by
-    mid-morning there's usually a line out the door.
-    ---
-
-    ---history
-    Originally a hardware store, Martha converted the space after
-    winning a local baking competition. The stone oven was imported
-    from France and is the heart of the operation.
-    ---
-}
-
-location BakerHome {
-    type: residence
-    accessibility: private
-    address: "22 Elm Lane"
-    bedrooms: 4
-    has_garden: true
-    garden_size_sqft: 600
-    residents: ["Martha", "David", "Jane", "Tom"]
-    comfort_level: 0.9
-
-    ---description
-    A comfortable family home on a quiet street. The kitchen is
-    oversized (Martha insisted) and there's always something
-    baking, even at home.
-    ---
-}
-
-location BakersGuildHall {
-    type: office
-    accessibility: members_only
-    address: "7 Guild Row"
-    capacity: 100
-    meeting_room_capacity: 40
-    established: "1892"
-
-    ---description
-    The historic headquarters of the Bakers Guild, where trade
-    matters are discussed and apprenticeships are arranged.
-    ---
-}
-
-
-

Validation Rules

-
    -
  1. Unique names: Location names must be unique within their scope
  2. -
  3. Valid field values: All fields must have values that conform to value types
  4. -
  5. Unique field names: No duplicate field names within a location
  6. -
  7. Unique prose tags: No duplicate prose block tags within a location
  8. -
  9. Valid identifiers: Location names must follow identifier rules ([a-zA-Z_][a-zA-Z0-9_]*)
  10. -
-
-

Locations vs. Other Declarations

-
- - - - - -
AspectLocationsInstitutionsCharacters
PurposePhysical/abstract placesOrganizations/groupsIndividuals
Resource linkingNoYesYes
Prose blocksYesYesYes
SpeciesNoNoYes
TemplatesNoNoYes
-
-

Locations are intentionally simple. They define where things happen. For who does things, use characters. For organizational structures, use institutions.

-
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/16b-institutions.html b/docs/book/reference/16b-institutions.html deleted file mode 100644 index 389074a..0000000 --- a/docs/book/reference/16b-institutions.html +++ /dev/null @@ -1,569 +0,0 @@ - - - - - - Institutions - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Institutions

-

Institutions define organizations, groups, and systems – entities that function like characters but represent collectives rather than individuals. Unlike locations (which model where), institutions model what structures and organizations operate in your world.

-
-

Syntax

-
<institution-decl> ::= "institution" <identifier> "{" <institution-body> "}"
-
-<institution-body> ::= (<field> | <uses-behaviors> | <uses-schedule> | <prose-block>)*
-
-<uses-behaviors>  ::= "uses" "behaviors" ":" "[" <behavior-link> ("," <behavior-link>)* "]"
-
-<behavior-link>   ::= "{" "tree" ":" <path> ","?
-                           ("when" ":" <expression> ","?)?
-                           ("priority" ":" <priority-level> ","?)? "}"
-
-<priority-level>  ::= "low" | "normal" | "high" | "critical"
-
-<uses-schedule>   ::= "uses" "schedule" ":" <identifier>
-                     | "uses" "schedules" ":" "[" <identifier> ("," <identifier>)* "]"
-
-

An institution declaration consists of:

-
    -
  • The institution keyword
  • -
  • A unique name (identifier)
  • -
  • A body block containing fields, resource links, and optional prose blocks
  • -
-
-

Basic Institution

-

The simplest institution has a name and descriptive fields:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-}
-
-
-

Fields

-

Institution fields describe properties of the organization:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-    dues_annual: 120
-    meeting_frequency: "monthly"
-    accepts_apprentices: true
-    max_apprentices: 10
-    location: BakersGuildHall
-}
-
-

Common Field Patterns

-
- - - - - - -
FieldTypeDescription
typeenum/identifierCategory of organization
membersintegerMembership count
foundedstringEstablishment date
reputationfloatPublic standing (0.0-1.0)
locationidentifierWhere the institution operates
leaderidentifierWho runs the institution
-
-

These are conventions – you define whatever fields make sense for your world.

-
-

Prose Blocks

-

Institutions support prose blocks for rich narrative documentation:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-
-    ---description
-    The Bakers Guild has been the backbone of the town's bread trade
-    since 1892. Members share recipes, arrange apprenticeships, and
-    collectively negotiate flour prices with suppliers.
-    ---
-
-    ---charter
-    Article I: All members shall maintain the highest standards of
-    baking quality. Article II: Apprentices must complete a three-year
-    training program. Article III: Monthly meetings are mandatory.
-    ---
-
-    ---traditions
-    Every autumn, the Guild hosts the Great Bake-Off, a competition
-    open to all members. The winner earns the title of Master Baker
-    for the following year.
-    ---
-}
-
-

Prose block rules:

-
    -
  • Start with ---tag_name on its own line
  • -
  • Content is free-form text (Markdown supported)
  • -
  • End with --- on its own line
  • -
  • Multiple prose blocks per institution are allowed
  • -
  • Each tag must be unique within the institution
  • -
-
-

Resource Linking: Behaviors

-

Institutions can link to behavior trees using the uses behaviors clause. This defines what actions the institution takes as a collective entity.

-

Simple Behavior Linking

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-
-    uses behaviors: [
-        { tree: ManageApprentices },
-        { tree: NegotiateSuppliers },
-        { tree: HostEvents }
-    ]
-}
-
-

Each behavior link is an object with a tree field referencing a behavior tree by name or path.

- -
institution BakersGuild {
-    type: trade_guild
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostEvents, priority: low }
-    ]
-}
-
-

Priority levels: low, normal (default), high, critical.

- -
institution BakersGuild {
-    type: trade_guild
-
-    uses behaviors: [
-        { tree: ManageApprentices },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: EmergencyMeeting, when: reputation < 0.3, priority: critical }
-    ]
-}
-
-

The when clause takes an expression that determines when the behavior activates.

- -
- - - -
FieldRequiredTypeDescription
treeYespathReference to a behavior tree
priorityNopriority levelExecution priority (default: normal)
whenNoexpressionActivation condition
-
-
-

Resource Linking: Schedules

-

Institutions can link to schedules using the uses schedule or uses schedules clause.

-

Single Schedule

-
institution BakersGuild {
-    type: trade_guild
-    uses schedule: GuildOperatingHours
-}
-
-

Multiple Schedules

-
institution BakersGuild {
-    type: trade_guild
-    uses schedules: [WeekdaySchedule, WeekendSchedule, HolidaySchedule]
-}
-
-
-

Complete Syntax Example

-

An institution using all available features:

-
institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-    dues_annual: 120
-    location: BakersGuildHall
-    leader: Martha
-    accepts_apprentices: true
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostAnnualBakeOff, when: month is october, priority: high },
-        { tree: EmergencyMeeting, when: reputation < 0.3, priority: critical }
-    ]
-
-    uses schedule: GuildOperatingHours
-
-    ---description
-    The Bakers Guild has been the backbone of the town's bread trade
-    since 1892. Martha Baker currently serves as Guild Master.
-    ---
-
-    ---membership_rules
-    New members must be nominated by an existing member and pass
-    a baking trial. Apprentices are accepted from age 16.
-    ---
-}
-
-
-

Membership Modeling

-

Institutions themselves don’t have a built-in membership list. Instead, model membership through character fields or relationships:

-

Via Character Fields

-
character Martha {
-    age: 45
-    guild_member: true
-    guild_role: guild_master
-    guild: BakersGuild
-}
-
-character Jane {
-    age: 19
-    guild_member: true
-    guild_role: apprentice
-    guild: BakersGuild
-}
-
-

Via Relationships

-
relationship GuildMembership {
-    Martha as guild_master { }
-    BakersGuild as organization { }
-    bond: 0.95
-    years_active: 20
-}
-
-relationship Apprenticeship {
-    Jane as apprentice { }
-    BakersGuild as guild { }
-    Martha as mentor { }
-    years_completed: 1
-    years_remaining: 2
-}
-
-
-

Institutions vs. Characters

-

Both institutions and characters can use behaviors and schedules, but they serve different purposes:

-
- - - - - - - -
AspectInstitutionsCharacters
RepresentsOrganizations, collectivesIndividuals
SpeciesNoYes (optional)
TemplatesNoYes (optional)
uses behaviorsYesYes
uses scheduleYesYes
Prose blocksYesYes
Participation in relationshipsYes (via name)Yes (via name)
-
-

Use institutions when you need an entity that acts collectively: a guild votes, a government issues decrees, a school enrolls students.

-
-

Use Cases

-
    -
  • Organizations: Guilds, companies, governments, religions
  • -
  • Social structures: Families, tribes, castes, classes
  • -
  • Systems: Economic systems, magical systems, legal frameworks
  • -
  • Abstract entities: Dream logic, fate, cultural norms
  • -
  • Collectives: Military units, sports teams, musical ensembles
  • -
-
-

Complete Example: Baker Family World

-
use schema::enums::{GuildRole, InstitutionType};
-
-institution BakersGuild {
-    type: trade_guild
-    members: 50
-    founded: "1892"
-    reputation: 0.85
-    location: BakersGuildHall
-    leader: Martha
-    annual_dues: 120
-    accepts_apprentices: true
-    max_apprentices_per_mentor: 2
-
-    uses behaviors: [
-        { tree: ManageApprentices, priority: normal },
-        { tree: NegotiateSuppliers, priority: high },
-        { tree: HostAnnualBakeOff, when: month is october, priority: high }
-    ]
-
-    uses schedule: GuildOperatingHours
-
-    ---description
-    The Bakers Guild has served the town since 1892, ensuring quality
-    standards and fair pricing across all bakeries. Monthly meetings
-    are held at the Guild Hall, and the annual Bake-Off is the
-    highlight of the autumn calendar.
-    ---
-}
-
-institution TownCouncil {
-    type: government
-    members: 12
-    meets: "first Monday of each month"
-    location: TownHall
-    jurisdiction: "town limits"
-
-    uses behaviors: [
-        { tree: ReviewPetitions },
-        { tree: AllocateBudget, priority: high }
-    ]
-
-    ---description
-    The elected body governing the town. Martha Baker has been
-    lobbying them for years about flour import tariffs.
-    ---
-}
-
-institution BakersBakeryBusiness {
-    type: business
-    owner: Martha
-    employees: 4
-    location: BakersBakery
-    annual_revenue: 180000
-    established: "2011"
-
-    uses behaviors: [
-        { tree: DailyBakingOps, priority: high },
-        { tree: InventoryManagement },
-        { tree: CustomerService }
-    ]
-
-    uses schedule: BakeryOperatingHours
-
-    ---description
-    The business entity behind Baker's Bakery. Martha runs the
-    operation with help from her daughter Jane (apprentice baker),
-    two full-time bakers, and a part-time cashier.
-    ---
-}
-
-
-

Validation Rules

-
    -
  1. Unique names: Institution names must be unique within their scope
  2. -
  3. Valid field values: All fields must have values conforming to value types
  4. -
  5. Unique field names: No duplicate field names within an institution
  6. -
  7. Unique prose tags: No duplicate prose block tags within an institution
  8. -
  9. Valid behavior links: Each behavior link must have a tree field
  10. -
  11. Valid priority levels: Priority must be low, normal, high, or critical
  12. -
  13. Valid schedule references: Schedule names in uses schedule/uses schedules must be valid identifiers
  14. -
  15. Valid identifiers: Institution names must follow identifier rules ([a-zA-Z_][a-zA-Z0-9_]*)
  16. -
-
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/17-expressions.html b/docs/book/reference/17-expressions.html deleted file mode 100644 index 7abbe06..0000000 --- a/docs/book/reference/17-expressions.html +++ /dev/null @@ -1,745 +0,0 @@ - - - - - - Expression Language - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Expression Language

-

The Storybook expression language enables conditions, queries, and logic throughout the system. Expressions appear in life arc transitions, behavior tree guards, decorator conditions, and relationship queries. This chapter provides a complete reference for expression syntax and semantics.

-

What are Expressions?

-

Expressions are logical statements that evaluate to true or false. They combine:

-
    -
  • Literals: Numbers, strings, booleans
  • -
  • Identifiers: References to fields and entities
  • -
  • Comparisons: ==, !=, <, <=, >, >=
  • -
  • Logical operators: and, or, not
  • -
  • Field access: self.field, other.field
  • -
  • Quantifiers: forall, exists (for collections)
  • -
-

Syntax

-
<expression> ::= <literal>
-               | <identifier>
-               | <field-access>
-               | <comparison>
-               | <logical>
-               | <unary>
-               | <quantifier>
-               | "(" <expression> ")"
-
-<literal> ::= <int> | <float> | <string> | <bool>
-
-<identifier> ::= <simple-name>
-               | <qualified-path>
-
-<field-access> ::= <expression> "." <identifier>
-                 | "self" "." <identifier>
-                 | "other" "." <identifier>
-
-<comparison> ::= <expression> <comp-op> <expression>
-
-<comp-op> ::= "==" | "!=" | "<" | "<=" | ">" | ">="
-
-<logical> ::= <expression> "and" <expression>
-            | <expression> "or" <expression>
-
-<unary> ::= "not" <expression>
-          | "-" <expression>
-
-<quantifier> ::= ("forall" | "exists") <identifier> "in" <expression> ":" <expression>
-
-

Literals

-

Integer Literals

-
42
--7
-0
-1000
-
-

Float Literals

-
3.14
--0.5
-0.0
-100.25
-
-

String Literals

-
"Martha"
-"Sourdough takes patience."
-"active"
-
-

Strings are enclosed in double quotes. Escape sequences: \n, \t, \\, \".

-

Boolean Literals

-
true
-false
-
-

Identifiers

-

Identifiers reference fields or entities.

-

Simple Identifiers

-
health
-enemy_count
-is_ready
-
-

Qualified Paths

-
Martha.skill_level
-Character.emotional_state
-
-

Comparison Operators

-

Equality: ==

-

Tests if two values are equal.

-
name == "Martha"
-count == 5
-status == active
-
-

Type compatibility:

-
    -
  • Both operands must be the same type
  • -
  • Works with: int, float, string, bool, enum values
  • -
-

Inequality: !=

-

Tests if two values are not equal.

-
name != "Gregory"
-health != 0
-ready != true
-
-

Less Than: <

-

Tests if left operand is less than right.

-
health < 20
-age < 18
-distance < 10.0
-
-

Valid types: int, float

-

Less Than or Equal: <=

-
health <= 50
-count <= max_count
-
-

Greater Than: >

-
strength > 10
-bond > 0.5
-
-

Greater Than or Equal: >=

-
age >= 21
-score >= 100
-
-

Logical Operators

-

AND: and

-

Both operands must be true.

-
health < 50 and has_potion
-is_ready and not is_busy
-age >= 18 and age < 65
-
-

Evaluation: Short-circuit (if left is false, right is not evaluated)

-

OR: or

-

At least one operand must be true.

-
is_day or is_lit
-health < 20 or surrounded
-enemy_count == 0 or all_enemies_dead
-
-

Evaluation: Short-circuit (if left is true, right is not evaluated)

-

Operator Precedence

-

From highest to lowest:

-
    -
  1. Parentheses: (...)
  2. -
  3. Unary: not, -
  4. -
  5. Comparisons: ==, !=, <, <=, >, >=
  6. -
  7. AND: and
  8. -
  9. OR: or
  10. -
-

Examples:

-
not is_ready and is_awake
-// Equivalent to: (not is_ready) and is_awake
-
-health < 50 or is_poisoned and has_antidote
-// Equivalent to: (health < 50) or (is_poisoned and has_antidote)
-
-// Use parentheses for clarity:
-(health < 50 or is_poisoned) and has_antidote
-
-

Unary Operators

-

NOT: not

-

Inverts a boolean value.

-
not is_ready
-not (health < 20)
-not enemy_nearby and safe
-
-

Negation: -

-

Negates a numeric value.

-
-health
--10
--(max_value - current_value)
-
-

Field Access

-

Direct Field Access

-
health
-bond
-emotional_state
-
-

References a field on the current entity.

-

Dot Access

-
Martha.skill_level
-Character.emotional_state
-enemy.health
-
-

Access fields on other entities.

-

Self Access

-

In relationships and certain contexts, self refers to the current participant:

-
self.bond
-self.responsibility
-self.trust
-
-

Use case: Relationship transitions, symmetric queries

-

Other Access

-

In relationships, other refers to other participants:

-
other.bond
-other.aware_of_mentor
-other.respect
-
-

Use case: Relationship queries with perspective

-

Example in Life Arcs

-
life_arc RelationshipState {
-    state new {
-        on self.bond > 0.7 and other.bond > 0.7 -> stable
-    }
-
-    state stable {
-        on self.bond < 0.3 -> troubled
-        on other.bond < 0.3 -> troubled
-    }
-
-    state troubled {
-        on self.bond < 0.1 or other.bond < 0.1 -> broken
-    }
-
-    state broken {}
-}
-
-

Quantifiers

-

Quantifiers test conditions over collections.

-

ForAll: forall

-

Tests if a condition holds for all elements in a collection.

-
forall e in enemies: e.defeated
-forall item in inventory: item.weight < 10
-
-

Syntax:

-
forall <variable> in <collection>: <predicate>
-
-

Semantics:

-
    -
  • Returns true if predicate is true for every element
  • -
  • Returns true for empty collections (vacuously true)
  • -
-

Examples:

-
// All enemies defeated?
-forall enemy in enemies: enemy.health <= 0
-
-// All party members ready?
-forall member in party: member.is_ready
-
-// All doors locked?
-forall door in doors: door.is_locked
-
-

Exists: exists

-

Tests if a condition holds for at least one element.

-
exists e in enemies: e.is_hostile
-exists item in inventory: item.is_healing_potion
-
-

Syntax:

-
exists <variable> in <collection>: <predicate>
-
-

Semantics:

-
    -
  • Returns true if predicate is true for any element
  • -
  • Returns false for empty collections
  • -
-

Examples:

-
// Any enemy nearby?
-exists enemy in enemies: enemy.distance < 10
-
-// Any door unlocked?
-exists door in doors: not door.is_locked
-
-// Any ally wounded?
-exists ally in allies: ally.health < ally.max_health * 0.5
-
-

Nested Quantifiers

-

Quantifiers can nest:

-
forall team in teams: exists player in team: player.is_leader
-// Every team has at least one leader
-
-exists room in dungeon: forall enemy in room.enemies: enemy.defeated
-// At least one room has all enemies defeated
-
-

Usage in Context

-

Life Arc Transitions

-
life_arc CombatState {
-    state idle {
-        on enemy_count > 0 -> combat
-    }
-
-    state combat {
-        on health < 20 -> fleeing
-        on enemy_count == 0 -> victorious
-    }
-
-    state fleeing {
-        on distance_from_enemies > 100 -> safe
-    }
-
-    state victorious {
-        on celebration_complete -> idle
-    }
-
-    state safe {
-        on health >= 50 -> idle
-    }
-}
-
-

Behavior Tree Conditions

-
behavior GuardedAction {
-    if(health > 50 and has_weapon) {
-        AggressiveAttack
-    }
-}
-
-behavior ConditionalChoice {
-    choose tactics {
-        then melee {
-            if(distance < 5 and weapon_type == "sword")
-            MeleeAttack
-        }
-
-        then ranged {
-            if(distance >= 5 and has_arrows)
-            RangedAttack
-        }
-    }
-}
-
-

Behavior Tree Conditions

-
behavior SmartAI {
-    choose strategy {
-        then aggressive {
-            if(health > 70 and enemy_count < 3)
-            Attack
-        }
-
-        then defensive {
-            if(health < 30 or enemy_count >= 5)
-            Defend
-        }
-
-        then balanced {
-            if(health >= 30 and health <= 70)
-            TacticalManeuver
-        }
-    }
-}
-
-

Type System

-

Type Compatibility

-

Comparisons require compatible types:

-
- - - - - - - - - -
OperatorLeft TypeRight TypeValid?
==, !=intint
==, !=floatfloat
==, !=stringstring
==, !=boolbool
==, !=enumsame enum
==, !=intfloat
<, <=, >, >=intint
<, <=, >, >=floatfloat
<, <=, >, >=stringstring
-
-

Implicit Coercion

-

None. Storybook has no implicit type coercion. All comparisons must be between compatible types.

-

Error:

-
count == "5"  // Error: int vs string
-health < true  // Error: int vs bool
-
-

Correct:

-
count == 5
-health < 50
-
-

Special Keyword: is

-

The is keyword provides syntactic sugar for equality with enum values:

-
// Instead of:
-status == active
-
-// You can write:
-status is active
-
-

More examples:

-
name is "Martha"
-skill_level is master
-emotional_state is focused
-
-

This is purely syntactic—is and == are equivalent.

-

Complete Examples

-

Simple Conditions

-
health < 20
-enemy_nearby
-not is_ready
-count > 5
-
-

Complex Conditions

-
(health < 20 and not has_potion) or surrounded
-forall e in enemies: e.defeated
-exists item in inventory: item.is_healing_potion and item.quantity > 0
-
-

Life Arc with Complex Conditions

-
life_arc CharacterMood {
-    state content {
-        on health < 30 or hunger > 80 -> distressed
-        on social_interaction > 0.8 -> happy
-    }
-
-    state distressed {
-        on health >= 50 and hunger < 30 -> content
-        on (health < 10 or hunger > 95) and help_available -> desperate
-    }
-
-    state happy {
-        on social_interaction < 0.3 -> content
-        on received_bad_news -> distressed
-    }
-
-    state desperate {
-        on help_received -> distressed
-    }
-}
-
-

Behavior with Quantifiers

-
behavior SquadLeader {
-    choose leadership {
-        then regroup {
-            if(squad_has_wounded)
-            OrderRetreat
-        }
-
-        then advance {
-            if(squad_all_ready)
-            OrderAdvance
-        }
-
-        then hold_position {
-            if(not squad_all_ready)
-            OrderHold
-        }
-    }
-}
-
-

Relationship Query

-
life_arc FriendshipQuality {
-    state new_friends {
-        on self.bond > 0.7 and other.bond > 0.7 -> strong_bond
-        on self.trust < 0.3 or other.trust < 0.3 -> shaky
-    }
-
-    state strong_bond {
-        on self.bond < 0.5 -> weakening
-    }
-
-    state weakening {
-        on self.bond < 0.2 or other.bond < 0.2 -> ended
-        on self.bond > 0.7 and other.bond > 0.7 -> strong_bond
-    }
-
-    state shaky {
-        on self.trust > 0.6 and other.trust > 0.6 -> new_friends
-        on self.trust < 0.1 or other.trust < 0.1 -> ended
-    }
-
-    state ended {}
-}
-
-

Validation Rules

-
    -
  1. Type consistency: Both sides of comparison must be compatible types
  2. -
  3. Boolean context: Logical operators (and, or, not) require boolean operands
  4. -
  5. Field existence: Referenced fields must exist on the entity
  6. -
  7. Collection validity: Quantifiers require collection-typed expressions
  8. -
  9. Variable scope: Quantifier variables only valid within their predicate
  10. -
  11. No division by zero: Arithmetic operations must not divide by zero
  12. -
  13. Enum validity: Enum comparisons must reference defined enum values
  14. -
-

Best Practices

-

1. Use Parentheses for Clarity

-

Avoid:

-
health < 50 or is_poisoned and has_antidote
-
-

Prefer:

-
(health < 50 or is_poisoned) and has_antidote
-
-

2. Break Complex Conditions

-

Avoid:

-
on (health < 20 and not has_potion) or (surrounded and not has_escape) or (enemy_count > 10 and weapon_broken) -> desperate
-
-

Prefer:

-
state combat {
-    on health < 20 and not has_potion -> desperate
-    on surrounded and not has_escape -> desperate
-    on enemy_count > 10 and weapon_broken -> desperate
-}
-
-

3. Name Complex Conditions

-

For repeated complex conditions, consider using intermediate fields:

-

Instead of:

-
on health < (max_health * 0.2) and enemy_count > 5 -> flee
-
-

Consider:

-
// In character definition:
-critically_wounded: health < (max_health * 0.2)
-outnumbered: enemy_count > 5
-
-// In life arc:
-on critically_wounded and outnumbered -> flee
-
-

4. Use is for Enums

-

Prefer:

-
status is active
-emotional_state is focused
-
-

Over:

-
status == active
-emotional_state == focused
-
-

5. Quantifiers for Collections

-

Avoid:

-
// Manual checks for each element
-if enemy1.defeated and enemy2.defeated and enemy3.defeated
-
-

Prefer:

-
if forall enemy in enemies: enemy.defeated
-
-

Cross-References

- - -
    -
  • Type safety: Strong typing prevents type errors at compile time
  • -
  • Short-circuit evaluation: AND/OR operators optimize evaluation
  • -
  • Quantifiers: Enable expressive collection queries
  • -
  • Field access: Context-sensitive (self, other) for relationships
  • -
  • Boolean algebra: Standard logical operators with expected semantics
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/18-value-types.html b/docs/book/reference/18-value-types.html deleted file mode 100644 index 71fe840..0000000 --- a/docs/book/reference/18-value-types.html +++ /dev/null @@ -1,857 +0,0 @@ - - - - - - Value Types - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Values

-

Values are the fundamental data types in Storybook. Every field in a character, template, or other declaration contains a value. This chapter provides a complete reference for all supported value types.

-

Value Types Overview

-

Storybook supports 12 value types:

-
- - - - - - - - - - - - -
TypeExampleUse Case
Int42, -7Quantities, IDs, counts
Float3.14, -0.5Measurements, probabilities
String"Hello", "Martha"Text, names, descriptions
Booltrue, falseFlags, switches
Time14:30, 09:15:30Clock times, schedule blocks
Duration2h30m, 45sTime intervals
Range20..40, 0.5..1.0Template variation bounds
IdentifierMartha, items::swordReferences to other declarations
List[1, 2, 3], ["a", "b"]Collections
Object{x: 10, y: 20}Structured data
ProseBlock---tag content ---Long-form narrative
OverrideTemplateX with {...}Template instantiation with modifications
-
-

Integer

-

Signed 64-bit integers.

-

Syntax

-
<int> ::= ["-"] <digit>+
-<digit> ::= "0".."9"
-
-

Examples

-
character Hero {
-    age: 25
-    gold: 1500
-    reputation: -10
-}
-
-

Range

-
    -
  • Minimum: -9,223,372,036,854,775,808
  • -
  • Maximum: 9,223,372,036,854,775,807
  • -
-

Use Cases

-
    -
  • Counts (items, population)
  • -
  • Identifiers (IDs, keys)
  • -
  • Scores (reputation, alignment)
  • -
  • Whole quantities (gold pieces, HP)
  • -
-

Float

-

64-bit floating-point numbers (IEEE 754 double precision).

-

Syntax

-
<float> ::= ["-"] <digit>+ "." <digit>+
-          | ["-"] <digit>+ ("e" | "E") ["+"|"-"] <digit>+
-
-

Examples

-
character Wizard {
-    mana: 100.0
-    spell_power: 1.5
-    corruption: 0.03
-    precision: 1e-6
-}
-
-

Special Values

-
    -
  • No NaN or Infinity support (use validation to prevent)
  • -
  • Negative zero (-0.0) equals positive zero (0.0)
  • -
-

Use Cases

-
    -
  • Probabilities (0.0 to 1.0)
  • -
  • Percentages (0.0 to 100.0)
  • -
  • Measurements with precision
  • -
  • Ratios and scaling factors
  • -
-

String

-

UTF-8 encoded text enclosed in double quotes.

-

Syntax

-
<string> ::= '"' <string-char>* '"'
-<string-char> ::= <any-char-except-quote-or-backslash>
-                | <escape-sequence>
-<escape-sequence> ::= "\n" | "\r" | "\t" | "\\" | "\""
-
-

Escape Sequences

-
    -
  • \n - Newline
  • -
  • \r - Carriage return
  • -
  • \t - Tab
  • -
  • \\ - Backslash
  • -
  • \" - Double quote
  • -
-

Examples

-
character Martha {
-    name: "Martha Baker"
-    greeting: "Fresh from the oven!"
-    multiline: "Line 1\nLine 2\nLine 3"
-    quote: "She said, \"The bread is ready!\""
-}
-
-

Limitations

-
    -
  • No raw strings (r“…“) or multi-line literals
  • -
  • For long text, use prose blocks
  • -
  • Maximum length: Implementation-defined (typically several MB)
  • -
-

Use Cases

-
    -
  • Character names
  • -
  • Short descriptions
  • -
  • Dialogue snippets
  • -
  • Enum-like values (before proper enums)
  • -
-

Boolean

-

Logical true/false values.

-

Syntax

-
<bool> ::= "true" | "false"
-
-

Examples

-
character Guard {
-    is_awake: true
-    has_seen_player: false
-    loyal_to_king: true
-}
-
-

Use Cases

-
    -
  • Feature flags (can_fly, is_hostile)
  • -
  • State tracking (door_open, quest_complete)
  • -
  • Conditions (is_friendly, accepts_bribes)
  • -
-

Time

-

Clock time in 24-hour format.

-

Syntax

-
<time> ::= <hour> ":" <minute>
-         | <hour> ":" <minute> ":" <second>
-
-<hour> ::= "0".."23"
-<minute> ::= "0".."59"
-<second> ::= "0".."59"
-
-

Examples

-
schedule BakerySchedule {
-    block {
-        start: 06:00
-        end: 08:30
-        action: baking::prepare_dough
-    }
-
-    block {
-        start: 14:30:15  // With seconds
-        end: 15:00:00
-        action: baking::afternoon_cleanup
-    }
-}
-
-character EarlyRiser {
-    wake_time: 05:30
-    bedtime: 21:00
-}
-
-

Validation

-
    -
  • Hours: 0-23 (24-hour format)
  • -
  • Minutes: 0-59
  • -
  • Seconds: 0-59 (optional)
  • -
  • No AM/PM notation
  • -
  • No timezone support (context-dependent)
  • -
-

Use Cases

-
    -
  • Schedule blocks (see Schedules)
  • -
  • Character routines
  • -
  • Event timing
  • -
  • Time-based conditions
  • -
-

Duration

-

Time intervals with hour/minute/second components.

-

Syntax

-
<duration> ::= <duration-component>+
-
-<duration-component> ::= <number> ("h" | "m" | "s")
-
-<number> ::= <digit>+
-
-

Examples

-
character Traveler {
-    journey_time: 2h30m
-    rest_needed: 8h
-    sprint_duration: 45s
-}
-
-behavior TimedAction {
-    choose {
-        timeout(5m) {
-            CompleteObjective
-        }
-
-        cooldown(30s) {
-            UseSpecialAbility
-        }
-    }
-}
-
-

Components

-
    -
  • h - Hours
  • -
  • m - Minutes
  • -
  • s - Seconds
  • -
-

Can combine multiple components: 1h30m15s

-

Validation

-
    -
  • All components non-negative
  • -
  • No fractional components (1.5h not allowed; use 1h30m)
  • -
  • Can specify same unit multiple times: 90m = 1h30m (normalized)
  • -
-

Use Cases

-
    -
  • Behavior tree timeouts/cooldowns
  • -
  • Travel times
  • -
  • Cooldown periods
  • -
  • Event durations
  • -
-

Range

-

Numeric range with inclusive bounds (for templates only).

-

Syntax

-
<range> ::= <value> ".." <value>
-
-

Both bounds must be the same type (both int or both float).

-

Examples

-
template Villager {
-    age: 18..65
-    wealth: 10..100
-    height: 150.0..190.0  // Float range
-}
-
-template RandomEvent {
-    probability: 0.0..1.0
-    damage: 5..20
-}
-
-

Semantics

-
    -
  • Templates only: Ranges are only valid in templates
  • -
  • Instantiation: When a template is used, a specific value within the range is selected
  • -
  • Inclusive bounds: Both min and max are included
  • -
  • Order matters: min must be ≤ max
  • -
-

Validation

-
    -
  • Both bounds same type
  • -
  • minmax
  • -
  • Cannot use ranges in character/species/etc. (only templates)
  • -
-

Use Cases

-
    -
  • Template variation
  • -
  • Procedural generation
  • -
  • Random NPC attributes
  • -
  • Loot table ranges
  • -
-

Identifier

-

Reference to another declaration by qualified path.

-

Syntax

-
<identifier> ::= <simple-name>
-               | <qualified-path>
-
-<simple-name> ::= <ident>
-
-<qualified-path> ::= <ident> ("::" <ident>)+
-
-

Examples

-
character Martha: Human {  // Species reference
-    // ...
-}
-
-character Elena from Apprentice {  // Template reference
-    // ...
-}
-
-character Guard {
-    uses behaviors: [
-        { tree: guards::patrol }  // Behavior reference
-    ]
-    uses schedule: DailyRoutine  // Schedule reference
-}
-
-relationship Partnership {
-    Martha  // Character reference
-    Jane  // Character reference
-}
-
-

Resolution

-
    -
  • Unqualified: Searches current module, then imports
  • -
  • Qualified: module::submodule::Name
  • -
  • Validation: Compiler ensures all references resolve
  • -
-

Use Cases

-
    -
  • Species typing (: Species)
  • -
  • Template inheritance (from Template)
  • -
  • Behavior tree references
  • -
  • Schedule references
  • -
  • Relationship participants
  • -
  • Cross-references
  • -
-

List

-

Ordered collection of values.

-

Syntax

-
<list> ::= "[" "]"
-         | "[" <value> ("," <value>)* "]"
-
-

Examples

-
character Mage {
-    known_spells: ["Fireball", "Lightning", "Shield"]
-    spell_levels: [3, 5, 2]
-    party_members: [Martha, Jane, Elena]
-}
-
-character Traveler {
-    inventory: [
-        {item: "Sword", damage: 10},
-        {item: "Potion", healing: 50},
-        {item: "Key", opens: "TowerDoor"}
-    ]
-}
-
-

Type Constraints

-
    -
  • Homogeneous preferred: All elements should be the same type
  • -
  • Heterogeneous allowed: Mixed types permitted but discouraged
  • -
  • Empty lists: [] is valid
  • -
-

Operations

-

Lists are immutable at declaration time. Runtime list operations depend on the execution environment.

-

Use Cases

-
    -
  • Collections (inventory, spells, party members)
  • -
  • References (multiple behaviors, schedules, participants)
  • -
  • Enum-like sets (before proper enums)
  • -
-

Object

-

Structured data with named fields.

-

Syntax

-
<object> ::= "{" "}"
-           | "{" <field> ("," <field>)* "}"
-
-<field> ::= <identifier> ":" <value>
-
-

Examples

-
character Hero {
-    position: {x: 100, y: 200}
-
-    stats: {
-        strength: 15,
-        dexterity: 12,
-        intelligence: 10
-    }
-
-    equipment: {
-        weapon: {
-            name: "Longsword",
-            damage: 10,
-            enchantment: "Fire"
-        },
-        armor: {
-            name: "Plate Mail",
-            defense: 8
-        }
-    }
-}
-
-

Nesting

-

Objects can be nested arbitrarily deep:

-
character Complex {
-    deep: {
-        level1: {
-            level2: {
-                level3: {
-                    value: 42
-                }
-            }
-        }
-    }
-}
-
-

Use Cases

-
    -
  • Structured data (position, stats)
  • -
  • Nested configurations
  • -
  • Inline data structures
  • -
  • Complex field values
  • -
-

Prose Blocks

-

Long-form narrative text with semantic tags.

-

Syntax

-
<prose-block> ::= "---" <tag> <content> "---"
-
-<tag> ::= <identifier>
-
-<content> ::= <any-text-except-triple-dash>
-
-

Common Tags

-
    -
  • ---description: General description
  • -
  • ---backstory: Character history
  • -
  • ---appearance: Physical description
  • -
  • ---personality: Behavioral traits
  • -
  • ---motivation: Goals and desires
  • -
  • ---notes: Meta-commentary
  • -
  • ---ecology: Species habitat/behavior
  • -
  • ---culture: Social structures
  • -
  • ---narrative: Story context
  • -
-

Examples

-
character Martha {
-    age: 34
-
-    ---backstory
-    Martha learned to bake from her grandmother, starting at age
-    twelve. She now runs the most popular bakery in town, known
-    for her sourdough bread and unwavering quality standards.
-    ---
-
-    ---personality
-    Meticulous and patient, with an unwavering commitment to
-    quality. Tough but fair with her staff, and deeply loyal
-    to the customers who have supported her bakery for years.
-    ---
-}
-
-species Dragon {
-    lifespan: 1000
-
-    ---ecology
-    Dragons nest in high mountain caves and emerge every few decades
-    to hunt large prey. They hoard treasure as a mating display.
-    ---
-}
-
-

Formatting

-
    -
  • Leading/trailing whitespace is preserved
  • -
  • No escape sequences needed
  • -
  • Can contain any characters except --- on its own line
  • -
  • Indentation is significant for readability but not semantics
  • -
-

Multiple Prose Blocks

-

A single declaration can have multiple prose blocks with different tags:

-
character Gandalf {
-    ---appearance
-    An old man with a long gray beard, pointed hat, and staff.
-    ---
-
-    ---backstory
-    One of the Istari sent to Middle-earth to contest Sauron.
-    ---
-
-    ---personality
-    Patient and wise, but with a mischievous streak.
-    ---
-}
-
-

Use Cases

-
    -
  • Character backstories
  • -
  • Species descriptions
  • -
  • World-building flavor text
  • -
  • Design notes
  • -
  • Narrative context
  • -
-

Override

-

Template instantiation with field modifications.

-

Syntax

-
<override> ::= <qualified-path> "with" "{" <override-op>* "}"
-
-<override-op> ::= <identifier> ":" <value>           // Set
-                | "remove" <identifier>              // Remove
-                | "append" <identifier> ":" <value>  // Append (for lists)
-
-

Examples

-

Basic Override

-
template BaseWarrior {
-    strength: 10
-    dexterity: 8
-    weapon: "Sword"
-}
-
-character StrongWarrior {
-    stats: BaseWarrior with {
-        strength: 15  // Override strength
-    }
-}
-
-

Remove Fields

-
template FullEquipment {
-    helmet: "Iron"
-    chest: "Plate"
-    legs: "Mail"
-    boots: "Leather"
-}
-
-character LightFighter {
-    equipment: FullEquipment with {
-        remove helmet
-        remove chest
-    }
-}
-
-

Append to Lists

-
template BasicSpells {
-    spells: ["Fireball", "Shield"]
-}
-
-character AdvancedMage {
-    magic: BasicSpells with {
-        append spells: "Teleport"
-        append spells: "Lightning"
-    }
-    // Result: ["Fireball", "Shield", "Teleport", "Lightning"]
-}
-
-

Complex Override

-
template RogueTemplate {
-    stealth: 15
-    lockpicking: 12
-    backstab_damage: 20
-    equipment: ["Dagger", "Lockpicks"]
-}
-
-character MasterThief {
-    abilities: RogueTemplate with {
-        stealth: 20              // Set
-        remove backstab_damage   // Remove
-        append equipment: "Grappling Hook"  // Append
-    }
-}
-
-

Operations

-

set (default)

-

Replace a field’s value:

-
field_name: new_value
-
-

remove

-

Delete a field from the template:

-
remove field_name
-
-

append

-

Add to a list field (field must be a list):

-
append field_name: value_to_add
-
-

Validation

-
    -
  • Base template must exist
  • -
  • Overridden fields must exist in template
  • -
  • Removed fields must exist in template
  • -
  • Appended fields must be lists
  • -
  • Type compatibility enforced
  • -
-

Use Cases

-
    -
  • Customizing template instances
  • -
  • Procedural character generation
  • -
  • Variant creation
  • -
  • Data composition
  • -
-

Type Coercion

-

Storybook has no implicit type coercion. All type conversions must be explicit.

-

Not allowed:

-
character Wrong {
-    count: "42"  // Error: expected int, got string
-    flag: 1      // Error: expected bool, got int
-}
-
-

Correct:

-
character Right {
-    count: 42
-    flag: true
-}
-
-

Null and Optional

-

Storybook does not have null. For optional values, use:

-
    -
  1. -

    Template ranges with 0 as lower bound:

    -
    template MaybeWeapon {
    -    weapon_count: 0..5
    -}
    -
    -
  2. -
  3. -

    Boolean flags:

    -
    character Guard {
    -    has_weapon: false
    -}
    -
    -
  4. -
  5. -

    Empty lists:

    -
    character Unarmed {
    -    weapons: []
    -}
    -
    -
  6. -
-

Summary Table

-
- - - - - - - - - - - - -
TypeMutable?Comparable?Valid in Templates?Notes
IntNoYesYes64-bit signed
FloatNoYesYes64-bit IEEE 754
StringNoYesYesUTF-8
BoolNoYesYestrue/false
TimeNoYesNoHH:MM or HH:MM:SS
DurationNoYesNoCompounds (2h30m)
RangeNoNoYes (only)Template variation
IdentifierNoYesYesDeclaration reference
ListNoYesYesOrdered collection
ObjectNoYesYesNamed fields
ProseBlockNoNoYesNarrative text
OverrideNoNoYesTemplate modification
-
-

Cross-References

- - -
    -
  • Immutability: All values are immutable at declaration time
  • -
  • Type safety: Strong static typing with no implicit coercion
  • -
  • Structural equivalence: Objects/lists compared by structure, not identity
  • -
  • Prose as data: Narrative text is first-class data, not comments
  • -
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/reference/19-validation.html b/docs/book/reference/19-validation.html deleted file mode 100644 index 02f2d3c..0000000 --- a/docs/book/reference/19-validation.html +++ /dev/null @@ -1,530 +0,0 @@ - - - - - - Validation Rules - Storybook Language Guide - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- -
- - - - - - - - -
-
-

Validation Rules

-

The Storybook compiler performs multi-layered validation to catch errors before runtime. This chapter documents all validation rules, organized by declaration type, along with the error messages you can expect and how to fix them.

-

Validation Layers

-

Storybook validation happens in four stages:

-
    -
  1. Lexical: Tokenization of raw text (invalid characters, malformed literals)
  2. -
  3. Syntactic: Grammar structure (missing braces, wrong keyword order)
  4. -
  5. Semantic: Cross-reference resolution, type checking, field merging
  6. -
  7. Domain: Narrative-specific constraints (bond ranges, schedule overlaps)
  8. -
-

Errors at earlier stages prevent later stages from running.

-

Character Validation

-

Required Rules

-
- - - - - - - - -
RuleDescriptionSeverity
Unique nameCharacter names must be unique within their moduleError
Species existsIf : Species is used, the species must be definedError
Templates existAll templates in from clause must be definedError
No circular inheritanceTemplate chains cannot form cyclesError
Field type consistencyField values must match expected typesError
Behavior trees existAll uses behaviors references must resolveError
Schedules existAll uses schedule references must resolveError
Prose tag uniquenessEach prose tag can appear at most once per characterError
-
-

Examples

-

Species not found:

-
character Martha: Hobbit {  // Error: species 'Hobbit' not defined
-    age: 34
-}
-
-

Fix: Define the species or correct the reference:

-
species Hobbit {
-    lifespan: 130
-}
-
-character Martha: Hobbit {
-    age: 34
-}
-
-

Duplicate character name:

-
character Martha { age: 34 }
-character Martha { age: 36 }  // Error: duplicate character name 'Martha'
-
-

Template Validation

-
- - - - - - - -
RuleDescriptionSeverity
Unique nameTemplate names must be unique within their moduleError
Includes existAll included templates must be definedError
No circular includesInclude chains cannot form cyclesError
Range validityRange bounds must satisfy min <= maxError
Range type matchBoth bounds of a range must be the same typeError
Strict enforcementCharacters using strict templates cannot add extra fieldsError
Resource links validBehavior/schedule references must resolveError
-
-

Examples

-

Invalid range:

-
template BadRange {
-    age: 65..18  // Error: range min (65) must be <= max (18)
-}
-
-

Strict template violation:

-
template Rigid strict {
-    required_stat: 10
-}
-
-character Constrained from Rigid {
-    required_stat: 15
-    extra_field: 42    // Error: field 'extra_field' not allowed by strict template 'Rigid'
-}
-
-

Behavior Tree Validation

-
- - - - - - - - - -
RuleDescriptionSeverity
At least one nodeBehavior body must contain at least one nodeError
Composite childrenchoose and then require at least one childError
Decorator childDecorators require exactly one childError
Subtree existsinclude must reference a defined behaviorError
Expression validityCondition expressions must be well-formedError
Duration formatDecorator durations must be valid (e.g., 5s, 10m)Error
Repeat count validrepeat N requires N >= 0Error
Repeat range validrepeat min..max requires 0 <= min <= maxError
Retry count validretry N requires N >= 1Error
-
-

Examples

-

Empty composite:

-
behavior Empty {
-    choose options {
-        // Error: 'choose' requires at least one child
-    }
-}
-
-

Invalid subtree reference:

-
behavior Main {
-    include NonExistentBehavior  // Error: behavior 'NonExistentBehavior' not defined
-}
-
-

Life Arc Validation

-
- - - - - - -
RuleDescriptionSeverity
At least one stateLife arc must contain at least one stateError
Unique state namesState names must be unique within the life arcError
Valid transitionsTransition targets must reference defined statesError
Expression validityTransition conditions must be well-formedError
Field targets validOn-enter field references must resolveError
Reachable statesAll states should be reachable from initial stateWarning
-
-

Examples

-

Invalid transition target:

-
life_arc Broken {
-    state active {
-        on timer_expired -> nonexistent  // Error: state 'nonexistent' not defined
-    }
-}
-
-

Unreachable state (warning):

-
life_arc HasOrphan {
-    state start {
-        on ready -> middle
-    }
-
-    state middle {
-        on done -> end
-    }
-
-    state orphan {}  // Warning: state 'orphan' is not reachable
-
-    state end {}
-}
-
-

Schedule Validation

-
- - - - - - - -
RuleDescriptionSeverity
Time formatTimes must be valid HH:MM or HH:MM:SSError
Extends existsBase schedule must be definedError
No circular extendsSchedule chains cannot form cyclesError
Named blocks uniqueBlock names must be unique within a scheduleError
Action references validAction references must resolve to defined behaviorsError
Constraint values validTemporal constraint values must reference defined enumsError
Recurrence names uniqueRecurrence names must be unique within a scheduleError
-
-

Examples

-

Invalid time format:

-
schedule Bad {
-    block work {
-        25:00 - 17:00  // Error: invalid hour '25'
-        action: work
-    }
-}
-
-

Circular extends:

-
schedule A extends B { }
-schedule B extends A { }  // Error: circular schedule extension detected
-
-

Relationship Validation

-
- - - - -
RuleDescriptionSeverity
At least two participantsRelationships require >= 2 participantsError
Participants existAll participant names must reference defined entitiesError
Unique participantsEach participant appears at most onceError
Field type consistencyFields must have valid value typesError
-
-

Examples

-

Too few participants:

-
relationship Lonely {
-    Martha  // Error: relationship requires at least 2 participants
-    bond: 0.5
-}
-
-

Species Validation

-
- - - - - -
RuleDescriptionSeverity
Unique nameSpecies names must be unique within their moduleError
No circular includesInclude chains cannot form cyclesError
Includes existAll included species must be definedError
Field type consistencyFields must have valid valuesError
Prose tag uniquenessEach prose tag can appear at most onceError
-
-

Enum Validation

-
- - - - -
RuleDescriptionSeverity
Unique enum nameEnum names must be unique within their moduleError
Unique variantsVariant names must be unique within the enumError
Non-emptyEnums must have at least one variantError
Valid identifiersVariants must follow identifier rulesError
-
-

Examples

-

Duplicate variant:

-
enum Size {
-    tiny,
-    small,
-    small,  // Error: duplicate variant 'small' in enum 'Size'
-    large
-}
-
-

Institution and Location Validation

-
- - - -
RuleDescriptionSeverity
Unique nameNames must be unique within their moduleError
Resource links validBehavior/schedule references must resolveError
Field type consistencyFields must have valid valuesError
-
-

Expression Validation

-

Expressions are validated wherever they appear (life arc transitions, behavior tree conditions, if decorators).

-
- - - - - - -
RuleDescriptionSeverity
Type consistencyBoth sides of comparison must have compatible typesError
Boolean contextLogical operators require boolean operandsError
Field existenceReferenced fields must exist on the entityError
Collection validityQuantifiers require collection-typed expressionsError
Variable scopeQuantifier variables only valid within their predicateError
Enum validityEnum comparisons must reference defined valuesError
-
-

Examples

-

Type mismatch:

-
life_arc TypeError {
-    state checking {
-        on count == "five" -> done  // Error: cannot compare int with string
-    }
-
-    state done {}
-}
-
-

Use Statement Validation

-
- - - - -
RuleDescriptionSeverity
Path existsImported paths must reference defined modules/itemsError
No circular importsModules cannot form circular dependency chainsError
Valid identifiersAll path segments must be valid identifiersError
Grouped import validityAll items in {} must exist in the target moduleError
-
-

Examples

-

Missing import:

-
use schema::nonexistent::Thing;  // Error: module 'schema::nonexistent' not found
-
-

Cross-File Validation

-

When resolving across multiple .sb files, the compiler performs additional checks:

-
- - - -
RuleDescriptionSeverity
All references resolveCross-file references must find their targetsError
No naming conflictsDeclarations must not collide across files in the same moduleError
Import visibilityOnly public declarations can be importedError
-
-

Common Error Patterns

-

Missing Definitions

-

The most common error is referencing something that does not exist:

-
character Martha: Human from Baker {
-    specialty: sourdough
-}
-
-

If Human, Baker, or the sourdough enum variant are not defined or imported, the compiler will report an error. Fix by adding the appropriate use statements:

-
use schema::core_enums::{SkillLevel, Specialty};
-use schema::templates::Baker;
-use schema::beings::Human;
-
-character Martha: Human from Baker {
-    specialty: sourdough
-}
-
-

Circular Dependencies

-

Circular references are rejected at every level:

-
    -
  • Templates including each other
  • -
  • Species including each other
  • -
  • Schedules extending each other
  • -
  • Modules importing each other
  • -
-

Break cycles by restructuring into a hierarchy or extracting shared parts into a common module.

-

Type Mismatches

-

Storybook has no implicit type coercion. Ensure values match their expected types:

-
// Wrong:
-character Bad {
-    age: "twenty"  // Error: expected int, got string
-    is_ready: 1    // Error: expected bool, got int
-}
-
-// Correct:
-character Good {
-    age: 20
-    is_ready: true
-}
-
-

Validation Summary

-
- - - - - - - - - - - -
DeclarationKey Constraints
CharacterUnique name, valid species/templates, no circular inheritance
TemplateUnique name, valid includes, valid ranges, strict enforcement
BehaviorNon-empty, valid composites, valid decorators, valid subtrees
Life ArcNon-empty, unique states, valid transitions, reachable states
ScheduleValid times, valid extends chain, unique block names
Relationship>= 2 participants, valid references
SpeciesUnique name, valid includes, no cycles
EnumUnique name, unique variants, non-empty
InstitutionUnique name, valid resource links
LocationUnique name, valid field types
UseValid paths, no circular imports
-
-

Cross-References

- - -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/book/searcher.js b/docs/book/searcher.js deleted file mode 100644 index dc03e0a..0000000 --- a/docs/book/searcher.js +++ /dev/null @@ -1,483 +0,0 @@ -"use strict"; -window.search = window.search || {}; -(function search(search) { - // Search functionality - // - // You can use !hasFocus() to prevent keyhandling in your key - // event handlers while the user is typing their search. - - if (!Mark || !elasticlunr) { - return; - } - - //IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith - if (!String.prototype.startsWith) { - String.prototype.startsWith = function(search, pos) { - return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; - }; - } - - var search_wrap = document.getElementById('search-wrapper'), - searchbar = document.getElementById('searchbar'), - searchbar_outer = document.getElementById('searchbar-outer'), - searchresults = document.getElementById('searchresults'), - searchresults_outer = document.getElementById('searchresults-outer'), - searchresults_header = document.getElementById('searchresults-header'), - searchicon = document.getElementById('search-toggle'), - content = document.getElementById('content'), - - searchindex = null, - doc_urls = [], - results_options = { - teaser_word_count: 30, - limit_results: 30, - }, - search_options = { - bool: "AND", - expand: true, - fields: { - title: {boost: 1}, - body: {boost: 1}, - breadcrumbs: {boost: 0} - } - }, - mark_exclude = [], - marker = new Mark(content), - current_searchterm = "", - URL_SEARCH_PARAM = 'search', - URL_MARK_PARAM = 'highlight', - teaser_count = 0, - - SEARCH_HOTKEY_KEYCODE = 83, - ESCAPE_KEYCODE = 27, - DOWN_KEYCODE = 40, - UP_KEYCODE = 38, - SELECT_KEYCODE = 13; - - function hasFocus() { - return searchbar === document.activeElement; - } - - function removeChildren(elem) { - while (elem.firstChild) { - elem.removeChild(elem.firstChild); - } - } - - // Helper to parse a url into its building blocks. - function parseURL(url) { - var a = document.createElement('a'); - a.href = url; - return { - source: url, - protocol: a.protocol.replace(':',''), - host: a.hostname, - port: a.port, - params: (function(){ - var ret = {}; - var seg = a.search.replace(/^\?/,'').split('&'); - var len = seg.length, i = 0, s; - for (;i': '>', - '"': '"', - "'": ''' - }; - var repl = function(c) { return MAP[c]; }; - return function(s) { - return s.replace(/[&<>'"]/g, repl); - }; - })(); - - function formatSearchMetric(count, searchterm) { - if (count == 1) { - return count + " search result for '" + searchterm + "':"; - } else if (count == 0) { - return "No search results for '" + searchterm + "'."; - } else { - return count + " search results for '" + searchterm + "':"; - } - } - - function formatSearchResult(result, searchterms) { - var teaser = makeTeaser(escapeHTML(result.doc.body), searchterms); - teaser_count++; - - // The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor - var url = doc_urls[result.ref].split("#"); - if (url.length == 1) { // no anchor found - url.push(""); - } - - // encodeURIComponent escapes all chars that could allow an XSS except - // for '. Due to that we also manually replace ' with its url-encoded - // representation (%27). - var searchterms = encodeURIComponent(searchterms.join(" ")).replace(/\'/g, "%27"); - - return '' + result.doc.breadcrumbs + '' - + '' - + teaser + ''; - } - - function makeTeaser(body, searchterms) { - // The strategy is as follows: - // First, assign a value to each word in the document: - // Words that correspond to search terms (stemmer aware): 40 - // Normal words: 2 - // First word in a sentence: 8 - // Then use a sliding window with a constant number of words and count the - // sum of the values of the words within the window. Then use the window that got the - // maximum sum. If there are multiple maximas, then get the last one. - // Enclose the terms in . - var stemmed_searchterms = searchterms.map(function(w) { - return elasticlunr.stemmer(w.toLowerCase()); - }); - var searchterm_weight = 40; - var weighted = []; // contains elements of ["word", weight, index_in_document] - // split in sentences, then words - var sentences = body.toLowerCase().split('. '); - var index = 0; - var value = 0; - var searchterm_found = false; - for (var sentenceindex in sentences) { - var words = sentences[sentenceindex].split(' '); - value = 8; - for (var wordindex in words) { - var word = words[wordindex]; - if (word.length > 0) { - for (var searchtermindex in stemmed_searchterms) { - if (elasticlunr.stemmer(word).startsWith(stemmed_searchterms[searchtermindex])) { - value = searchterm_weight; - searchterm_found = true; - } - }; - weighted.push([word, value, index]); - value = 2; - } - index += word.length; - index += 1; // ' ' or '.' if last word in sentence - }; - index += 1; // because we split at a two-char boundary '. ' - }; - - if (weighted.length == 0) { - return body; - } - - var window_weight = []; - var window_size = Math.min(weighted.length, results_options.teaser_word_count); - - var cur_sum = 0; - for (var wordindex = 0; wordindex < window_size; wordindex++) { - cur_sum += weighted[wordindex][1]; - }; - window_weight.push(cur_sum); - for (var wordindex = 0; wordindex < weighted.length - window_size; wordindex++) { - cur_sum -= weighted[wordindex][1]; - cur_sum += weighted[wordindex + window_size][1]; - window_weight.push(cur_sum); - }; - - if (searchterm_found) { - var max_sum = 0; - var max_sum_window_index = 0; - // backwards - for (var i = window_weight.length - 1; i >= 0; i--) { - if (window_weight[i] > max_sum) { - max_sum = window_weight[i]; - max_sum_window_index = i; - } - }; - } else { - max_sum_window_index = 0; - } - - // add around searchterms - var teaser_split = []; - var index = weighted[max_sum_window_index][2]; - for (var i = max_sum_window_index; i < max_sum_window_index+window_size; i++) { - var word = weighted[i]; - if (index < word[2]) { - // missing text from index to start of `word` - teaser_split.push(body.substring(index, word[2])); - index = word[2]; - } - if (word[1] == searchterm_weight) { - teaser_split.push("") - } - index = word[2] + word[0].length; - teaser_split.push(body.substring(word[2], index)); - if (word[1] == searchterm_weight) { - teaser_split.push("") - } - }; - - return teaser_split.join(''); - } - - function init(config) { - results_options = config.results_options; - search_options = config.search_options; - searchbar_outer = config.searchbar_outer; - doc_urls = config.doc_urls; - searchindex = elasticlunr.Index.load(config.index); - - // Set up events - searchicon.addEventListener('click', function(e) { searchIconClickHandler(); }, false); - searchbar.addEventListener('keyup', function(e) { searchbarKeyUpHandler(); }, false); - document.addEventListener('keydown', function(e) { globalKeyHandler(e); }, false); - // If the user uses the browser buttons, do the same as if a reload happened - window.onpopstate = function(e) { doSearchOrMarkFromUrl(); }; - // Suppress "submit" events so the page doesn't reload when the user presses Enter - document.addEventListener('submit', function(e) { e.preventDefault(); }, false); - - // If reloaded, do the search or mark again, depending on the current url parameters - doSearchOrMarkFromUrl(); - } - - function unfocusSearchbar() { - // hacky, but just focusing a div only works once - var tmp = document.createElement('input'); - tmp.setAttribute('style', 'position: absolute; opacity: 0;'); - searchicon.appendChild(tmp); - tmp.focus(); - tmp.remove(); - } - - // On reload or browser history backwards/forwards events, parse the url and do search or mark - function doSearchOrMarkFromUrl() { - // Check current URL for search request - var url = parseURL(window.location.href); - if (url.params.hasOwnProperty(URL_SEARCH_PARAM) - && url.params[URL_SEARCH_PARAM] != "") { - showSearch(true); - searchbar.value = decodeURIComponent( - (url.params[URL_SEARCH_PARAM]+'').replace(/\+/g, '%20')); - searchbarKeyUpHandler(); // -> doSearch() - } else { - showSearch(false); - } - - if (url.params.hasOwnProperty(URL_MARK_PARAM)) { - var words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' '); - marker.mark(words, { - exclude: mark_exclude - }); - - var markers = document.querySelectorAll("mark"); - function hide() { - for (var i = 0; i < markers.length; i++) { - markers[i].classList.add("fade-out"); - window.setTimeout(function(e) { marker.unmark(); }, 300); - } - } - for (var i = 0; i < markers.length; i++) { - markers[i].addEventListener('click', hide); - } - } - } - - // Eventhandler for keyevents on `document` - function globalKeyHandler(e) { - if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || e.target.type === 'textarea' || e.target.type === 'text' || !hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)) { return; } - - if (e.keyCode === ESCAPE_KEYCODE) { - e.preventDefault(); - searchbar.classList.remove("active"); - setSearchUrlParameters("", - (searchbar.value.trim() !== "") ? "push" : "replace"); - if (hasFocus()) { - unfocusSearchbar(); - } - showSearch(false); - marker.unmark(); - } else if (!hasFocus() && e.keyCode === SEARCH_HOTKEY_KEYCODE) { - e.preventDefault(); - showSearch(true); - window.scrollTo(0, 0); - searchbar.select(); - } else if (hasFocus() && e.keyCode === DOWN_KEYCODE) { - e.preventDefault(); - unfocusSearchbar(); - searchresults.firstElementChild.classList.add("focus"); - } else if (!hasFocus() && (e.keyCode === DOWN_KEYCODE - || e.keyCode === UP_KEYCODE - || e.keyCode === SELECT_KEYCODE)) { - // not `:focus` because browser does annoying scrolling - var focused = searchresults.querySelector("li.focus"); - if (!focused) return; - e.preventDefault(); - if (e.keyCode === DOWN_KEYCODE) { - var next = focused.nextElementSibling; - if (next) { - focused.classList.remove("focus"); - next.classList.add("focus"); - } - } else if (e.keyCode === UP_KEYCODE) { - focused.classList.remove("focus"); - var prev = focused.previousElementSibling; - if (prev) { - prev.classList.add("focus"); - } else { - searchbar.select(); - } - } else { // SELECT_KEYCODE - window.location.assign(focused.querySelector('a')); - } - } - } - - function showSearch(yes) { - if (yes) { - search_wrap.classList.remove('hidden'); - searchicon.setAttribute('aria-expanded', 'true'); - } else { - search_wrap.classList.add('hidden'); - searchicon.setAttribute('aria-expanded', 'false'); - var results = searchresults.children; - for (var i = 0; i < results.length; i++) { - results[i].classList.remove("focus"); - } - } - } - - function showResults(yes) { - if (yes) { - searchresults_outer.classList.remove('hidden'); - } else { - searchresults_outer.classList.add('hidden'); - } - } - - // Eventhandler for search icon - function searchIconClickHandler() { - if (search_wrap.classList.contains('hidden')) { - showSearch(true); - window.scrollTo(0, 0); - searchbar.select(); - } else { - showSearch(false); - } - } - - // Eventhandler for keyevents while the searchbar is focused - function searchbarKeyUpHandler() { - var searchterm = searchbar.value.trim(); - if (searchterm != "") { - searchbar.classList.add("active"); - doSearch(searchterm); - } else { - searchbar.classList.remove("active"); - showResults(false); - removeChildren(searchresults); - } - - setSearchUrlParameters(searchterm, "push_if_new_search_else_replace"); - - // Remove marks - marker.unmark(); - } - - // Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor . - // `action` can be one of "push", "replace", "push_if_new_search_else_replace" - // and replaces or pushes a new browser history item. - // "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet. - function setSearchUrlParameters(searchterm, action) { - var url = parseURL(window.location.href); - var first_search = ! url.params.hasOwnProperty(URL_SEARCH_PARAM); - if (searchterm != "" || action == "push_if_new_search_else_replace") { - url.params[URL_SEARCH_PARAM] = searchterm; - delete url.params[URL_MARK_PARAM]; - url.hash = ""; - } else { - delete url.params[URL_MARK_PARAM]; - delete url.params[URL_SEARCH_PARAM]; - } - // A new search will also add a new history item, so the user can go back - // to the page prior to searching. A updated search term will only replace - // the url. - if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) { - history.pushState({}, document.title, renderURL(url)); - } else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) { - history.replaceState({}, document.title, renderURL(url)); - } - } - - function doSearch(searchterm) { - - // Don't search the same twice - if (current_searchterm == searchterm) { return; } - else { current_searchterm = searchterm; } - - if (searchindex == null) { return; } - - // Do the actual search - var results = searchindex.search(searchterm, search_options); - var resultcount = Math.min(results.length, results_options.limit_results); - - // Display search metrics - searchresults_header.innerText = formatSearchMetric(resultcount, searchterm); - - // Clear and insert results - var searchterms = searchterm.split(' '); - removeChildren(searchresults); - for(var i = 0; i < resultcount ; i++){ - var resultElem = document.createElement('li'); - resultElem.innerHTML = formatSearchResult(results[i], searchterms); - searchresults.appendChild(resultElem); - } - - // Display results - showResults(true); - } - - fetch(path_to_root + 'searchindex.json') - .then(response => response.json()) - .then(json => init(json)) - .catch(error => { // Try to load searchindex.js if fetch failed - var script = document.createElement('script'); - script.src = path_to_root + 'searchindex.js'; - script.onload = () => init(window.search); - document.head.appendChild(script); - }); - - // Exported functions - search.hasFocus = hasFocus; -})(window.search); diff --git a/docs/book/searchindex.js b/docs/book/searchindex.js deleted file mode 100644 index 01311ff..0000000 --- a/docs/book/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Object.assign(window.search, {"doc_urls":["index.html#storybook-language-guide","index.html#what-is-storybook","index.html#choose-your-path","index.html#-for-storytellers","index.html#-for-developers","index.html#-for-everyone","index.html#quick-start","index.html#documentation-structure","index.html#getting-help","tutorial/01-welcome.html#welcome-to-storybook","tutorial/01-welcome.html#what-you-will-learn","tutorial/01-welcome.html#what-is-storybook","tutorial/01-welcome.html#your-first-storybook-file","tutorial/01-welcome.html#key-concepts","tutorial/01-welcome.html#everything-is-a-declaration","tutorial/01-welcome.html#fields-hold-data","tutorial/01-welcome.html#prose-blocks-tell-stories","tutorial/01-welcome.html#project-structure","tutorial/01-welcome.html#next-steps","tutorial/02-creating-characters.html#creating-characters","tutorial/02-creating-characters.html#a-simple-character","tutorial/02-creating-characters.html#adding-descriptions-with-prose-blocks","tutorial/02-creating-characters.html#defining-species","tutorial/02-creating-characters.html#but-what-about-hybrids","tutorial/02-creating-characters.html#reusing-traits-with-templates","tutorial/02-creating-characters.html#species-vs-templates","tutorial/02-creating-characters.html#field-resolution","tutorial/02-creating-characters.html#using-enums-for-controlled-values","tutorial/02-creating-characters.html#importing-across-files","tutorial/02-creating-characters.html#putting-it-all-together","tutorial/02-creating-characters.html#next-steps","tutorial/03-first-behavior-tree.html#your-first-behavior-tree","tutorial/03-first-behavior-tree.html#what-is-a-behavior-tree","tutorial/03-first-behavior-tree.html#your-first-tree","tutorial/03-first-behavior-tree.html#understanding-choose-selector","tutorial/03-first-behavior-tree.html#understanding-then-sequence","tutorial/03-first-behavior-tree.html#naming-your-nodes","tutorial/03-first-behavior-tree.html#combining-choose-and-then","tutorial/03-first-behavior-tree.html#actions","tutorial/03-first-behavior-tree.html#a-complete-example","tutorial/03-first-behavior-tree.html#behavior-character-connection","tutorial/03-first-behavior-tree.html#next-steps","tutorial/04-making-characters-act.html#making-characters-act","tutorial/04-making-characters-act.html#conditions-if-and-when","tutorial/04-making-characters-act.html#condition-expressions","tutorial/04-making-characters-act.html#action-parameters","tutorial/04-making-characters-act.html#decorators","tutorial/04-making-characters-act.html#repeat----looping","tutorial/04-making-characters-act.html#invert----flip-results","tutorial/04-making-characters-act.html#retry----try-again-on-failure","tutorial/04-making-characters-act.html#timeout----time-limits","tutorial/04-making-characters-act.html#cooldown----rate-limiting","tutorial/04-making-characters-act.html#if-as-decorator-guard","tutorial/04-making-characters-act.html#succeed_always-and-fail_always","tutorial/04-making-characters-act.html#combining-decorators","tutorial/04-making-characters-act.html#subtree-references","tutorial/04-making-characters-act.html#behavior-linking-with-priorities","tutorial/04-making-characters-act.html#a-complete-example","tutorial/04-making-characters-act.html#next-steps","tutorial/05-advanced-behaviors.html#advanced-behaviors","tutorial/05-advanced-behaviors.html#deep-decision-trees","tutorial/05-advanced-behaviors.html#modular-subtrees","tutorial/05-advanced-behaviors.html#conditional-behavior-selection","tutorial/05-advanced-behaviors.html#decorator-combinations","tutorial/05-advanced-behaviors.html#prose-documentation","tutorial/05-advanced-behaviors.html#design-tips","tutorial/05-advanced-behaviors.html#next-steps","tutorial/06-relationships.html#character-relationships","tutorial/06-relationships.html#basic-relationships","tutorial/06-relationships.html#adding-roles","tutorial/06-relationships.html#perspectives-self-and-other","tutorial/06-relationships.html#prose-in-relationships","tutorial/06-relationships.html#multi-party-relationships","tutorial/06-relationships.html#asymmetric-awareness","tutorial/06-relationships.html#institutional-relationships","tutorial/06-relationships.html#building-a-relationship-web","tutorial/06-relationships.html#next-steps","tutorial/07-schedules.html#schedules-and-time","tutorial/07-schedules.html#basic-schedules","tutorial/07-schedules.html#named-blocks","tutorial/07-schedules.html#linking-schedules-to-characters","tutorial/07-schedules.html#temporal-constraints","tutorial/07-schedules.html#season-constraints","tutorial/07-schedules.html#day-of-week-constraints","tutorial/07-schedules.html#recurring-events","tutorial/07-schedules.html#schedule-composition-with-extends","tutorial/07-schedules.html#overnight-blocks","tutorial/07-schedules.html#a-complete-schedule-example","tutorial/07-schedules.html#next-steps","tutorial/08-life-arcs.html#life-arcs","tutorial/08-life-arcs.html#what-is-a-life-arc","tutorial/08-life-arcs.html#your-first-life-arc","tutorial/08-life-arcs.html#states","tutorial/08-life-arcs.html#transitions","tutorial/08-life-arcs.html#transition-priority","tutorial/08-life-arcs.html#on-enter-actions","tutorial/08-life-arcs.html#elenas-complete-journey","tutorial/08-life-arcs.html#common-patterns","tutorial/08-life-arcs.html#hub-and-spoke","tutorial/08-life-arcs.html#linear-progression","tutorial/08-life-arcs.html#cyclic-states","tutorial/08-life-arcs.html#tips","tutorial/08-life-arcs.html#what-you-have-learned","tutorial/08-life-arcs.html#where-to-go-next","tutorial/09-locations-institutions.html#locations-and-institutions","tutorial/09-locations-institutions.html#what-are-locations","tutorial/09-locations-institutions.html#your-first-location","tutorial/09-locations-institutions.html#adding-detail","tutorial/09-locations-institutions.html#prose-blocks","tutorial/09-locations-institutions.html#building-a-world-with-locations","tutorial/09-locations-institutions.html#modeling-hierarchy","tutorial/09-locations-institutions.html#what-are-institutions","tutorial/09-locations-institutions.html#your-first-institution","tutorial/09-locations-institutions.html#institutions-with-behaviors","tutorial/09-locations-institutions.html#behavior-priorities","tutorial/09-locations-institutions.html#conditional-behaviors","tutorial/09-locations-institutions.html#institutions-with-schedules","tutorial/09-locations-institutions.html#prose-blocks-1","tutorial/09-locations-institutions.html#connecting-characters-to-institutions","tutorial/09-locations-institutions.html#through-character-fields","tutorial/09-locations-institutions.html#through-relationships","tutorial/09-locations-institutions.html#locations-vs-institutions","tutorial/09-locations-institutions.html#putting-it-all-together","tutorial/09-locations-institutions.html#key-takeaways","tutorial/09-locations-institutions.html#next-steps","reference/09-overview.html#language-overview","reference/09-overview.html#philosophy","reference/09-overview.html#design-principles","reference/09-overview.html#1-code-as-narrative","reference/09-overview.html#2-explicit-is-better-than-implicit","reference/09-overview.html#3-progressive-disclosure","reference/09-overview.html#4-semantic-validation","reference/09-overview.html#language-structure","reference/09-overview.html#declaration-types","reference/09-overview.html#value-types","reference/09-overview.html#expression-language","reference/09-overview.html#compilation-model","reference/09-overview.html#source--ast--sbir--runtime","reference/09-overview.html#validation-layers","reference/09-overview.html#file-organization","reference/09-overview.html#project-structure","reference/09-overview.html#import-system","reference/09-overview.html#quick-reference","reference/09-overview.html#character-declaration","reference/09-overview.html#behavior-tree","reference/09-overview.html#life-arc","reference/09-overview.html#schedule","reference/09-overview.html#relationship","reference/09-overview.html#next-steps","reference/10-characters.html#characters","reference/10-characters.html#syntax","reference/10-characters.html#components","reference/10-characters.html#name","reference/10-characters.html#species-optional","reference/10-characters.html#template-inheritance-optional","reference/10-characters.html#fields","reference/10-characters.html#prose-blocks","reference/10-characters.html#behavior-integration","reference/10-characters.html#schedule-integration","reference/10-characters.html#species-vs-templates","reference/10-characters.html#field-resolution-order","reference/10-characters.html#validation-rules","reference/10-characters.html#examples","reference/10-characters.html#basic-character","reference/10-characters.html#character-with-species","reference/10-characters.html#character-with-template-inheritance","reference/10-characters.html#character-with-all-features","reference/10-characters.html#character-with-overrides","reference/10-characters.html#use-cases","reference/10-characters.html#protagonist-definition","reference/10-characters.html#npc-templates","reference/10-characters.html#ensemble-casts","reference/10-characters.html#cross-references","reference/10-characters.html#related-concepts","reference/11-behavior-trees.html#behavior-trees","reference/11-behavior-trees.html#what-is-a-behavior-tree","reference/11-behavior-trees.html#syntax","reference/11-behavior-trees.html#composite-nodes","reference/11-behavior-trees.html#selector-choose","reference/11-behavior-trees.html#sequence-then","reference/11-behavior-trees.html#nesting-composites","reference/11-behavior-trees.html#condition-nodes","reference/11-behavior-trees.html#if-vs-when","reference/11-behavior-trees.html#condition-syntax","reference/11-behavior-trees.html#action-nodes","reference/11-behavior-trees.html#basic-actions","reference/11-behavior-trees.html#actions-with-parameters","reference/11-behavior-trees.html#decorator-nodes","reference/11-behavior-trees.html#common-decorators","reference/11-behavior-trees.html#subtree-references","reference/11-behavior-trees.html#basic-subtree","reference/11-behavior-trees.html#qualified-subtree-references","reference/11-behavior-trees.html#named-nodes","reference/11-behavior-trees.html#complete-examples","reference/11-behavior-trees.html#simple-guard-ai","reference/11-behavior-trees.html#complex-npc-behavior","reference/11-behavior-trees.html#morning-baking-routine","reference/11-behavior-trees.html#repeating-behavior","reference/11-behavior-trees.html#retry-logic-for-delicate-recipes","reference/11-behavior-trees.html#integration-with-characters","reference/11-behavior-trees.html#execution-semantics","reference/11-behavior-trees.html#tick-based-evaluation","reference/11-behavior-trees.html#node-return-values","reference/11-behavior-trees.html#stateful-vs-stateless","reference/11-behavior-trees.html#validation-rules","reference/11-behavior-trees.html#best-practices","reference/11-behavior-trees.html#1-prefer-shallow-trees","reference/11-behavior-trees.html#2-use-named-nodes-for-clarity","reference/11-behavior-trees.html#3-subtrees-for-reusability","reference/11-behavior-trees.html#4-decorators-for-timing","reference/11-behavior-trees.html#5-guard-for-preconditions","reference/11-behavior-trees.html#cross-references","reference/11-behavior-trees.html#related-concepts","reference/12-decorators.html#decorators","reference/12-decorators.html#what-are-decorators","reference/12-decorators.html#decorator-types","reference/12-decorators.html#syntax","reference/12-decorators.html#repeat-decorators","reference/12-decorators.html#infinite-repeat-repeat","reference/12-decorators.html#repeat-n-times-repeat-n","reference/12-decorators.html#repeat-range-repeat-minmax","reference/12-decorators.html#invert-decorator","reference/12-decorators.html#retry-decorator","reference/12-decorators.html#timeout-decorator","reference/12-decorators.html#cooldown-decorator","reference/12-decorators.html#if-decorator","reference/12-decorators.html#force-result-decorators","reference/12-decorators.html#succeed_always","reference/12-decorators.html#fail_always","reference/12-decorators.html#combining-decorators","reference/12-decorators.html#duration-syntax","reference/12-decorators.html#comparison-table","reference/12-decorators.html#validation-rules","reference/12-decorators.html#use-cases-by-category","reference/12-decorators.html#timing-control","reference/12-decorators.html#reliability","reference/12-decorators.html#logic-control","reference/12-decorators.html#iteration","reference/12-decorators.html#best-practices","reference/12-decorators.html#1-use-guards-for-expensive-checks","reference/12-decorators.html#2-combine-timeout-with-retry","reference/12-decorators.html#3-use-cooldowns-for-rate-limiting","reference/12-decorators.html#4-invert-for-readable-conditions","reference/12-decorators.html#5-succeed_always-for-optional-tasks","reference/12-decorators.html#cross-references","reference/12-decorators.html#related-concepts","reference/13-life-arcs.html#life-arcs","reference/13-life-arcs.html#what-is-a-life-arc","reference/13-life-arcs.html#syntax","reference/13-life-arcs.html#states","reference/13-life-arcs.html#basic-state","reference/13-life-arcs.html#state-names","reference/13-life-arcs.html#on-enter-actions","reference/13-life-arcs.html#syntax-1","reference/13-life-arcs.html#examples","reference/13-life-arcs.html#field-update-semantics","reference/13-life-arcs.html#multiple-field-updates","reference/13-life-arcs.html#transitions","reference/13-life-arcs.html#syntax-2","reference/13-life-arcs.html#basic-transitions","reference/13-life-arcs.html#expression-conditions","reference/13-life-arcs.html#multiple-transitions","reference/13-life-arcs.html#self-transitions","reference/13-life-arcs.html#complete-examples","reference/13-life-arcs.html#elenas-career-journey","reference/13-life-arcs.html#quest-progress","reference/13-life-arcs.html#name-checker-equality-examples","reference/13-life-arcs.html#status-monitor","reference/13-life-arcs.html#character-mood-swings","reference/13-life-arcs.html#execution-semantics","reference/13-life-arcs.html#tick-based-evaluation","reference/13-life-arcs.html#transition-priority","reference/13-life-arcs.html#state-persistence","reference/13-life-arcs.html#on-enter-execution","reference/13-life-arcs.html#validation-rules","reference/13-life-arcs.html#design-patterns","reference/13-life-arcs.html#1-hub-and-spoke","reference/13-life-arcs.html#2-linear-progression","reference/13-life-arcs.html#3-cyclic-states","reference/13-life-arcs.html#4-hierarchical-simulated","reference/13-life-arcs.html#best-practices","reference/13-life-arcs.html#1-use-descriptive-state-names","reference/13-life-arcs.html#2-add-narrative-prose-blocks","reference/13-life-arcs.html#3-order-transitions-by-priority","reference/13-life-arcs.html#4-avoid-orphan-states","reference/13-life-arcs.html#5-use-on-enter-for-state-initialization","reference/13-life-arcs.html#cross-references","reference/13-life-arcs.html#related-concepts","reference/14-schedules.html#schedules","reference/14-schedules.html#what-is-a-schedule","reference/14-schedules.html#syntax","reference/14-schedules.html#schedule-blocks","reference/14-schedules.html#basic-block","reference/14-schedules.html#named-block","reference/14-schedules.html#block-content","reference/14-schedules.html#time-ranges","reference/14-schedules.html#syntax-1","reference/14-schedules.html#examples","reference/14-schedules.html#overnight-ranges","reference/14-schedules.html#actions","reference/14-schedules.html#syntax-2","reference/14-schedules.html#examples-1","reference/14-schedules.html#qualified-paths","reference/14-schedules.html#temporal-constraints","reference/14-schedules.html#season-constraint","reference/14-schedules.html#day-of-week-constraint","reference/14-schedules.html#month-constraint","reference/14-schedules.html#date-range-constraint","reference/14-schedules.html#recurrence-patterns","reference/14-schedules.html#syntax-3","reference/14-schedules.html#examples-2","reference/14-schedules.html#schedule-composition","reference/14-schedules.html#extends-clause","reference/14-schedules.html#override-semantics","reference/14-schedules.html#multiple-levels","reference/14-schedules.html#complete-examples","reference/14-schedules.html#simple-daily-schedule","reference/14-schedules.html#seasonal-variation","reference/14-schedules.html#weekly-pattern-with-recurrence","reference/14-schedules.html#extended-schedule","reference/14-schedules.html#complex-year-round-schedule","reference/14-schedules.html#integration-with-characters","reference/14-schedules.html#execution-semantics","reference/14-schedules.html#time-based-selection","reference/14-schedules.html#priority-order","reference/14-schedules.html#block-overlap","reference/14-schedules.html#validation-rules","reference/14-schedules.html#best-practices","reference/14-schedules.html#1-use-named-blocks-for-overrides","reference/14-schedules.html#2-group-related-blocks","reference/14-schedules.html#3-use-recurrences-for-special-events","reference/14-schedules.html#4-extend-for-variations","reference/14-schedules.html#5-use-temporal-constraints-for-clarity","reference/14-schedules.html#cross-references","reference/14-schedules.html#related-concepts","reference/15-relationships.html#relationships","reference/15-relationships.html#what-is-a-relationship","reference/15-relationships.html#syntax","reference/15-relationships.html#basic-relationships","reference/15-relationships.html#simple-two-party-relationship","reference/15-relationships.html#multi-party-relationship","reference/15-relationships.html#roles","reference/15-relationships.html#syntax-1","reference/15-relationships.html#examples","reference/15-relationships.html#role-semantics","reference/15-relationships.html#perspective-fields-selfother-blocks","reference/15-relationships.html#syntax-2","reference/15-relationships.html#self-block","reference/15-relationships.html#other-block","reference/15-relationships.html#both-blocks","reference/15-relationships.html#asymmetric-relationships","reference/15-relationships.html#shared-fields","reference/15-relationships.html#prose-blocks","reference/15-relationships.html#complete-examples","reference/15-relationships.html#simple-friendship","reference/15-relationships.html#marriage-with-roles","reference/15-relationships.html#parent-child-with-perspectives","reference/15-relationships.html#employer-employee","reference/15-relationships.html#complex-multi-perspective","reference/15-relationships.html#business-rivalry","reference/15-relationships.html#multi-party-family","reference/15-relationships.html#co-owners-partnership","reference/15-relationships.html#participant-types","reference/15-relationships.html#field-resolution","reference/15-relationships.html#validation-rules","reference/15-relationships.html#use-cases","reference/15-relationships.html#social-networks","reference/15-relationships.html#family-structures","reference/15-relationships.html#power-dynamics","reference/15-relationships.html#asymmetric-awareness","reference/15-relationships.html#best-practices","reference/15-relationships.html#1-use-descriptive-relationship-names","reference/15-relationships.html#2-use-roles-for-clarity","reference/15-relationships.html#3-shared-fields-for-mutual-properties","reference/15-relationships.html#4-selfother-for-perspectives","reference/15-relationships.html#5-prose-blocks-for-rich-context","reference/15-relationships.html#cross-references","reference/15-relationships.html#related-concepts","reference/16a-locations.html#locations","reference/16a-locations.html#syntax","reference/16a-locations.html#basic-location","reference/16a-locations.html#fields","reference/16a-locations.html#common-field-patterns","reference/16a-locations.html#prose-blocks","reference/16a-locations.html#ranges","reference/16a-locations.html#lists","reference/16a-locations.html#referencing-other-entities","reference/16a-locations.html#nested-structure-with-fields","reference/16a-locations.html#location-with-enum-fields","reference/16a-locations.html#complete-example-baker-family-locations","reference/16a-locations.html#validation-rules","reference/16a-locations.html#locations-vs-other-declarations","reference/16a-locations.html#cross-references","reference/16b-institutions.html#institutions","reference/16b-institutions.html#syntax","reference/16b-institutions.html#basic-institution","reference/16b-institutions.html#fields","reference/16b-institutions.html#common-field-patterns","reference/16b-institutions.html#prose-blocks","reference/16b-institutions.html#resource-linking-behaviors","reference/16b-institutions.html#simple-behavior-linking","reference/16b-institutions.html#behavior-links-with-priority","reference/16b-institutions.html#conditional-behavior-links","reference/16b-institutions.html#behavior-link-fields","reference/16b-institutions.html#resource-linking-schedules","reference/16b-institutions.html#single-schedule","reference/16b-institutions.html#multiple-schedules","reference/16b-institutions.html#complete-syntax-example","reference/16b-institutions.html#membership-modeling","reference/16b-institutions.html#via-character-fields","reference/16b-institutions.html#via-relationships","reference/16b-institutions.html#institutions-vs-characters","reference/16b-institutions.html#use-cases","reference/16b-institutions.html#complete-example-baker-family-world","reference/16b-institutions.html#validation-rules","reference/16b-institutions.html#cross-references","reference/16-other-declarations.html#other-declarations","reference/16-other-declarations.html#templates","reference/16-other-declarations.html#syntax","reference/16-other-declarations.html#basic-template","reference/16-other-declarations.html#template-includes","reference/16-other-declarations.html#range-values","reference/16-other-declarations.html#strict-mode","reference/16-other-declarations.html#resource-linking-in-templates","reference/16-other-declarations.html#templates-vs-species","reference/16-other-declarations.html#validation-rules","reference/16-other-declarations.html#institutions","reference/16-other-declarations.html#syntax-1","reference/16-other-declarations.html#basic-institution","reference/16-other-declarations.html#institutions-with-fields","reference/16-other-declarations.html#resource-linking","reference/16-other-declarations.html#prose-blocks","reference/16-other-declarations.html#use-cases","reference/16-other-declarations.html#validation-rules-1","reference/16-other-declarations.html#locations","reference/16-other-declarations.html#syntax-2","reference/16-other-declarations.html#basic-location","reference/16-other-declarations.html#location-with-structure","reference/16-other-declarations.html#geographic-hierarchy","reference/16-other-declarations.html#location-with-state","reference/16-other-declarations.html#use-cases-1","reference/16-other-declarations.html#validation-rules-2","reference/16-other-declarations.html#species","reference/16-other-declarations.html#syntax-3","reference/16-other-declarations.html#basic-species","reference/16-other-declarations.html#species-with-includes","reference/16-other-declarations.html#field-resolution-with-includes","reference/16-other-declarations.html#species-vs-templates","reference/16-other-declarations.html#design-pattern-prefer-composition-over-deep-hierarchies","reference/16-other-declarations.html#validation-rules-3","reference/16-other-declarations.html#enums","reference/16-other-declarations.html#syntax-4","reference/16-other-declarations.html#basic-enum","reference/16-other-declarations.html#using-enums","reference/16-other-declarations.html#common-enum-patterns","reference/16-other-declarations.html#calendar-enums-configurable","reference/16-other-declarations.html#validation-integration","reference/16-other-declarations.html#use-cases-2","reference/16-other-declarations.html#validation-rules-4","reference/16-other-declarations.html#use-statements","reference/16-other-declarations.html#syntax-5","reference/16-other-declarations.html#single-import","reference/16-other-declarations.html#grouped-import","reference/16-other-declarations.html#wildcard-import","reference/16-other-declarations.html#qualified-paths","reference/16-other-declarations.html#path-resolution","reference/16-other-declarations.html#common-patterns","reference/16-other-declarations.html#validation-rules-5","reference/16-other-declarations.html#best-practices","reference/16-other-declarations.html#cross-references","reference/16-other-declarations.html#related-concepts","reference/17-expressions.html#expression-language","reference/17-expressions.html#what-are-expressions","reference/17-expressions.html#syntax","reference/17-expressions.html#literals","reference/17-expressions.html#integer-literals","reference/17-expressions.html#float-literals","reference/17-expressions.html#string-literals","reference/17-expressions.html#boolean-literals","reference/17-expressions.html#identifiers","reference/17-expressions.html#simple-identifiers","reference/17-expressions.html#qualified-paths","reference/17-expressions.html#comparison-operators","reference/17-expressions.html#equality-","reference/17-expressions.html#inequality-","reference/17-expressions.html#less-than-","reference/17-expressions.html#less-than-or-equal-","reference/17-expressions.html#greater-than-","reference/17-expressions.html#greater-than-or-equal-","reference/17-expressions.html#logical-operators","reference/17-expressions.html#and-and","reference/17-expressions.html#or-or","reference/17-expressions.html#operator-precedence","reference/17-expressions.html#unary-operators","reference/17-expressions.html#not-not","reference/17-expressions.html#negation--","reference/17-expressions.html#field-access","reference/17-expressions.html#direct-field-access","reference/17-expressions.html#dot-access","reference/17-expressions.html#self-access","reference/17-expressions.html#other-access","reference/17-expressions.html#example-in-life-arcs","reference/17-expressions.html#quantifiers","reference/17-expressions.html#forall-forall","reference/17-expressions.html#exists-exists","reference/17-expressions.html#nested-quantifiers","reference/17-expressions.html#usage-in-context","reference/17-expressions.html#life-arc-transitions","reference/17-expressions.html#behavior-tree-conditions","reference/17-expressions.html#behavior-tree-conditions-1","reference/17-expressions.html#type-system","reference/17-expressions.html#type-compatibility","reference/17-expressions.html#implicit-coercion","reference/17-expressions.html#special-keyword-is","reference/17-expressions.html#complete-examples","reference/17-expressions.html#simple-conditions","reference/17-expressions.html#complex-conditions","reference/17-expressions.html#life-arc-with-complex-conditions","reference/17-expressions.html#behavior-with-quantifiers","reference/17-expressions.html#relationship-query","reference/17-expressions.html#validation-rules","reference/17-expressions.html#best-practices","reference/17-expressions.html#1-use-parentheses-for-clarity","reference/17-expressions.html#2-break-complex-conditions","reference/17-expressions.html#3-name-complex-conditions","reference/17-expressions.html#4-use-is-for-enums","reference/17-expressions.html#5-quantifiers-for-collections","reference/17-expressions.html#cross-references","reference/17-expressions.html#related-concepts","reference/18-value-types.html#values","reference/18-value-types.html#value-types-overview","reference/18-value-types.html#integer","reference/18-value-types.html#syntax","reference/18-value-types.html#examples","reference/18-value-types.html#range","reference/18-value-types.html#use-cases","reference/18-value-types.html#float","reference/18-value-types.html#syntax-1","reference/18-value-types.html#examples-1","reference/18-value-types.html#special-values","reference/18-value-types.html#use-cases-1","reference/18-value-types.html#string","reference/18-value-types.html#syntax-2","reference/18-value-types.html#escape-sequences","reference/18-value-types.html#examples-2","reference/18-value-types.html#limitations","reference/18-value-types.html#use-cases-2","reference/18-value-types.html#boolean","reference/18-value-types.html#syntax-3","reference/18-value-types.html#examples-3","reference/18-value-types.html#use-cases-3","reference/18-value-types.html#time","reference/18-value-types.html#syntax-4","reference/18-value-types.html#examples-4","reference/18-value-types.html#validation","reference/18-value-types.html#use-cases-4","reference/18-value-types.html#duration","reference/18-value-types.html#syntax-5","reference/18-value-types.html#examples-5","reference/18-value-types.html#components","reference/18-value-types.html#validation-1","reference/18-value-types.html#use-cases-5","reference/18-value-types.html#range-1","reference/18-value-types.html#syntax-6","reference/18-value-types.html#examples-6","reference/18-value-types.html#semantics","reference/18-value-types.html#validation-2","reference/18-value-types.html#use-cases-6","reference/18-value-types.html#identifier","reference/18-value-types.html#syntax-7","reference/18-value-types.html#examples-7","reference/18-value-types.html#resolution","reference/18-value-types.html#use-cases-7","reference/18-value-types.html#list","reference/18-value-types.html#syntax-8","reference/18-value-types.html#examples-8","reference/18-value-types.html#type-constraints","reference/18-value-types.html#operations","reference/18-value-types.html#use-cases-8","reference/18-value-types.html#object","reference/18-value-types.html#syntax-9","reference/18-value-types.html#examples-9","reference/18-value-types.html#nesting","reference/18-value-types.html#use-cases-9","reference/18-value-types.html#prose-blocks","reference/18-value-types.html#syntax-10","reference/18-value-types.html#common-tags","reference/18-value-types.html#examples-10","reference/18-value-types.html#formatting","reference/18-value-types.html#multiple-prose-blocks","reference/18-value-types.html#use-cases-10","reference/18-value-types.html#override","reference/18-value-types.html#syntax-11","reference/18-value-types.html#examples-11","reference/18-value-types.html#operations-1","reference/18-value-types.html#validation-3","reference/18-value-types.html#use-cases-11","reference/18-value-types.html#type-coercion","reference/18-value-types.html#null-and-optional","reference/18-value-types.html#summary-table","reference/18-value-types.html#cross-references","reference/18-value-types.html#related-concepts","reference/19-validation.html#validation-rules","reference/19-validation.html#validation-layers","reference/19-validation.html#character-validation","reference/19-validation.html#required-rules","reference/19-validation.html#examples","reference/19-validation.html#template-validation","reference/19-validation.html#examples-1","reference/19-validation.html#behavior-tree-validation","reference/19-validation.html#examples-2","reference/19-validation.html#life-arc-validation","reference/19-validation.html#examples-3","reference/19-validation.html#schedule-validation","reference/19-validation.html#examples-4","reference/19-validation.html#relationship-validation","reference/19-validation.html#examples-5","reference/19-validation.html#species-validation","reference/19-validation.html#enum-validation","reference/19-validation.html#examples-6","reference/19-validation.html#institution-and-location-validation","reference/19-validation.html#expression-validation","reference/19-validation.html#examples-7","reference/19-validation.html#use-statement-validation","reference/19-validation.html#examples-8","reference/19-validation.html#cross-file-validation","reference/19-validation.html#common-error-patterns","reference/19-validation.html#missing-definitions","reference/19-validation.html#circular-dependencies","reference/19-validation.html#type-mismatches","reference/19-validation.html#validation-summary","reference/19-validation.html#cross-references","advanced/20-patterns.html#design-patterns","advanced/20-patterns.html#behavior-tree-patterns","advanced/20-patterns.html#priority-fallback-chain","advanced/20-patterns.html#conditional-behavior-switching","advanced/20-patterns.html#composite-subtree-pattern","advanced/20-patterns.html#repeating-patrol-with-interrupts","advanced/20-patterns.html#character-architecture-patterns","advanced/20-patterns.html#species--templates-composition","advanced/20-patterns.html#strict-templates-for-schema-enforcement","advanced/20-patterns.html#template-inheritance-chains","advanced/20-patterns.html#relationship-patterns","advanced/20-patterns.html#bidirectional-perspective","advanced/20-patterns.html#power-dynamic-pattern","advanced/20-patterns.html#relationship-network","advanced/20-patterns.html#schedule-patterns","advanced/20-patterns.html#base-schedule-with-specializations","advanced/20-patterns.html#seasonal-variation","advanced/20-patterns.html#life-arc-patterns","advanced/20-patterns.html#progressive-development","advanced/20-patterns.html#emotional-state-machine","advanced/20-patterns.html#project-organization-patterns","advanced/20-patterns.html#schema--world-separation","advanced/20-patterns.html#module-per-domain","advanced/20-patterns.html#anti-patterns-to-avoid","advanced/20-patterns.html#cross-references","advanced/21-sbir-format.html#the-sbir-binary-format","advanced/21-sbir-format.html#compilation-pipeline","advanced/21-sbir-format.html#what-sbir-contains","advanced/21-sbir-format.html#resolution-process","advanced/21-sbir-format.html#template-merging","advanced/21-sbir-format.html#cross-file-reference-resolution","advanced/21-sbir-format.html#validation","advanced/21-sbir-format.html#design-goals","advanced/21-sbir-format.html#usage","advanced/21-sbir-format.html#cross-references","advanced/22-integration.html#integration-guide","advanced/22-integration.html#architecture-overview","advanced/22-integration.html#the-storybook-compiler","advanced/22-integration.html#cli-usage","advanced/22-integration.html#as-a-library","advanced/22-integration.html#key-types","advanced/22-integration.html#runtime-integration","advanced/22-integration.html#behavior-tree-execution","advanced/22-integration.html#life-arc-execution","advanced/22-integration.html#schedule-execution","advanced/22-integration.html#relationship-queries","advanced/22-integration.html#lsp-integration","advanced/22-integration.html#editor-setup","advanced/22-integration.html#tree-sitter-grammar","advanced/22-integration.html#file-organization-for-integration","advanced/22-integration.html#cross-references","advanced/23-best-practices.html#best-practices","advanced/23-best-practices.html#naming-conventions","advanced/23-best-practices.html#declarations","advanced/23-best-practices.html#fields","advanced/23-best-practices.html#behavior-tree-labels","advanced/23-best-practices.html#enum-variants","advanced/23-best-practices.html#file-organization","advanced/23-best-practices.html#separate-schema-from-world","advanced/23-best-practices.html#one-concern-per-file","advanced/23-best-practices.html#explicit-imports","advanced/23-best-practices.html#character-design","advanced/23-best-practices.html#use-species-for-identity-templates-for-traits","advanced/23-best-practices.html#document-with-prose-blocks","advanced/23-best-practices.html#prefer-flat-inheritance","advanced/23-best-practices.html#behavior-tree-design","advanced/23-best-practices.html#name-every-composite-node","advanced/23-best-practices.html#keep-trees-shallow","advanced/23-best-practices.html#use-decorators-for-control-flow","advanced/23-best-practices.html#expression-writing","advanced/23-best-practices.html#use-parentheses-for-clarity","advanced/23-best-practices.html#break-complex-conditions-into-multiple-transitions","advanced/23-best-practices.html#use-is-for-enum-comparisons","advanced/23-best-practices.html#schedule-design","advanced/23-best-practices.html#use-named-blocks-for-override-support","advanced/23-best-practices.html#group-related-blocks","advanced/23-best-practices.html#relationship-design","advanced/23-best-practices.html#use-roles-for-clarity","advanced/23-best-practices.html#use-perspectives-for-asymmetry","advanced/23-best-practices.html#general-principles","advanced/23-best-practices.html#cross-references","examples/24-baker-family-complete.html#baker-family-complete","examples/24-baker-family-complete.html#project-structure","examples/24-baker-family-complete.html#schema-layer","examples/24-baker-family-complete.html#enums","examples/24-baker-family-complete.html#species","examples/24-baker-family-complete.html#templates","examples/24-baker-family-complete.html#characters","examples/24-baker-family-complete.html#martha","examples/24-baker-family-complete.html#jane","examples/24-baker-family-complete.html#elena","examples/24-baker-family-complete.html#gregory","examples/24-baker-family-complete.html#behaviors","examples/24-baker-family-complete.html#relationships","examples/24-baker-family-complete.html#locations","examples/24-baker-family-complete.html#institutions","examples/24-baker-family-complete.html#key-takeaways","examples/24-baker-family-complete.html#cross-references","examples/25-day-in-life.html#day-in-the-life","examples/25-day-in-life.html#the-baker","examples/25-day-in-life.html#the-schedule","examples/25-day-in-life.html#behaviors","examples/25-day-in-life.html#morning-routine","examples/25-day-in-life.html#baking-behavior","examples/25-day-in-life.html#customer-service","examples/25-day-in-life.html#emergency-handling","examples/25-day-in-life.html#life-arc-career-and-energy","examples/25-day-in-life.html#relationships","examples/25-day-in-life.html#key-takeaways","examples/25-day-in-life.html#cross-references","examples/26-character-evolution.html#character-evolution","examples/26-character-evolution.html#the-apprentices-journey","examples/26-character-evolution.html#schema","examples/26-character-evolution.html#the-character-at-different-stages","examples/26-character-evolution.html#the-evolution-life-arc","examples/26-character-evolution.html#evolving-behaviors","examples/26-character-evolution.html#evolving-relationships","examples/26-character-evolution.html#evolving-schedules","examples/26-character-evolution.html#key-takeaways","examples/26-character-evolution.html#cross-references","examples/27-multi-character.html#multi-character-interactions","examples/27-multi-character.html#the-setting","examples/27-multi-character.html#the-characters","examples/27-multi-character.html#interlocking-behaviors","examples/27-multi-character.html#marthas-behavior","examples/27-multi-character.html#janes-behavior","examples/27-multi-character.html#elenas-behavior","examples/27-multi-character.html#gregorys-behavior","examples/27-multi-character.html#relationships","examples/27-multi-character.html#the-saturday-schedule","examples/27-multi-character.html#life-arc-elenas-saturday-confidence","examples/27-multi-character.html#key-takeaways","examples/27-multi-character.html#cross-references"],"index":{"documentStore":{"docInfo":{"0":{"body":97,"breadcrumbs":4,"title":3},"1":{"body":95,"breadcrumbs":2,"title":1},"10":{"body":55,"breadcrumbs":3,"title":1},"100":{"body":29,"breadcrumbs":4,"title":2},"101":{"body":39,"breadcrumbs":3,"title":1},"102":{"body":32,"breadcrumbs":3,"title":1},"103":{"body":26,"breadcrumbs":4,"title":2},"104":{"body":21,"breadcrumbs":4,"title":2},"105":{"body":20,"breadcrumbs":3,"title":1},"106":{"body":31,"breadcrumbs":4,"title":2},"107":{"body":45,"breadcrumbs":4,"title":2},"108":{"body":82,"breadcrumbs":4,"title":2},"109":{"body":88,"breadcrumbs":5,"title":3},"11":{"body":35,"breadcrumbs":3,"title":1},"110":{"body":41,"breadcrumbs":4,"title":2},"111":{"body":21,"breadcrumbs":3,"title":1},"112":{"body":17,"breadcrumbs":4,"title":2},"113":{"body":44,"breadcrumbs":4,"title":2},"114":{"body":39,"breadcrumbs":4,"title":2},"115":{"body":37,"breadcrumbs":4,"title":2},"116":{"body":20,"breadcrumbs":4,"title":2},"117":{"body":42,"breadcrumbs":4,"title":2},"118":{"body":10,"breadcrumbs":5,"title":3},"119":{"body":29,"breadcrumbs":5,"title":3},"12":{"body":58,"breadcrumbs":5,"title":3},"120":{"body":37,"breadcrumbs":4,"title":2},"121":{"body":74,"breadcrumbs":5,"title":3},"122":{"body":200,"breadcrumbs":4,"title":2},"123":{"body":46,"breadcrumbs":4,"title":2},"124":{"body":25,"breadcrumbs":4,"title":2},"125":{"body":12,"breadcrumbs":4,"title":2},"126":{"body":40,"breadcrumbs":3,"title":1},"127":{"body":0,"breadcrumbs":4,"title":2},"128":{"body":14,"breadcrumbs":5,"title":3},"129":{"body":15,"breadcrumbs":6,"title":4},"13":{"body":0,"breadcrumbs":4,"title":2},"130":{"body":22,"breadcrumbs":5,"title":3},"131":{"body":17,"breadcrumbs":5,"title":3},"132":{"body":0,"breadcrumbs":4,"title":2},"133":{"body":80,"breadcrumbs":4,"title":2},"134":{"body":30,"breadcrumbs":4,"title":2},"135":{"body":28,"breadcrumbs":4,"title":2},"136":{"body":0,"breadcrumbs":4,"title":2},"137":{"body":26,"breadcrumbs":6,"title":4},"138":{"body":20,"breadcrumbs":4,"title":2},"139":{"body":0,"breadcrumbs":4,"title":2},"14":{"body":33,"breadcrumbs":4,"title":2},"140":{"body":12,"breadcrumbs":4,"title":2},"141":{"body":22,"breadcrumbs":4,"title":2},"142":{"body":0,"breadcrumbs":4,"title":2},"143":{"body":11,"breadcrumbs":4,"title":2},"144":{"body":14,"breadcrumbs":4,"title":2},"145":{"body":6,"breadcrumbs":4,"title":2},"146":{"body":8,"breadcrumbs":3,"title":1},"147":{"body":8,"breadcrumbs":3,"title":1},"148":{"body":71,"breadcrumbs":4,"title":2},"149":{"body":17,"breadcrumbs":2,"title":1},"15":{"body":25,"breadcrumbs":5,"title":3},"150":{"body":91,"breadcrumbs":2,"title":1},"151":{"body":0,"breadcrumbs":2,"title":1},"152":{"body":13,"breadcrumbs":2,"title":1},"153":{"body":37,"breadcrumbs":3,"title":2},"154":{"body":49,"breadcrumbs":4,"title":3},"155":{"body":36,"breadcrumbs":2,"title":1},"156":{"body":32,"breadcrumbs":3,"title":2},"157":{"body":49,"breadcrumbs":3,"title":2},"158":{"body":43,"breadcrumbs":3,"title":2},"159":{"body":70,"breadcrumbs":4,"title":3},"16":{"body":39,"breadcrumbs":6,"title":4},"160":{"body":66,"breadcrumbs":4,"title":3},"161":{"body":79,"breadcrumbs":3,"title":2},"162":{"body":0,"breadcrumbs":2,"title":1},"163":{"body":20,"breadcrumbs":3,"title":2},"164":{"body":22,"breadcrumbs":3,"title":2},"165":{"body":30,"breadcrumbs":4,"title":3},"166":{"body":70,"breadcrumbs":3,"title":2},"167":{"body":26,"breadcrumbs":3,"title":2},"168":{"body":0,"breadcrumbs":3,"title":2},"169":{"body":50,"breadcrumbs":3,"title":2},"17":{"body":51,"breadcrumbs":4,"title":2},"170":{"body":34,"breadcrumbs":3,"title":2},"171":{"body":44,"breadcrumbs":3,"title":2},"172":{"body":33,"breadcrumbs":3,"title":2},"173":{"body":29,"breadcrumbs":3,"title":2},"174":{"body":28,"breadcrumbs":4,"title":2},"175":{"body":59,"breadcrumbs":4,"title":2},"176":{"body":49,"breadcrumbs":3,"title":1},"177":{"body":0,"breadcrumbs":4,"title":2},"178":{"body":70,"breadcrumbs":4,"title":2},"179":{"body":49,"breadcrumbs":3,"title":1},"18":{"body":28,"breadcrumbs":4,"title":2},"180":{"body":30,"breadcrumbs":4,"title":2},"181":{"body":7,"breadcrumbs":4,"title":2},"182":{"body":22,"breadcrumbs":3,"title":1},"183":{"body":20,"breadcrumbs":4,"title":2},"184":{"body":10,"breadcrumbs":4,"title":2},"185":{"body":6,"breadcrumbs":4,"title":2},"186":{"body":48,"breadcrumbs":4,"title":2},"187":{"body":11,"breadcrumbs":4,"title":2},"188":{"body":67,"breadcrumbs":4,"title":2},"189":{"body":9,"breadcrumbs":4,"title":2},"19":{"body":13,"breadcrumbs":4,"title":2},"190":{"body":22,"breadcrumbs":4,"title":2},"191":{"body":12,"breadcrumbs":5,"title":3},"192":{"body":60,"breadcrumbs":4,"title":2},"193":{"body":0,"breadcrumbs":4,"title":2},"194":{"body":23,"breadcrumbs":5,"title":3},"195":{"body":61,"breadcrumbs":5,"title":3},"196":{"body":37,"breadcrumbs":5,"title":3},"197":{"body":41,"breadcrumbs":4,"title":2},"198":{"body":43,"breadcrumbs":6,"title":4},"199":{"body":53,"breadcrumbs":4,"title":2},"2":{"body":0,"breadcrumbs":3,"title":2},"20":{"body":57,"breadcrumbs":4,"title":2},"200":{"body":0,"breadcrumbs":4,"title":2},"201":{"body":29,"breadcrumbs":5,"title":3},"202":{"body":16,"breadcrumbs":5,"title":3},"203":{"body":30,"breadcrumbs":5,"title":3},"204":{"body":64,"breadcrumbs":4,"title":2},"205":{"body":0,"breadcrumbs":4,"title":2},"206":{"body":13,"breadcrumbs":6,"title":4},"207":{"body":14,"breadcrumbs":7,"title":5},"208":{"body":19,"breadcrumbs":5,"title":3},"209":{"body":9,"breadcrumbs":5,"title":3},"21":{"body":61,"breadcrumbs":6,"title":4},"210":{"body":13,"breadcrumbs":5,"title":3},"211":{"body":24,"breadcrumbs":4,"title":2},"212":{"body":32,"breadcrumbs":4,"title":2},"213":{"body":23,"breadcrumbs":2,"title":1},"214":{"body":29,"breadcrumbs":2,"title":1},"215":{"body":70,"breadcrumbs":3,"title":2},"216":{"body":70,"breadcrumbs":2,"title":1},"217":{"body":0,"breadcrumbs":3,"title":2},"218":{"body":49,"breadcrumbs":4,"title":3},"219":{"body":36,"breadcrumbs":6,"title":5},"22":{"body":66,"breadcrumbs":4,"title":2},"220":{"body":45,"breadcrumbs":5,"title":4},"221":{"body":55,"breadcrumbs":3,"title":2},"222":{"body":69,"breadcrumbs":3,"title":2},"223":{"body":91,"breadcrumbs":3,"title":2},"224":{"body":86,"breadcrumbs":3,"title":2},"225":{"body":101,"breadcrumbs":2,"title":1},"226":{"body":0,"breadcrumbs":4,"title":3},"227":{"body":42,"breadcrumbs":2,"title":1},"228":{"body":36,"breadcrumbs":2,"title":1},"229":{"body":65,"breadcrumbs":3,"title":2},"23":{"body":89,"breadcrumbs":3,"title":1},"230":{"body":61,"breadcrumbs":3,"title":2},"231":{"body":78,"breadcrumbs":3,"title":2},"232":{"body":53,"breadcrumbs":3,"title":2},"233":{"body":0,"breadcrumbs":4,"title":3},"234":{"body":17,"breadcrumbs":3,"title":2},"235":{"body":15,"breadcrumbs":2,"title":1},"236":{"body":9,"breadcrumbs":3,"title":2},"237":{"body":12,"breadcrumbs":2,"title":1},"238":{"body":0,"breadcrumbs":3,"title":2},"239":{"body":10,"breadcrumbs":6,"title":5},"24":{"body":67,"breadcrumbs":5,"title":3},"240":{"body":8,"breadcrumbs":5,"title":4},"241":{"body":7,"breadcrumbs":6,"title":5},"242":{"body":14,"breadcrumbs":5,"title":4},"243":{"body":21,"breadcrumbs":5,"title":4},"244":{"body":20,"breadcrumbs":3,"title":2},"245":{"body":31,"breadcrumbs":3,"title":2},"246":{"body":31,"breadcrumbs":4,"title":2},"247":{"body":61,"breadcrumbs":4,"title":2},"248":{"body":33,"breadcrumbs":3,"title":1},"249":{"body":6,"breadcrumbs":3,"title":1},"25":{"body":25,"breadcrumbs":5,"title":3},"250":{"body":18,"breadcrumbs":4,"title":2},"251":{"body":19,"breadcrumbs":4,"title":2},"252":{"body":7,"breadcrumbs":4,"title":2},"253":{"body":7,"breadcrumbs":3,"title":1},"254":{"body":16,"breadcrumbs":3,"title":1},"255":{"body":22,"breadcrumbs":5,"title":3},"256":{"body":29,"breadcrumbs":5,"title":3},"257":{"body":15,"breadcrumbs":3,"title":1},"258":{"body":6,"breadcrumbs":3,"title":1},"259":{"body":19,"breadcrumbs":4,"title":2},"26":{"body":53,"breadcrumbs":4,"title":2},"260":{"body":45,"breadcrumbs":4,"title":2},"261":{"body":35,"breadcrumbs":4,"title":2},"262":{"body":12,"breadcrumbs":4,"title":2},"263":{"body":0,"breadcrumbs":4,"title":2},"264":{"body":154,"breadcrumbs":5,"title":3},"265":{"body":62,"breadcrumbs":4,"title":2},"266":{"body":18,"breadcrumbs":6,"title":4},"267":{"body":44,"breadcrumbs":4,"title":2},"268":{"body":63,"breadcrumbs":5,"title":3},"269":{"body":0,"breadcrumbs":4,"title":2},"27":{"body":47,"breadcrumbs":6,"title":4},"270":{"body":41,"breadcrumbs":5,"title":3},"271":{"body":34,"breadcrumbs":4,"title":2},"272":{"body":20,"breadcrumbs":4,"title":2},"273":{"body":16,"breadcrumbs":4,"title":2},"274":{"body":52,"breadcrumbs":4,"title":2},"275":{"body":0,"breadcrumbs":4,"title":2},"276":{"body":28,"breadcrumbs":5,"title":3},"277":{"body":26,"breadcrumbs":5,"title":3},"278":{"body":27,"breadcrumbs":5,"title":3},"279":{"body":34,"breadcrumbs":5,"title":3},"28":{"body":39,"breadcrumbs":4,"title":2},"280":{"body":0,"breadcrumbs":4,"title":2},"281":{"body":10,"breadcrumbs":7,"title":5},"282":{"body":17,"breadcrumbs":7,"title":5},"283":{"body":15,"breadcrumbs":6,"title":4},"284":{"body":23,"breadcrumbs":6,"title":4},"285":{"body":9,"breadcrumbs":7,"title":5},"286":{"body":22,"breadcrumbs":4,"title":2},"287":{"body":30,"breadcrumbs":4,"title":2},"288":{"body":33,"breadcrumbs":2,"title":1},"289":{"body":60,"breadcrumbs":2,"title":1},"29":{"body":74,"breadcrumbs":4,"title":2},"290":{"body":67,"breadcrumbs":2,"title":1},"291":{"body":8,"breadcrumbs":3,"title":2},"292":{"body":7,"breadcrumbs":3,"title":2},"293":{"body":25,"breadcrumbs":3,"title":2},"294":{"body":34,"breadcrumbs":3,"title":2},"295":{"body":7,"breadcrumbs":3,"title":2},"296":{"body":14,"breadcrumbs":2,"title":1},"297":{"body":20,"breadcrumbs":2,"title":1},"298":{"body":26,"breadcrumbs":3,"title":2},"299":{"body":7,"breadcrumbs":2,"title":1},"3":{"body":13,"breadcrumbs":2,"title":1},"30":{"body":20,"breadcrumbs":4,"title":2},"300":{"body":3,"breadcrumbs":2,"title":1},"301":{"body":20,"breadcrumbs":2,"title":1},"302":{"body":18,"breadcrumbs":3,"title":2},"303":{"body":11,"breadcrumbs":3,"title":2},"304":{"body":29,"breadcrumbs":3,"title":2},"305":{"body":39,"breadcrumbs":4,"title":3},"306":{"body":18,"breadcrumbs":3,"title":2},"307":{"body":22,"breadcrumbs":4,"title":3},"308":{"body":7,"breadcrumbs":3,"title":2},"309":{"body":6,"breadcrumbs":2,"title":1},"31":{"body":20,"breadcrumbs":6,"title":3},"310":{"body":79,"breadcrumbs":2,"title":1},"311":{"body":8,"breadcrumbs":3,"title":2},"312":{"body":21,"breadcrumbs":3,"title":2},"313":{"body":19,"breadcrumbs":3,"title":2},"314":{"body":55,"breadcrumbs":3,"title":2},"315":{"body":0,"breadcrumbs":3,"title":2},"316":{"body":32,"breadcrumbs":4,"title":3},"317":{"body":34,"breadcrumbs":3,"title":2},"318":{"body":63,"breadcrumbs":4,"title":3},"319":{"body":29,"breadcrumbs":3,"title":2},"32":{"body":44,"breadcrumbs":5,"title":2},"320":{"body":74,"breadcrumbs":5,"title":4},"321":{"body":25,"breadcrumbs":3,"title":2},"322":{"body":0,"breadcrumbs":3,"title":2},"323":{"body":29,"breadcrumbs":4,"title":3},"324":{"body":25,"breadcrumbs":3,"title":2},"325":{"body":35,"breadcrumbs":3,"title":2},"326":{"body":62,"breadcrumbs":3,"title":2},"327":{"body":0,"breadcrumbs":3,"title":2},"328":{"body":26,"breadcrumbs":6,"title":5},"329":{"body":38,"breadcrumbs":5,"title":4},"33":{"body":52,"breadcrumbs":5,"title":2},"330":{"body":15,"breadcrumbs":6,"title":5},"331":{"body":15,"breadcrumbs":4,"title":3},"332":{"body":10,"breadcrumbs":6,"title":5},"333":{"body":20,"breadcrumbs":3,"title":2},"334":{"body":32,"breadcrumbs":3,"title":2},"335":{"body":29,"breadcrumbs":2,"title":1},"336":{"body":53,"breadcrumbs":2,"title":1},"337":{"body":29,"breadcrumbs":2,"title":1},"338":{"body":0,"breadcrumbs":3,"title":2},"339":{"body":22,"breadcrumbs":5,"title":4},"34":{"body":37,"breadcrumbs":6,"title":3},"340":{"body":14,"breadcrumbs":4,"title":3},"341":{"body":5,"breadcrumbs":2,"title":1},"342":{"body":2,"breadcrumbs":2,"title":1},"343":{"body":33,"breadcrumbs":2,"title":1},"344":{"body":23,"breadcrumbs":3,"title":2},"345":{"body":11,"breadcrumbs":5,"title":4},"346":{"body":12,"breadcrumbs":2,"title":1},"347":{"body":35,"breadcrumbs":3,"title":2},"348":{"body":27,"breadcrumbs":2,"title":1},"349":{"body":29,"breadcrumbs":3,"title":2},"35":{"body":30,"breadcrumbs":5,"title":2},"350":{"body":56,"breadcrumbs":3,"title":2},"351":{"body":52,"breadcrumbs":3,"title":2},"352":{"body":81,"breadcrumbs":3,"title":2},"353":{"body":0,"breadcrumbs":3,"title":2},"354":{"body":8,"breadcrumbs":3,"title":2},"355":{"body":14,"breadcrumbs":3,"title":2},"356":{"body":30,"breadcrumbs":4,"title":3},"357":{"body":33,"breadcrumbs":3,"title":2},"358":{"body":69,"breadcrumbs":4,"title":3},"359":{"body":57,"breadcrumbs":3,"title":2},"36":{"body":40,"breadcrumbs":5,"title":2},"360":{"body":38,"breadcrumbs":4,"title":3},"361":{"body":58,"breadcrumbs":4,"title":3},"362":{"body":26,"breadcrumbs":3,"title":2},"363":{"body":56,"breadcrumbs":3,"title":2},"364":{"body":43,"breadcrumbs":3,"title":2},"365":{"body":0,"breadcrumbs":3,"title":2},"366":{"body":20,"breadcrumbs":3,"title":2},"367":{"body":18,"breadcrumbs":3,"title":2},"368":{"body":24,"breadcrumbs":3,"title":2},"369":{"body":19,"breadcrumbs":3,"title":2},"37":{"body":59,"breadcrumbs":5,"title":2},"370":{"body":0,"breadcrumbs":3,"title":2},"371":{"body":12,"breadcrumbs":6,"title":5},"372":{"body":11,"breadcrumbs":5,"title":4},"373":{"body":12,"breadcrumbs":6,"title":5},"374":{"body":16,"breadcrumbs":4,"title":3},"375":{"body":22,"breadcrumbs":6,"title":5},"376":{"body":16,"breadcrumbs":3,"title":2},"377":{"body":36,"breadcrumbs":3,"title":2},"378":{"body":16,"breadcrumbs":2,"title":1},"379":{"body":40,"breadcrumbs":2,"title":1},"38":{"body":26,"breadcrumbs":4,"title":1},"380":{"body":30,"breadcrumbs":3,"title":2},"381":{"body":21,"breadcrumbs":2,"title":1},"382":{"body":33,"breadcrumbs":4,"title":3},"383":{"body":91,"breadcrumbs":3,"title":2},"384":{"body":27,"breadcrumbs":2,"title":1},"385":{"body":22,"breadcrumbs":2,"title":1},"386":{"body":29,"breadcrumbs":3,"title":2},"387":{"body":59,"breadcrumbs":4,"title":3},"388":{"body":37,"breadcrumbs":4,"title":3},"389":{"body":129,"breadcrumbs":6,"title":5},"39":{"body":46,"breadcrumbs":5,"title":2},"390":{"body":44,"breadcrumbs":3,"title":2},"391":{"body":35,"breadcrumbs":4,"title":3},"392":{"body":29,"breadcrumbs":3,"title":2},"393":{"body":20,"breadcrumbs":2,"title":1},"394":{"body":63,"breadcrumbs":2,"title":1},"395":{"body":15,"breadcrumbs":3,"title":2},"396":{"body":25,"breadcrumbs":2,"title":1},"397":{"body":36,"breadcrumbs":4,"title":3},"398":{"body":94,"breadcrumbs":3,"title":2},"399":{"body":14,"breadcrumbs":4,"title":3},"4":{"body":11,"breadcrumbs":2,"title":1},"40":{"body":34,"breadcrumbs":6,"title":3},"400":{"body":25,"breadcrumbs":4,"title":3},"401":{"body":25,"breadcrumbs":4,"title":3},"402":{"body":24,"breadcrumbs":4,"title":3},"403":{"body":20,"breadcrumbs":4,"title":3},"404":{"body":9,"breadcrumbs":4,"title":3},"405":{"body":7,"breadcrumbs":3,"title":2},"406":{"body":9,"breadcrumbs":3,"title":2},"407":{"body":74,"breadcrumbs":4,"title":3},"408":{"body":13,"breadcrumbs":3,"title":2},"409":{"body":20,"breadcrumbs":4,"title":3},"41":{"body":31,"breadcrumbs":5,"title":2},"410":{"body":22,"breadcrumbs":3,"title":2},"411":{"body":56,"breadcrumbs":4,"title":3},"412":{"body":32,"breadcrumbs":3,"title":2},"413":{"body":148,"breadcrumbs":6,"title":5},"414":{"body":70,"breadcrumbs":3,"title":2},"415":{"body":40,"breadcrumbs":3,"title":2},"416":{"body":29,"breadcrumbs":2,"title":1},"417":{"body":18,"breadcrumbs":2,"title":1},"418":{"body":38,"breadcrumbs":2,"title":1},"419":{"body":16,"breadcrumbs":3,"title":2},"42":{"body":17,"breadcrumbs":6,"title":3},"420":{"body":47,"breadcrumbs":3,"title":2},"421":{"body":42,"breadcrumbs":3,"title":2},"422":{"body":84,"breadcrumbs":3,"title":2},"423":{"body":29,"breadcrumbs":4,"title":3},"424":{"body":47,"breadcrumbs":4,"title":3},"425":{"body":28,"breadcrumbs":3,"title":2},"426":{"body":10,"breadcrumbs":2,"title":1},"427":{"body":25,"breadcrumbs":2,"title":1},"428":{"body":12,"breadcrumbs":3,"title":2},"429":{"body":54,"breadcrumbs":3,"title":2},"43":{"body":49,"breadcrumbs":4,"title":1},"430":{"body":37,"breadcrumbs":3,"title":2},"431":{"body":53,"breadcrumbs":3,"title":2},"432":{"body":21,"breadcrumbs":3,"title":2},"433":{"body":15,"breadcrumbs":3,"title":2},"434":{"body":9,"breadcrumbs":2,"title":1},"435":{"body":9,"breadcrumbs":2,"title":1},"436":{"body":32,"breadcrumbs":3,"title":2},"437":{"body":45,"breadcrumbs":3,"title":2},"438":{"body":54,"breadcrumbs":3,"title":2},"439":{"body":54,"breadcrumbs":3,"title":2},"44":{"body":33,"breadcrumbs":5,"title":2},"440":{"body":21,"breadcrumbs":3,"title":2},"441":{"body":16,"breadcrumbs":3,"title":2},"442":{"body":16,"breadcrumbs":2,"title":1},"443":{"body":16,"breadcrumbs":2,"title":1},"444":{"body":15,"breadcrumbs":3,"title":2},"445":{"body":33,"breadcrumbs":3,"title":2},"446":{"body":60,"breadcrumbs":4,"title":3},"447":{"body":62,"breadcrumbs":4,"title":3},"448":{"body":53,"breadcrumbs":8,"title":7},"449":{"body":19,"breadcrumbs":3,"title":2},"45":{"body":33,"breadcrumbs":5,"title":2},"450":{"body":12,"breadcrumbs":2,"title":1},"451":{"body":7,"breadcrumbs":2,"title":1},"452":{"body":7,"breadcrumbs":3,"title":2},"453":{"body":19,"breadcrumbs":3,"title":2},"454":{"body":57,"breadcrumbs":4,"title":3},"455":{"body":44,"breadcrumbs":4,"title":3},"456":{"body":20,"breadcrumbs":3,"title":2},"457":{"body":24,"breadcrumbs":3,"title":2},"458":{"body":24,"breadcrumbs":3,"title":2},"459":{"body":10,"breadcrumbs":3,"title":2},"46":{"body":12,"breadcrumbs":4,"title":1},"460":{"body":21,"breadcrumbs":2,"title":1},"461":{"body":6,"breadcrumbs":3,"title":2},"462":{"body":8,"breadcrumbs":3,"title":2},"463":{"body":6,"breadcrumbs":3,"title":2},"464":{"body":29,"breadcrumbs":3,"title":2},"465":{"body":22,"breadcrumbs":3,"title":2},"466":{"body":45,"breadcrumbs":3,"title":2},"467":{"body":25,"breadcrumbs":3,"title":2},"468":{"body":55,"breadcrumbs":3,"title":2},"469":{"body":19,"breadcrumbs":3,"title":2},"47":{"body":21,"breadcrumbs":5,"title":2},"470":{"body":29,"breadcrumbs":3,"title":2},"471":{"body":28,"breadcrumbs":4,"title":2},"472":{"body":26,"breadcrumbs":3,"title":1},"473":{"body":48,"breadcrumbs":3,"title":1},"474":{"body":0,"breadcrumbs":3,"title":1},"475":{"body":4,"breadcrumbs":4,"title":2},"476":{"body":4,"breadcrumbs":4,"title":2},"477":{"body":13,"breadcrumbs":4,"title":2},"478":{"body":2,"breadcrumbs":4,"title":2},"479":{"body":4,"breadcrumbs":3,"title":1},"48":{"body":16,"breadcrumbs":6,"title":3},"480":{"body":3,"breadcrumbs":4,"title":2},"481":{"body":2,"breadcrumbs":4,"title":2},"482":{"body":0,"breadcrumbs":4,"title":2},"483":{"body":23,"breadcrumbs":3,"title":1},"484":{"body":10,"breadcrumbs":3,"title":1},"485":{"body":15,"breadcrumbs":3,"title":1},"486":{"body":4,"breadcrumbs":4,"title":2},"487":{"body":4,"breadcrumbs":3,"title":1},"488":{"body":4,"breadcrumbs":4,"title":2},"489":{"body":0,"breadcrumbs":4,"title":2},"49":{"body":15,"breadcrumbs":7,"title":4},"490":{"body":19,"breadcrumbs":2,"title":0},"491":{"body":18,"breadcrumbs":2,"title":0},"492":{"body":27,"breadcrumbs":4,"title":2},"493":{"body":0,"breadcrumbs":4,"title":2},"494":{"body":8,"breadcrumbs":2,"title":0},"495":{"body":7,"breadcrumbs":3,"title":1},"496":{"body":0,"breadcrumbs":4,"title":2},"497":{"body":7,"breadcrumbs":5,"title":3},"498":{"body":6,"breadcrumbs":4,"title":2},"499":{"body":16,"breadcrumbs":4,"title":2},"5":{"body":8,"breadcrumbs":2,"title":1},"50":{"body":11,"breadcrumbs":6,"title":3},"500":{"body":11,"breadcrumbs":3,"title":1},"501":{"body":26,"breadcrumbs":5,"title":3},"502":{"body":5,"breadcrumbs":3,"title":1},"503":{"body":52,"breadcrumbs":4,"title":2},"504":{"body":50,"breadcrumbs":4,"title":2},"505":{"body":23,"breadcrumbs":4,"title":2},"506":{"body":0,"breadcrumbs":4,"title":2},"507":{"body":29,"breadcrumbs":5,"title":3},"508":{"body":21,"breadcrumbs":5,"title":3},"509":{"body":22,"breadcrumbs":5,"title":3},"51":{"body":13,"breadcrumbs":6,"title":3},"510":{"body":0,"breadcrumbs":4,"title":2},"511":{"body":29,"breadcrumbs":4,"title":2},"512":{"body":27,"breadcrumbs":4,"title":2},"513":{"body":24,"breadcrumbs":4,"title":2},"514":{"body":0,"breadcrumbs":4,"title":2},"515":{"body":6,"breadcrumbs":4,"title":2},"516":{"body":14,"breadcrumbs":4,"title":2},"517":{"body":36,"breadcrumbs":6,"title":4},"518":{"body":14,"breadcrumbs":4,"title":2},"519":{"body":45,"breadcrumbs":4,"title":2},"52":{"body":24,"breadcrumbs":5,"title":2},"520":{"body":48,"breadcrumbs":4,"title":2},"521":{"body":0,"breadcrumbs":4,"title":2},"522":{"body":10,"breadcrumbs":6,"title":4},"523":{"body":24,"breadcrumbs":6,"title":4},"524":{"body":29,"breadcrumbs":6,"title":4},"525":{"body":10,"breadcrumbs":5,"title":3},"526":{"body":13,"breadcrumbs":5,"title":3},"527":{"body":21,"breadcrumbs":4,"title":2},"528":{"body":34,"breadcrumbs":4,"title":2},"529":{"body":18,"breadcrumbs":3,"title":1},"53":{"body":18,"breadcrumbs":5,"title":2},"530":{"body":78,"breadcrumbs":5,"title":3},"531":{"body":4,"breadcrumbs":3,"title":1},"532":{"body":4,"breadcrumbs":3,"title":1},"533":{"body":8,"breadcrumbs":3,"title":1},"534":{"body":4,"breadcrumbs":3,"title":1},"535":{"body":14,"breadcrumbs":4,"title":2},"536":{"body":9,"breadcrumbs":3,"title":1},"537":{"body":7,"breadcrumbs":3,"title":1},"538":{"body":11,"breadcrumbs":3,"title":1},"539":{"body":13,"breadcrumbs":4,"title":2},"54":{"body":29,"breadcrumbs":5,"title":2},"540":{"body":11,"breadcrumbs":4,"title":2},"541":{"body":7,"breadcrumbs":3,"title":1},"542":{"body":16,"breadcrumbs":3,"title":1},"543":{"body":10,"breadcrumbs":4,"title":2},"544":{"body":16,"breadcrumbs":3,"title":1},"545":{"body":18,"breadcrumbs":3,"title":1},"546":{"body":11,"breadcrumbs":4,"title":2},"547":{"body":3,"breadcrumbs":3,"title":1},"548":{"body":3,"breadcrumbs":3,"title":1},"549":{"body":8,"breadcrumbs":3,"title":1},"55":{"body":49,"breadcrumbs":5,"title":2},"550":{"body":11,"breadcrumbs":4,"title":2},"551":{"body":5,"breadcrumbs":3,"title":1},"552":{"body":12,"breadcrumbs":3,"title":1},"553":{"body":23,"breadcrumbs":3,"title":1},"554":{"body":19,"breadcrumbs":3,"title":1},"555":{"body":11,"breadcrumbs":4,"title":2},"556":{"body":4,"breadcrumbs":3,"title":1},"557":{"body":11,"breadcrumbs":3,"title":1},"558":{"body":15,"breadcrumbs":3,"title":1},"559":{"body":10,"breadcrumbs":3,"title":1},"56":{"body":42,"breadcrumbs":6,"title":3},"560":{"body":17,"breadcrumbs":3,"title":1},"561":{"body":9,"breadcrumbs":4,"title":2},"562":{"body":5,"breadcrumbs":3,"title":1},"563":{"body":11,"breadcrumbs":3,"title":1},"564":{"body":16,"breadcrumbs":3,"title":1},"565":{"body":22,"breadcrumbs":3,"title":1},"566":{"body":10,"breadcrumbs":3,"title":1},"567":{"body":10,"breadcrumbs":4,"title":2},"568":{"body":5,"breadcrumbs":3,"title":1},"569":{"body":12,"breadcrumbs":3,"title":1},"57":{"body":56,"breadcrumbs":5,"title":2},"570":{"body":31,"breadcrumbs":3,"title":1},"571":{"body":12,"breadcrumbs":3,"title":1},"572":{"body":15,"breadcrumbs":4,"title":2},"573":{"body":3,"breadcrumbs":3,"title":1},"574":{"body":3,"breadcrumbs":3,"title":1},"575":{"body":29,"breadcrumbs":3,"title":1},"576":{"body":14,"breadcrumbs":4,"title":2},"577":{"body":10,"breadcrumbs":3,"title":1},"578":{"body":15,"breadcrumbs":4,"title":2},"579":{"body":4,"breadcrumbs":3,"title":1},"58":{"body":32,"breadcrumbs":5,"title":2},"580":{"body":6,"breadcrumbs":3,"title":1},"581":{"body":28,"breadcrumbs":3,"title":1},"582":{"body":12,"breadcrumbs":3,"title":1},"583":{"body":12,"breadcrumbs":4,"title":2},"584":{"body":6,"breadcrumbs":4,"title":2},"585":{"body":11,"breadcrumbs":3,"title":1},"586":{"body":27,"breadcrumbs":4,"title":2},"587":{"body":58,"breadcrumbs":3,"title":1},"588":{"body":14,"breadcrumbs":3,"title":1},"589":{"body":31,"breadcrumbs":5,"title":3},"59":{"body":17,"breadcrumbs":4,"title":2},"590":{"body":12,"breadcrumbs":4,"title":2},"591":{"body":4,"breadcrumbs":3,"title":1},"592":{"body":18,"breadcrumbs":3,"title":1},"593":{"body":88,"breadcrumbs":3,"title":1},"594":{"body":22,"breadcrumbs":3,"title":1},"595":{"body":17,"breadcrumbs":3,"title":1},"596":{"body":10,"breadcrumbs":4,"title":2},"597":{"body":29,"breadcrumbs":4,"title":2},"598":{"body":25,"breadcrumbs":4,"title":2},"599":{"body":63,"breadcrumbs":4,"title":2},"6":{"body":25,"breadcrumbs":3,"title":2},"60":{"body":66,"breadcrumbs":5,"title":3},"600":{"body":22,"breadcrumbs":4,"title":2},"601":{"body":26,"breadcrumbs":4,"title":2},"602":{"body":22,"breadcrumbs":4,"title":2},"603":{"body":44,"breadcrumbs":4,"title":2},"604":{"body":0,"breadcrumbs":4,"title":2},"605":{"body":66,"breadcrumbs":4,"title":2},"606":{"body":41,"breadcrumbs":3,"title":1},"607":{"body":58,"breadcrumbs":4,"title":2},"608":{"body":34,"breadcrumbs":3,"title":1},"609":{"body":77,"breadcrumbs":5,"title":3},"61":{"body":63,"breadcrumbs":4,"title":2},"610":{"body":22,"breadcrumbs":3,"title":1},"611":{"body":51,"breadcrumbs":5,"title":3},"612":{"body":34,"breadcrumbs":3,"title":1},"613":{"body":60,"breadcrumbs":4,"title":2},"614":{"body":28,"breadcrumbs":3,"title":1},"615":{"body":33,"breadcrumbs":4,"title":2},"616":{"body":12,"breadcrumbs":3,"title":1},"617":{"body":40,"breadcrumbs":4,"title":2},"618":{"body":33,"breadcrumbs":4,"title":2},"619":{"body":14,"breadcrumbs":3,"title":1},"62":{"body":43,"breadcrumbs":5,"title":3},"620":{"body":24,"breadcrumbs":5,"title":3},"621":{"body":61,"breadcrumbs":4,"title":2},"622":{"body":15,"breadcrumbs":3,"title":1},"623":{"body":34,"breadcrumbs":5,"title":3},"624":{"body":8,"breadcrumbs":3,"title":1},"625":{"body":33,"breadcrumbs":5,"title":3},"626":{"body":0,"breadcrumbs":5,"title":3},"627":{"body":39,"breadcrumbs":4,"title":2},"628":{"body":25,"breadcrumbs":4,"title":2},"629":{"body":31,"breadcrumbs":4,"title":2},"63":{"body":29,"breadcrumbs":4,"title":2},"630":{"body":82,"breadcrumbs":4,"title":2},"631":{"body":25,"breadcrumbs":4,"title":2},"632":{"body":19,"breadcrumbs":4,"title":2},"633":{"body":0,"breadcrumbs":5,"title":3},"634":{"body":37,"breadcrumbs":5,"title":3},"635":{"body":23,"breadcrumbs":5,"title":3},"636":{"body":42,"breadcrumbs":5,"title":3},"637":{"body":40,"breadcrumbs":5,"title":3},"638":{"body":0,"breadcrumbs":5,"title":3},"639":{"body":54,"breadcrumbs":5,"title":3},"64":{"body":40,"breadcrumbs":4,"title":2},"640":{"body":42,"breadcrumbs":6,"title":4},"641":{"body":27,"breadcrumbs":5,"title":3},"642":{"body":0,"breadcrumbs":4,"title":2},"643":{"body":35,"breadcrumbs":4,"title":2},"644":{"body":29,"breadcrumbs":5,"title":3},"645":{"body":45,"breadcrumbs":4,"title":2},"646":{"body":0,"breadcrumbs":4,"title":2},"647":{"body":46,"breadcrumbs":5,"title":3},"648":{"body":34,"breadcrumbs":4,"title":2},"649":{"body":0,"breadcrumbs":5,"title":3},"65":{"body":39,"breadcrumbs":4,"title":2},"650":{"body":25,"breadcrumbs":4,"title":2},"651":{"body":40,"breadcrumbs":5,"title":3},"652":{"body":0,"breadcrumbs":5,"title":3},"653":{"body":22,"breadcrumbs":5,"title":3},"654":{"body":25,"breadcrumbs":5,"title":3},"655":{"body":57,"breadcrumbs":5,"title":3},"656":{"body":19,"breadcrumbs":4,"title":2},"657":{"body":21,"breadcrumbs":6,"title":3},"658":{"body":29,"breadcrumbs":5,"title":2},"659":{"body":57,"breadcrumbs":5,"title":2},"66":{"body":24,"breadcrumbs":4,"title":2},"660":{"body":0,"breadcrumbs":5,"title":2},"661":{"body":43,"breadcrumbs":5,"title":2},"662":{"body":15,"breadcrumbs":7,"title":4},"663":{"body":23,"breadcrumbs":4,"title":1},"664":{"body":34,"breadcrumbs":5,"title":2},"665":{"body":29,"breadcrumbs":4,"title":1},"666":{"body":15,"breadcrumbs":5,"title":2},"667":{"body":12,"breadcrumbs":4,"title":2},"668":{"body":32,"breadcrumbs":4,"title":2},"669":{"body":8,"breadcrumbs":4,"title":2},"67":{"body":21,"breadcrumbs":4,"title":2},"670":{"body":22,"breadcrumbs":4,"title":2},"671":{"body":29,"breadcrumbs":3,"title":1},"672":{"body":54,"breadcrumbs":4,"title":2},"673":{"body":0,"breadcrumbs":4,"title":2},"674":{"body":34,"breadcrumbs":5,"title":3},"675":{"body":20,"breadcrumbs":5,"title":3},"676":{"body":16,"breadcrumbs":4,"title":2},"677":{"body":17,"breadcrumbs":4,"title":2},"678":{"body":38,"breadcrumbs":4,"title":2},"679":{"body":20,"breadcrumbs":4,"title":2},"68":{"body":33,"breadcrumbs":4,"title":2},"680":{"body":31,"breadcrumbs":5,"title":3},"681":{"body":30,"breadcrumbs":5,"title":3},"682":{"body":13,"breadcrumbs":4,"title":2},"683":{"body":16,"breadcrumbs":4,"title":2},"684":{"body":0,"breadcrumbs":4,"title":2},"685":{"body":21,"breadcrumbs":3,"title":1},"686":{"body":19,"breadcrumbs":3,"title":1},"687":{"body":18,"breadcrumbs":5,"title":3},"688":{"body":26,"breadcrumbs":4,"title":2},"689":{"body":0,"breadcrumbs":4,"title":2},"69":{"body":28,"breadcrumbs":4,"title":2},"690":{"body":35,"breadcrumbs":5,"title":3},"691":{"body":32,"breadcrumbs":6,"title":4},"692":{"body":21,"breadcrumbs":4,"title":2},"693":{"body":0,"breadcrumbs":4,"title":2},"694":{"body":28,"breadcrumbs":7,"title":5},"695":{"body":27,"breadcrumbs":5,"title":3},"696":{"body":45,"breadcrumbs":5,"title":3},"697":{"body":0,"breadcrumbs":5,"title":3},"698":{"body":12,"breadcrumbs":5,"title":3},"699":{"body":27,"breadcrumbs":5,"title":3},"7":{"body":25,"breadcrumbs":3,"title":2},"70":{"body":81,"breadcrumbs":4,"title":2},"700":{"body":17,"breadcrumbs":6,"title":4},"701":{"body":0,"breadcrumbs":4,"title":2},"702":{"body":17,"breadcrumbs":5,"title":3},"703":{"body":31,"breadcrumbs":7,"title":5},"704":{"body":15,"breadcrumbs":5,"title":3},"705":{"body":0,"breadcrumbs":4,"title":2},"706":{"body":22,"breadcrumbs":7,"title":5},"707":{"body":41,"breadcrumbs":5,"title":3},"708":{"body":0,"breadcrumbs":4,"title":2},"709":{"body":22,"breadcrumbs":5,"title":3},"71":{"body":59,"breadcrumbs":4,"title":2},"710":{"body":22,"breadcrumbs":5,"title":3},"711":{"body":67,"breadcrumbs":4,"title":2},"712":{"body":13,"breadcrumbs":4,"title":2},"713":{"body":16,"breadcrumbs":6,"title":3},"714":{"body":43,"breadcrumbs":5,"title":2},"715":{"body":0,"breadcrumbs":5,"title":2},"716":{"body":32,"breadcrumbs":4,"title":1},"717":{"body":24,"breadcrumbs":4,"title":1},"718":{"body":43,"breadcrumbs":4,"title":1},"719":{"body":0,"breadcrumbs":4,"title":1},"72":{"body":38,"breadcrumbs":5,"title":3},"720":{"body":122,"breadcrumbs":4,"title":1},"721":{"body":66,"breadcrumbs":4,"title":1},"722":{"body":197,"breadcrumbs":4,"title":1},"723":{"body":35,"breadcrumbs":4,"title":1},"724":{"body":79,"breadcrumbs":4,"title":1},"725":{"body":167,"breadcrumbs":4,"title":1},"726":{"body":100,"breadcrumbs":4,"title":1},"727":{"body":27,"breadcrumbs":4,"title":1},"728":{"body":47,"breadcrumbs":5,"title":2},"729":{"body":13,"breadcrumbs":5,"title":2},"73":{"body":59,"breadcrumbs":4,"title":2},"730":{"body":17,"breadcrumbs":4,"title":2},"731":{"body":52,"breadcrumbs":3,"title":1},"732":{"body":104,"breadcrumbs":3,"title":1},"733":{"body":0,"breadcrumbs":3,"title":1},"734":{"body":15,"breadcrumbs":4,"title":2},"735":{"body":48,"breadcrumbs":4,"title":2},"736":{"body":21,"breadcrumbs":4,"title":2},"737":{"body":26,"breadcrumbs":4,"title":2},"738":{"body":33,"breadcrumbs":6,"title":4},"739":{"body":54,"breadcrumbs":3,"title":1},"74":{"body":17,"breadcrumbs":4,"title":2},"740":{"body":54,"breadcrumbs":4,"title":2},"741":{"body":15,"breadcrumbs":4,"title":2},"742":{"body":20,"breadcrumbs":4,"title":2},"743":{"body":17,"breadcrumbs":4,"title":2},"744":{"body":48,"breadcrumbs":3,"title":1},"745":{"body":36,"breadcrumbs":5,"title":3},"746":{"body":156,"breadcrumbs":5,"title":3},"747":{"body":78,"breadcrumbs":4,"title":2},"748":{"body":62,"breadcrumbs":4,"title":2},"749":{"body":74,"breadcrumbs":4,"title":2},"75":{"body":40,"breadcrumbs":5,"title":3},"750":{"body":50,"breadcrumbs":4,"title":2},"751":{"body":16,"breadcrumbs":4,"title":2},"752":{"body":21,"breadcrumbs":6,"title":3},"753":{"body":105,"breadcrumbs":4,"title":1},"754":{"body":170,"breadcrumbs":4,"title":1},"755":{"body":0,"breadcrumbs":5,"title":2},"756":{"body":63,"breadcrumbs":5,"title":2},"757":{"body":39,"breadcrumbs":5,"title":2},"758":{"body":52,"breadcrumbs":5,"title":2},"759":{"body":34,"breadcrumbs":5,"title":2},"76":{"body":19,"breadcrumbs":4,"title":2},"760":{"body":167,"breadcrumbs":4,"title":1},"761":{"body":38,"breadcrumbs":5,"title":2},"762":{"body":147,"breadcrumbs":8,"title":5},"763":{"body":59,"breadcrumbs":5,"title":2},"764":{"body":23,"breadcrumbs":5,"title":2},"77":{"body":24,"breadcrumbs":4,"title":2},"78":{"body":46,"breadcrumbs":4,"title":2},"79":{"body":16,"breadcrumbs":4,"title":2},"8":{"body":23,"breadcrumbs":3,"title":2},"80":{"body":20,"breadcrumbs":5,"title":3},"81":{"body":7,"breadcrumbs":4,"title":2},"82":{"body":18,"breadcrumbs":4,"title":2},"83":{"body":42,"breadcrumbs":5,"title":3},"84":{"body":55,"breadcrumbs":4,"title":2},"85":{"body":65,"breadcrumbs":5,"title":3},"86":{"body":22,"breadcrumbs":4,"title":2},"87":{"body":73,"breadcrumbs":5,"title":3},"88":{"body":28,"breadcrumbs":4,"title":2},"89":{"body":26,"breadcrumbs":4,"title":2},"9":{"body":27,"breadcrumbs":4,"title":2},"90":{"body":30,"breadcrumbs":4,"title":2},"91":{"body":50,"breadcrumbs":5,"title":3},"92":{"body":54,"breadcrumbs":3,"title":1},"93":{"body":38,"breadcrumbs":3,"title":1},"94":{"body":32,"breadcrumbs":4,"title":2},"95":{"body":28,"breadcrumbs":4,"title":2},"96":{"body":129,"breadcrumbs":5,"title":3},"97":{"body":0,"breadcrumbs":4,"title":2},"98":{"body":28,"breadcrumbs":4,"title":2},"99":{"body":27,"breadcrumbs":4,"title":2}},"docs":{"0":{"body":"Create rich narrative simulations through code that reads like stories. Welcome to the complete guide for the Storybook narrative simulation language! Whether you're a creative writer bringing characters to life or a developer building simulation systems, this documentation will help you master Storybook. ⚠️ Alpha Software Notice Storybook is currently in alpha and under active development at r3t Studios . While the core language features are stable and ready to use, you should expect: New features to be added as we expand the language capabilities Minor syntax adjustments as we refine the design based on real-world usage API changes in the compiled output format as we optimize for game engine integration We're committed to a thoughtful path toward version 1.0. Breaking changes will be clearly documented, and we'll provide migration guides when syntax evolves. Your feedback during this alpha period is invaluable in shaping the language's future!","breadcrumbs":"Introduction » Storybook Language Guide","id":"0","title":"Storybook Language Guide"},"1":{"body":"Storybook is a compiled simulation language designed for open-world, autonomous game simulations . While it includes a basic embedded virtual machine for terminal-based debugging, it's built to be integrated into game engines and developed hand-in-hand with technical game developers. Storybook defines characters, behaviors, relationships, and narrative events for autonomous agents in dynamic worlds. It bridges the gap between storytelling and technical simulation through: Readable syntax - Code that looks like natural descriptions, but compiles to efficient bytecode Named nodes - Behavior trees you can read as stories, that drive AI decision-making Prose blocks - Embed narrative directly in definitions for context-aware storytelling Rich semantics - From simple traits to complex state machines and schedules Game engine integration - Designed to power autonomous NPCs in Unity, Unreal, Godot, and custom engines","breadcrumbs":"Introduction » What is Storybook?","id":"1","title":"What is Storybook?"},"10":{"body":"In this tutorial, we follow Martha and her bakery family, using their daily lives to learn each concept: Creating Characters - Define Martha with traits and descriptions Your First Behavior Tree - Give characters decision-making abilities Making Characters Act - Actions, conditions, and decorators Advanced Behaviors - Subtrees, parameters, and complex patterns Character Relationships - Model how characters interact Schedules and Time - Give characters daily routines Life Arcs - Track character development over time","breadcrumbs":"Welcome to Storybook » What You Will Learn","id":"10","title":"What You Will Learn"},"100":{"body":"States form a loop (day/night, seasons, mood swings): life_arc DayNightCycle { state dawn { on hour >= 8 -> day } state day { on hour >= 18 -> dusk } state dusk { on hour >= 20 -> night } state night { on hour >= 6 -> dawn }\n}","breadcrumbs":"Life Arcs » Cyclic States","id":"100","title":"Cyclic States"},"101":{"body":"Order transitions by urgency : Put the most critical conditions first, since the first true transition wins. Use descriptive state names : waiting_for_customer is clearer than state1. Add narrative prose blocks : They make life arcs readable as stories and serve as documentation. Avoid orphan states : Every state should be reachable from some other state (the compiler will warn you about unreachable states).","breadcrumbs":"Life Arcs » Tips","id":"101","title":"Tips"},"102":{"body":"Congratulations! You have completed the tutorial. You now know how to: Create characters with species, templates, and enums Build behavior trees with selectors, sequences, and decorators Add conditions and action parameters Model relationships with perspectives Define time-based schedules Track character development with life arcs","breadcrumbs":"Life Arcs » What You Have Learned","id":"102","title":"What You Have Learned"},"103":{"body":"Reference Guide : Complete syntax specifications Design Patterns : Common patterns and best practices Examples Gallery : Full working examples to learn from Reference : For complete life arc syntax, see the Life Arcs Reference .","breadcrumbs":"Life Arcs » Where to Go Next","id":"103","title":"Where to Go Next"},"104":{"body":"So far you have created characters, given them behaviors, connected them with relationships, scheduled their days, and guided them through life arcs. But characters need places to be and organizations to belong to . That is what locations and institutions provide.","breadcrumbs":"Locations and Institutions » Locations and Institutions","id":"104","title":"Locations and Institutions"},"105":{"body":"A location is a place in your world. It can be a building, a room, a park, a city -- any space where things happen. Locations hold fields that describe the place and optional prose blocks for narrative detail.","breadcrumbs":"Locations and Institutions » What Are Locations?","id":"105","title":"What Are Locations?"},"106":{"body":"Let's create the bakery where Martha works: location BakersBakery { type: bakery address: \"14 Main Street\" capacity: 30\n} That is all it takes. The location keyword, a name, and a block of fields. Every field is a key-value pair, and you choose whatever fields make sense for your world.","breadcrumbs":"Locations and Institutions » Your First Location","id":"106","title":"Your First Location"},"107":{"body":"A real location needs more than three fields. Let's flesh out the bakery: location BakersBakery { type: bakery address: \"14 Main Street\" capacity: 30 employees: 4 specialty: \"artisan sourdough\" daily_output_loaves: 80..120 open: true established: \"2011\"\n} Notice daily_output_loaves: 80..120 -- that is a range. Each simulation run can pick a different number of loaves, adding natural variation.","breadcrumbs":"Locations and Institutions » Adding Detail","id":"107","title":"Adding Detail"},"108":{"body":"Bare fields are good for data, but locations also need narrative flavor. Use prose blocks: location BakersBakery { type: bakery address: \"14 Main Street\" capacity: 30 ---description A warm, inviting bakery on Main Street. The smell of fresh bread wafts out the door every morning at dawn. Martha has run the shop for fifteen years, and the locals consider it the heart of the neighborhood. ---\n} Prose blocks start with ---tag_name and end with ---. The tag name (description here) becomes the key. You can have as many prose blocks as you want: location BakersBakery { type: bakery ---description The bakery on Main Street... --- ---history Originally a hardware store, Martha converted the space in 2011... --- ---atmosphere Flour dust catches the light from tall windows... ---\n}","breadcrumbs":"Locations and Institutions » Prose Blocks","id":"108","title":"Prose Blocks"},"109":{"body":"Locations work best when they form a coherent world. Here is the Baker family's neighborhood: location BakersBakery { type: bakery address: \"14 Main Street\" capacity: 30 owner: Martha ---description Martha's artisan bakery. The stone oven was imported from France. ---\n} location BakerHome { type: residence address: \"22 Elm Lane\" bedrooms: 4 has_garden: true ---description The Baker family home. Martha insisted on an oversized kitchen. ---\n} location BakersGuildHall { type: guild_hall address: \"7 Guild Row\" capacity: 100 established: \"1892\" ---description The historic headquarters of the Bakers Guild. ---\n} location TownSquare { type: public_square capacity: 500 has_fountain: true has_market_stalls: true ---description The central gathering place. On weekends, the farmers market fills the square with produce stalls. ---\n}","breadcrumbs":"Locations and Institutions » Building a World with Locations","id":"109","title":"Building a World with Locations"},"11":{"body":"Storybook is a domain-specific language (DSL) for narrative simulation. It lets you describe: Who characters are (traits, backstory, species) What they do (behavior trees with decision logic) How they relate to others (relationships with perspectives) When they act (schedules and time-based routines) How they change (life arcs and state machines) All of this in syntax designed to be readable and expressive.","breadcrumbs":"Welcome to Storybook » What is Storybook?","id":"11","title":"What is Storybook?"},"110":{"body":"Storybook does not enforce a built-in parent-child relationship for locations. Instead, you use fields to express hierarchy: location MainStreet { type: street district: TownCenter shops: 12\n} location BakersBakery { type: bakery street: MainStreet district: TownCenter\n} This convention-based approach keeps the language simple while letting you model whatever spatial relationships your world needs.","breadcrumbs":"Locations and Institutions » Modeling Hierarchy","id":"110","title":"Modeling Hierarchy"},"111":{"body":"An institution is an organization, group, or system. Think of it as a character that represents a collective: a guild, a government, a school, a business. Institutions have a key capability that locations lack -- they can use behaviors and schedules , just like characters.","breadcrumbs":"Locations and Institutions » What Are Institutions?","id":"111","title":"What Are Institutions?"},"112":{"body":"institution BakersGuild { type: trade_guild members: 50 founded: \"1892\" reputation: 0.85\n} This looks just like a location so far. The difference comes when you add behaviors.","breadcrumbs":"Locations and Institutions » Your First Institution","id":"112","title":"Your First Institution"},"113":{"body":"Institutions can act. The uses behaviors clause links behavior trees to the institution: institution BakersGuild { type: trade_guild members: 50 reputation: 0.85 uses behaviors: [ { tree: ManageApprentices }, { tree: NegotiateSuppliers }, { tree: HostEvents } ]\n} Each entry in the list is a behavior link object with a tree field. This tells the simulation engine that the Bakers Guild can manage apprentices, negotiate with suppliers, and host events.","breadcrumbs":"Locations and Institutions » Institutions with Behaviors","id":"113","title":"Institutions with Behaviors"},"114":{"body":"Not all behaviors are equally important. Use the priority field: institution BakersGuild { type: trade_guild uses behaviors: [ { tree: ManageApprentices, priority: normal }, { tree: NegotiateSuppliers, priority: high }, { tree: HostEvents, priority: low } ]\n} Priority levels are low, normal, high, and critical. Higher-priority behaviors take precedence when the institution must choose between actions.","breadcrumbs":"Locations and Institutions » Behavior Priorities","id":"114","title":"Behavior Priorities"},"115":{"body":"Some behaviors only activate under certain conditions: institution BakersGuild { type: trade_guild reputation: 0.85 uses behaviors: [ { tree: ManageApprentices }, { tree: NegotiateSuppliers, priority: high }, { tree: EmergencyMeeting, when: reputation < 0.3, priority: critical } ]\n} The when clause uses an expression . Here, the emergency meeting behavior only activates when reputation drops below 0.3.","breadcrumbs":"Locations and Institutions » Conditional Behaviors","id":"115","title":"Conditional Behaviors"},"116":{"body":"Institutions can also follow schedules: institution BakersGuild { type: trade_guild uses schedule: GuildOperatingHours\n} For multiple schedules: institution BakersGuild { type: trade_guild uses schedules: [WeekdaySchedule, WeekendSchedule]\n}","breadcrumbs":"Locations and Institutions » Institutions with Schedules","id":"116","title":"Institutions with Schedules"},"117":{"body":"Just like locations, institutions support prose blocks: institution BakersGuild { type: trade_guild members: 50 ---description The Bakers Guild has been the backbone of the town's bread trade since 1892. Members share recipes, arrange apprenticeships, and collectively negotiate flour prices. --- ---charter Article I: All members shall maintain the highest standards. Article II: Apprentices must complete a three-year program. ---\n}","breadcrumbs":"Locations and Institutions » Prose Blocks","id":"117","title":"Prose Blocks"},"118":{"body":"Institutions do not have a built-in membership list. You model membership through character fields or relationships.","breadcrumbs":"Locations and Institutions » Connecting Characters to Institutions","id":"118","title":"Connecting Characters to Institutions"},"119":{"body":"The simplest approach -- add fields to your characters: character Martha { age: 45 occupation: baker guild: BakersGuild guild_role: guild_master guild_member_since: \"2005\"\n} character Jane { age: 19 occupation: apprentice_baker guild: BakersGuild guild_role: apprentice guild_member_since: \"2024\"\n}","breadcrumbs":"Locations and Institutions » Through Character Fields","id":"119","title":"Through Character Fields"},"12":{"body":"Create a file called hello.sb and add this: character Martha { age: 34 skill_level: 0.95 ---description A master baker who runs the most popular bakery in town, known for her sourdough bread and apple pastries. ---\n} That is it. You have defined a character with two numeric fields and a prose description block. Let us break it down: character Martha declares a new character named Martha { ... } contains her attributes age: 34 is an integer field skill_level: 0.95 is a floating-point field (0.0 to 1.0) ---description ... --- is a prose block for narrative text","breadcrumbs":"Welcome to Storybook » Your First Storybook File","id":"12","title":"Your First Storybook File"},"120":{"body":"For richer modeling, use relationships: relationship GuildMembership { Martha as guild_master { years_active: 20 } BakersGuild as organization { } bond: 0.95\n} relationship Apprenticeship { Jane as apprentice { skills_learned: 12 } Martha as mentor { patience_remaining: 0.7 } BakersGuild as guild { } years_completed: 1\n} This approach captures richer information: roles, duration, and multi-party connections.","breadcrumbs":"Locations and Institutions » Through Relationships","id":"120","title":"Through Relationships"},"121":{"body":"When should you use each? Question Use... Where does something happen? Location Who or what organizes things? Institution Does it need behaviors? Institution Does it need a schedule? Institution Is it purely a place? Location Is it a group or organization? Institution Sometimes the same concept needs both: // The physical building\nlocation BakersGuildHall { type: guild_hall address: \"7 Guild Row\" capacity: 100\n} // The organization that meets there\ninstitution BakersGuild { type: trade_guild members: 50 location: BakersGuildHall uses behaviors: [ { tree: ManageApprentices }, { tree: NegotiateSuppliers } ] uses schedule: GuildOperatingHours\n} The guild hall is a place . The guild is an organization . Keeping them separate lets you say \"the guild meets at the guild hall\" without conflating the building with the institution.","breadcrumbs":"Locations and Institutions » Locations vs. Institutions","id":"121","title":"Locations vs. Institutions"},"122":{"body":"Here is a complete example showing how locations, institutions, and characters work together in the Baker family world: // Enums for type safety\nenum PlaceType { bakery, residence, guild_hall, public_square\n} enum GuildRole { guild_master, journeyman, apprentice\n} // Locations: where things happen\nlocation BakersBakery { type: bakery address: \"14 Main Street\" capacity: 30 owner: Martha ---description Martha's artisan bakery on Main Street. ---\n} location BakerHome { type: residence address: \"22 Elm Lane\" bedrooms: 4 residents: [\"Martha\", \"David\", \"Jane\", \"Tom\"]\n} location BakersGuildHall { type: guild_hall address: \"7 Guild Row\" capacity: 100 ---description The historic Bakers Guild headquarters, established 1892. ---\n} // Institution: the organization\ninstitution BakersGuild { type: trade_guild members: 50 founded: \"1892\" reputation: 0.85 location: BakersGuildHall leader: Martha uses behaviors: [ { tree: ManageApprentices, priority: normal }, { tree: NegotiateSuppliers, priority: high }, { tree: HostAnnualBakeOff, when: month is october } ] uses schedule: GuildOperatingHours ---description The Bakers Guild oversees apprenticeships, quality standards, and the annual Great Bake-Off competition. ---\n} // Institution: the business\ninstitution BakersBakeryBusiness { type: business owner: Martha employees: 4 location: BakersBakery uses behaviors: [ { tree: DailyBakingOps, priority: high }, { tree: InventoryManagement } ] uses schedule: BakeryOperatingHours\n} // Characters connected to all of the above\ncharacter Martha { age: 45 occupation: baker workplace: BakersBakery home: BakerHome guild: BakersGuild guild_role: guild_master\n} character Jane { age: 19 occupation: apprentice_baker workplace: BakersBakery home: BakerHome guild: BakersGuild guild_role: apprentice\n} // Relationships tying it all together\nrelationship GuildLeadership { Martha as guild_master { } BakersGuild as guild { } years_in_role: 8\n} relationship BakeryApprenticeship { Jane as apprentice { } Martha as mentor { } BakersGuild as certifying_body { } year: 1 total_years: 3\n}","breadcrumbs":"Locations and Institutions » Putting It All Together","id":"122","title":"Putting It All Together"},"123":{"body":"Locations are simple: name, fields, prose blocks. They model places . Institutions are richer: they add uses behaviors and uses schedule on top of fields and prose. They model organizations . Membership is modeled through character fields or relationships, not built into institution syntax. Separate place from organization : A guild hall (location) and the guild (institution) are different things. Use enums for type-safe categorization of locations and institutions.","breadcrumbs":"Locations and Institutions » Key Takeaways","id":"123","title":"Key Takeaways"},"124":{"body":"Learn about expressions used in conditional behavior links Explore behavior trees to create the behaviors your institutions use See schedules to define operating hours for institutions Read the full Locations Reference and Institutions Reference","breadcrumbs":"Locations and Institutions » Next Steps","id":"124","title":"Next Steps"},"125":{"body":"The Storybook language enables narrative simulation through structured declarations of characters, behaviors, relationships, and events.","breadcrumbs":"Language Overview » Language Overview","id":"125","title":"Language Overview"},"126":{"body":"Storybook is a domain-specific language for narrative simulation, influenced by: Rust : Strong typing, explicit declarations, and clear ownership semantics C# : Object-oriented patterns with declarative syntax Python : Readable, accessible syntax that prioritizes clarity The language balances technical precision with narrative expressiveness , making it accessible to storytellers while maintaining the rigor developers need.","breadcrumbs":"Language Overview » Philosophy","id":"126","title":"Philosophy"},"127":{"body":"","breadcrumbs":"Language Overview » Design Principles","id":"127","title":"Design Principles"},"128":{"body":"Named nodes and prose blocks let code read like stories: behavior Baker_MorningRoutine { choose daily_priority { then prepare_sourdough { ... } then serve_customers { ... } then restock_display { ... } }\n}","breadcrumbs":"Language Overview » 1. Code as Narrative","id":"128","title":"1. Code as Narrative"},"129":{"body":"Every declaration is self-documenting: Character fields show what defines them Behavior trees show decision structures Relationships name their participants","breadcrumbs":"Language Overview » 2. Explicit is Better Than Implicit","id":"129","title":"2. Explicit is Better Than Implicit"},"13":{"body":"","breadcrumbs":"Welcome to Storybook » Key Concepts","id":"13","title":"Key Concepts"},"130":{"body":"Simple cases are simple, complex cases are possible: Basic characters need just a name and fields Templates enable inheritance and reuse Advanced features (state machines, decorators) available when needed","breadcrumbs":"Language Overview » 3. Progressive Disclosure","id":"130","title":"3. Progressive Disclosure"},"131":{"body":"The compiler catches narrative errors: Bond values must be 0.0..1.0 Schedule blocks can't overlap Life arc transitions must reference valid states","breadcrumbs":"Language Overview » 4. Semantic Validation","id":"131","title":"4. Semantic Validation"},"132":{"body":"","breadcrumbs":"Language Overview » Language Structure","id":"132","title":"Language Structure"},"133":{"body":"Storybook has 10 top-level declaration types: Declaration Purpose Example character Define entities with traits and behaviors A baker with skills and schedule template Reusable patterns with ranges A generic NPC template behavior Decision trees for actions How a character responds to events life_arc State machines for life stages Apprentice → Baker → Master schedule Time-based activities Daily routine from 6am to 10pm relationship Connections between entities Parent-child with bond values institution Organizations and groups A bakery with employees location Places with properties The town square species Type definitions with traits Human vs Cat vs Rabbit enum Named value sets EmotionalState options","breadcrumbs":"Language Overview » Declaration Types","id":"133","title":"Declaration Types"},"134":{"body":"Fields can contain: Primitives : 42, 3.14, \"text\", true Time : 08:30:00, 14:15 Duration : 2h30m, 45s Ranges : 20..40 (for templates) Identifiers : OtherCharacter, path::to::Thing Lists : [1, 2, 3] Objects : { field: value } Prose blocks : ---tag\\nMulti-line\\ntext\\n---","breadcrumbs":"Language Overview » Value Types","id":"134","title":"Value Types"},"135":{"body":"Conditions and queries use: Comparisons : age > 18, energy <= 0.5 Equality : status is active, ready is true Logic : tired and hungry, rich or lucky, not ready Field access : self.health, other.bond Quantifiers : forall x in children: x.happy","breadcrumbs":"Language Overview » Expression Language","id":"135","title":"Expression Language"},"136":{"body":"","breadcrumbs":"Language Overview » Compilation Model","id":"136","title":"Compilation Model"},"137":{"body":".sb files → Parser → Abstract Syntax Tree → Resolver → SBIR Binary SBIR (Storybook Intermediate Representation) is a compact binary format that: Resolves all cross-file references Validates semantic constraints Optimizes for simulation runtime","breadcrumbs":"Language Overview » Source → AST → SBIR → Runtime","id":"137","title":"Source → AST → SBIR → Runtime"},"138":{"body":"Lexical : Valid tokens and syntax Syntactic : Correct grammar structure Semantic : Type checking, reference resolution Domain : Narrative constraints (bond ranges, schedule overlaps)","breadcrumbs":"Language Overview » Validation Layers","id":"138","title":"Validation Layers"},"139":{"body":"","breadcrumbs":"Language Overview » File Organization","id":"139","title":"File Organization"},"14":{"body":"Storybook files contain declarations -- named definitions of things in your world: character Martha { ... } // A person or creature\nbehavior BakeRoutine { ... } // Decision-making logic\nrelationship Family { ... } // A connection between entities\nschedule DailyRoutine { ... } // Time-based activities\nlife_arc Career { ... } // How someone changes over time","breadcrumbs":"Welcome to Storybook » Everything is a Declaration","id":"14","title":"Everything is a Declaration"},"140":{"body":"my-storybook/\n├── characters/\n│ ├── baker.sb\n│ └── family.sb\n├── behaviors/\n│ └── daily_routine.sb\n├── world/\n│ ├── locations.sb\n│ └── institutions.sb\n└── schema/ ├── species.sb └── templates.sb","breadcrumbs":"Language Overview » Project Structure","id":"140","title":"Project Structure"},"141":{"body":"Use use statements to reference definitions from other files: use schema::species::Human;\nuse schema::templates::Adult; character Baker: Human from Adult { // ...\n} Resolution order: Same file Explicitly imported Error if not found","breadcrumbs":"Language Overview » Import System","id":"141","title":"Import System"},"142":{"body":"","breadcrumbs":"Language Overview » Quick Reference","id":"142","title":"Quick Reference"},"143":{"body":"character Name: Species from Template { field: value field: value ---prose_tag Text content ---\n}","breadcrumbs":"Language Overview » Character Declaration","id":"143","title":"Character Declaration"},"144":{"body":"behavior Name { choose label { // Selector then label { ... } // Sequence if (condition) // Condition ActionName // Action include path // Subtree }\n}","breadcrumbs":"Language Overview » Behavior Tree","id":"144","title":"Behavior Tree"},"145":{"body":"life_arc Name { state StateName { on condition -> NextState }\n}","breadcrumbs":"Language Overview » Life Arc","id":"145","title":"Life Arc"},"146":{"body":"schedule Name { 08:00 -> 12:00: activity { } 12:00 -> 13:00: lunch { }\n}","breadcrumbs":"Language Overview » Schedule","id":"146","title":"Schedule"},"147":{"body":"relationship Name { Person1 as role Person2 as role bond: 0.85\n}","breadcrumbs":"Language Overview » Relationship","id":"147","title":"Relationship"},"148":{"body":"Dive deeper into each declaration type: Characters - Detailed character syntax Behavior Trees - Complete behavior node reference Decorators - All decorator types Life Arcs - State machine semantics Schedules - Time-based planning Relationships - Connection modeling Other Declarations - Templates, institutions, etc. Expressions - Full expression language Value Types - All field value types Validation - Error checking rules Philosophy Note : Storybook treats narrative as data. Characters aren't objects with methods - they're declarations of traits, connected by behaviors and relationships . This separation enables rich analysis, modification, and simulation of narrative worlds.","breadcrumbs":"Language Overview » Next Steps","id":"148","title":"Next Steps"},"149":{"body":"Characters are the primary entities in Storybook—the people, creatures, and beings that inhabit your world. Each character has a set of attributes that define who they are, what they can do, and how they relate to the world around them.","breadcrumbs":"Characters » Characters","id":"149","title":"Characters"},"15":{"body":"Fields use a simple name: value format: age: 34 // Integer\nskill_level: 0.95 // Float\nname: \"Martha Baker\" // String\nis_open: true // Boolean\nwake_time: 04:30 // Time\nbake_duration: 45m // Duration","breadcrumbs":"Welcome to Storybook » Fields Hold Data","id":"15","title":"Fields Hold Data"},"150":{"body":" ::= \"character\" ? ? ::= \":\" ::= \"from\" (\",\" )* ::= \"{\" * \"}\" ::= | | ::= \"uses\" \"behaviors\" \":\" ::= \"uses\" (\"schedule\" | \"schedules\") \":\" ( | ) ::= \"[\" (\",\" )* \"]\" ::= \"{\" * \"}\" ::= \"tree\" \":\" | \"when\" \":\" | \"priority\" \":\" (\"low\" | \"normal\" | \"high\" | \"critical\") ::= \"[\" (\",\" )* \"]\" ::= \":\" ::= | | | | | ::= \"---\" \"---\"","breadcrumbs":"Characters » Syntax","id":"150","title":"Syntax"},"151":{"body":"","breadcrumbs":"Characters » Components","id":"151","title":"Components"},"152":{"body":"The character's identifier. Must be unique within its scope and follow standard identifier rules (alphanumeric + underscore, cannot start with digit).","breadcrumbs":"Characters » Name","id":"152","title":"Name"},"153":{"body":"The species clause (: SpeciesName) defines what the character fundamentally is . This is distinct from templates, which define what attributes they have . Purpose : Ontological typing—what kind of being this is Validation : Must reference a defined species declaration Single inheritance : A character can only have one species Default behavior : Species fields are inherited automatically Example: character Martha: Human { age: 34\n}","breadcrumbs":"Characters » Species (Optional)","id":"153","title":"Species (Optional)"},"154":{"body":"The template clause (from Template1, Template2) specifies templates from which the character inherits fields. Templates provide reusable attribute sets. Purpose : Compositional inheritance—mix-and-match capabilities and traits Multiple inheritance : Characters can inherit from multiple templates Merge semantics : Fields from later templates override earlier ones Override allowed : Character fields override all inherited fields Example: character Martha: Human from Baker, BusinessOwner { specialty: \"sourdough\"\n}","breadcrumbs":"Characters » Template Inheritance (Optional)","id":"154","title":"Template Inheritance (Optional)"},"155":{"body":"Fields define the character's attributes using the standard field syntax. All value types are supported. Common field categories: Physical traits : height, weight, age, eye_color Personality : confidence, patience, dedication Professional : skill_level, specialty, recipes_mastered State tracking : energy, mood, orders_today Capabilities : can_teach, can_work_independently","breadcrumbs":"Characters » Fields","id":"155","title":"Fields"},"156":{"body":"Characters can contain multiple prose blocks for narrative content. Common tags: ---backstory: Character history and origin ---appearance: Physical description ---personality: Behavioral traits and quirks ---motivation: Goals and desires ---secrets: Hidden information Prose blocks are narrative-only and do not affect simulation logic.","breadcrumbs":"Characters » Prose Blocks","id":"156","title":"Prose Blocks"},"157":{"body":"Characters can link to behavior trees using the uses behaviors clause. character Guard { uses behaviors: [ { tree: combat::patrol_route priority: normal }, { tree: combat::engage_intruder when: threat_detected priority: high } ]\n} Each behavior link includes: tree : Qualified path to the behavior tree (required) when : Condition expression for activation (optional) priority : Execution priority (optional, default: normal) See Behavior Trees for details on behavior tree syntax and semantics.","breadcrumbs":"Characters » Behavior Integration","id":"157","title":"Behavior Integration"},"158":{"body":"Characters can follow schedules using the uses schedule or uses schedules clause. character Baker { uses schedule: BakerySchedule\n} character Innkeeper { uses schedules: [WeekdaySchedule, WeekendSchedule]\n} Single schedule: uses schedule: ScheduleName Multiple schedules: uses schedules: [Schedule1, Schedule2] The runtime selects the appropriate schedule based on temporal constraints. See Schedules for composition and selection semantics.","breadcrumbs":"Characters » Schedule Integration","id":"158","title":"Schedule Integration"},"159":{"body":"The distinction between species (:) and templates (from) reflects ontological vs. compositional typing: Feature Species (:) Templates (from) Semantics What the character is What the character has Cardinality Exactly one Zero or more Example : Human, : Dragon from Warrior, Mage Purpose Fundamental nature Reusable trait sets Override Can override species fields Can override template fields Example showing both: species Dragon { max_lifespan: 1000 can_fly: true\n} template Hoarder { treasure_value: 0..1000000 greed_level: 0.0..1.0\n} template Ancient { age: 500..1000 wisdom: 0.8..1.0\n} character Smaug: Dragon from Hoarder, Ancient { age: 850 treasure_value: 500000 greed_level: 0.95\n}","breadcrumbs":"Characters » Species vs. Templates","id":"159","title":"Species vs. Templates"},"16":{"body":"Prose blocks embed narrative text directly in your definitions: ---backstory\nMartha learned to bake from her grandmother, starting at age\ntwelve with simple bread recipes. Over the years she mastered\nsourdough, pastries, and specialty cakes, eventually opening\nher own bakery.\n--- You can have multiple prose blocks with different tags (backstory, appearance, personality, etc.) in a single declaration.","breadcrumbs":"Welcome to Storybook » Prose Blocks Tell Stories","id":"16","title":"Prose Blocks Tell Stories"},"160":{"body":"When a character inherits from species and templates, fields are resolved in this order (later overrides earlier): Species fields (base ontology) Template fields (left to right in from clause) Character fields (highest priority) Example: species Human { lifespan: 80 speed: 1.0\n} template Warrior { speed: 1.5 strength: 10\n} template Berserker { speed: 2.0 strength: 15\n} character Conan: Human from Warrior, Berserker { strength: 20\n} // Resolved fields:\n// lifespan: 80 (from Human)\n// speed: 2.0 (Berserker overrides Warrior overrides Human)\n// strength: 20 (character overrides Berserker)","breadcrumbs":"Characters » Field Resolution Order","id":"160","title":"Field Resolution Order"},"161":{"body":"The Storybook compiler enforces these validation rules: Unique names : Character names must be unique within their module Species exists : If specified, the species must reference a defined species declaration Templates exist : All templates in the from clause must reference defined template declarations No circular inheritance : Templates cannot form circular dependency chains Field type consistency : Field values must match expected types from species/templates Reserved fields : Cannot use reserved keywords as field names Behavior trees exist : All behavior tree references must resolve to defined behavior declarations Schedules exist : All schedule references must resolve to defined schedule declarations Prose tag uniqueness : Each prose tag can appear at most once per character","breadcrumbs":"Characters » Validation Rules","id":"161","title":"Validation Rules"},"162":{"body":"","breadcrumbs":"Characters » Examples","id":"162","title":"Examples"},"163":{"body":"character SimpleMerchant { name: \"Gregor\" occupation: \"Fish Merchant\" wealth: 50 ---personality A straightforward fish seller at the market. Honest, hardworking, and always smells faintly of mackerel. ---\n}","breadcrumbs":"Characters » Basic Character","id":"163","title":"Basic Character"},"164":{"body":"character Martha: Human { age: 34 skill_level: 0.95 specialty: \"sourdough\" ---backstory Martha learned to bake from her grandmother, starting at age twelve. She now runs the most popular bakery in town. ---\n}","breadcrumbs":"Characters » Character with Species","id":"164","title":"Character with Species"},"165":{"body":"character Jane: Human from Baker, PastrySpecialist { age: 36 specialty: \"pastries\" recipes_mastered: 120 years_experience: 18 can_teach: true ---appearance A focused woman with flour-dusted apron and steady hands. Known for her intricate pastry decorations and precise temperature control. ---\n}","breadcrumbs":"Characters » Character with Template Inheritance","id":"165","title":"Character with Template Inheritance"},"166":{"body":"character CityGuard: Human from CombatTraining, LawEnforcement { age: 30 rank: \"Sergeant\" // Physical traits height: 175 strength: 12 // Equipment has_weapon: true armor_level: 2 // Behavior integration uses behaviors: [ { tree: guards::patrol_route priority: normal }, { tree: guards::engage_hostile when: threat_detected priority: high }, { tree: guards::sound_alarm when: emergency priority: critical } ] // Schedule integration uses schedules: [guards::day_shift, guards::night_shift] ---backstory A veteran of the city watch, now responsible for training new recruits while maintaining order in the merchant district. --- ---personality Gruff exterior with a hidden soft spot for street children. Follows the rules but knows when to look the other way. ---\n}","breadcrumbs":"Characters » Character with All Features","id":"166","title":"Character with All Features"},"167":{"body":"template WeaponUser { damage: 5..15 accuracy: 0.7\n} character MasterSwordsman: Human from WeaponUser { // Override template range with specific value damage: 15 accuracy: 0.95 // Add character-specific fields signature_move: \"Whirlwind Strike\"\n}","breadcrumbs":"Characters » Character with Overrides","id":"167","title":"Character with Overrides"},"168":{"body":"","breadcrumbs":"Characters » Use Cases","id":"168","title":"Use Cases"},"169":{"body":"Define rich, dynamic protagonists with complex attributes: character Elena: Human from Scholar, Diplomat { age: 28 intelligence: 18 charisma: 16 languages_known: [\"Common\", \"Elvish\", \"Draconic\"] books_read: 347 current_quest: \"Broker peace between warring kingdoms\" ---backstory Raised in the Grand Library, Elena discovered ancient texts that hinted at a forgotten alliance between humans and dragons. She now seeks to revive that alliance to end the current war. ---\n}","breadcrumbs":"Characters » Protagonist Definition","id":"169","title":"Protagonist Definition"},"17":{"body":"A typical Storybook project organizes files into directories: my-world/ schema/ core_enums.sb // Enum definitions (skill levels, moods, etc.) templates.sb // Reusable trait sets beings.sb // Species definitions world/ characters/ martha.sb // Character definitions jane.sb behaviors/ baking.sb // Behavior trees relationships/ family.sb // Relationship definitions Files reference each other using use statements: use schema::core_enums::SkillLevel;\nuse schema::beings::Human; character Martha: Human { skill_level: expert\n}","breadcrumbs":"Welcome to Storybook » Project Structure","id":"17","title":"Project Structure"},"170":{"body":"Create diverse NPCs from templates: template Villager { occupation: \"Farmer\" wealth: 10..50 disposition: 0.0..1.0 // 0=hostile, 1=friendly\n} character Oswald: Human from Villager { occupation: \"Blacksmith\" wealth: 45 disposition: 0.8\n} character Mildred: Human from Villager { occupation: \"Baker\" wealth: 35 disposition: 0.95\n}","breadcrumbs":"Characters » NPC Templates","id":"170","title":"NPC Templates"},"171":{"body":"Define multiple related characters: template BakeryStaff { punctuality: 0.5..1.0 teamwork: 0.5..1.0\n} template Apprentice { skill_level: 0.0..0.5 dedication: 0.5..1.0\n} character Elena: Human from BakeryStaff, Apprentice { age: 16 natural_talent: 0.8 dedication: 0.9 ---backstory Elena comes from a family of farmers who could never afford to buy bread from the bakery. When Martha offered her an apprenticeship, she jumped at the chance to learn a trade. ---\n}","breadcrumbs":"Characters » Ensemble Casts","id":"171","title":"Ensemble Casts"},"172":{"body":"Species - Species declarations Templates - Template definitions and strict mode Value Types - All supported value types Behavior Trees - Character behavior integration Schedules - Character schedule integration Relationships - Relationships between characters Life Arcs - Character state machines over time","breadcrumbs":"Characters » Cross-References","id":"172","title":"Cross-References"},"173":{"body":"Instantiation : Characters are concrete instances; they cannot be instantiated further Composition : Prefer template composition over deep species hierarchies Modularity : Characters can reference behaviors and schedules from other modules Narrative-driven : Use prose blocks to embed storytelling directly with data","breadcrumbs":"Characters » Related Concepts","id":"173","title":"Related Concepts"},"174":{"body":"Behavior trees define the decision-making logic for characters, institutions, and other entities. They model how an entity chooses actions, responds to conditions, and adapts to its environment. Storybook uses behavior trees for character AI, NPC routines, and complex reactive behavior.","breadcrumbs":"Behavior Trees » Behavior Trees","id":"174","title":"Behavior Trees"},"175":{"body":"A behavior tree is a hierarchical structure that executes from root to leaves, making decisions based on success/failure of child nodes: Composite nodes (choose, then) have multiple children and control flow Condition nodes (if, when) test predicates Action nodes execute concrete behaviors Decorator nodes (repeat, invert, timeout, etc.) modify child behavior Subtree nodes (include) reference other behavior trees Behavior trees are evaluated every tick (frame), flowing through the tree from root to leaves until a node returns success or failure.","breadcrumbs":"Behavior Trees » What is a Behavior Tree?","id":"175","title":"What is a Behavior Tree?"},"176":{"body":" ::= \"behavior\" ::= \"{\" * \"}\" ::= | | | | | ::= \"choose\"