release: Storybook v0.2.0 - Major syntax and features update

BREAKING CHANGES:
- Relationship syntax now requires blocks for all participants
- Removed self/other perspective blocks from relationships
- Replaced 'guard' keyword with 'if' for behavior tree decorators

Language Features:
- Add tree-sitter grammar with improved if/condition disambiguation
- Add comprehensive tutorial and reference documentation
- Add SBIR v0.2.0 binary format specification
- Add resource linking system for behaviors and schedules
- Add year-long schedule patterns (day, season, recurrence)
- Add behavior tree enhancements (named nodes, decorators)

Documentation:
- Complete tutorial series (9 chapters) with baker family examples
- Complete reference documentation for all language features
- SBIR v0.2.0 specification with binary format details
- Added locations and institutions documentation

Examples:
- Convert all examples to baker family scenario
- Add comprehensive working examples

Tooling:
- Zed extension with LSP integration
- Tree-sitter grammar for syntax highlighting
- Build scripts and development tools

Version Updates:
- Main package: 0.1.0 → 0.2.0
- Tree-sitter grammar: 0.1.0 → 0.2.0
- Zed extension: 0.1.0 → 0.2.0
- Storybook editor: 0.1.0 → 0.2.0
This commit is contained in:
2026-02-13 21:52:03 +00:00
parent 80332971b8
commit 16deb5d237
290 changed files with 90316 additions and 5827 deletions

View File

@@ -0,0 +1,429 @@
# 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:
```storybook
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:
```storybook
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:
```storybook
// 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:
```storybook
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:
```storybook
// 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:
```storybook
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:
```storybook
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:
```storybook
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:
```storybook
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:
```storybook
// 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
```storybook
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
```storybook
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
```storybook
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
```storybook
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
- [Behavior Trees](../reference/11-behavior-trees.md) - Complete behavior syntax
- [Characters](../reference/10-characters.md) - Character architecture
- [Relationships](../reference/15-relationships.md) - Relationship modeling
- [Schedules](../reference/14-schedules.md) - Schedule composition
- [Life Arcs](../reference/13-life-arcs.md) - State machine patterns

View File

@@ -0,0 +1,82 @@
# 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. **Parser**: Builds an Abstract Syntax Tree (AST) from tokens
3. **Resolver**: Validates, resolves cross-references, merges templates, and produces SBIR
## 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:**
```storybook
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](../reference/19-validation.md):
- 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](../SBIR-v0.2.0-SPEC.md).
## Cross-References
- [Language Overview](../reference/09-overview.md) - Compilation model
- [Validation Rules](../reference/19-validation.md) - What is validated before SBIR production
- [Integration Guide](./22-integration.md) - How runtimes consume SBIR

View File

@@ -0,0 +1,160 @@
# 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. **Runtime**: A simulation engine consumes SBIR and drives character behavior
```
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
```bash
# 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:
```rust
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:
| Type | Description |
|------|-------------|
| `ResolvedFile` | Container for all resolved declarations |
| `ResolvedCharacter` | Character with merged species/template fields |
| `ResolvedBehavior` | Behavior tree with resolved subtree references |
| `ResolvedLifeArc` | State machine with validated transitions |
| `ResolvedSchedule` | Schedule with resolved time blocks |
| `ResolvedRelationship` | Relationship with resolved participant references |
| `ResolvedInstitution` | Institution with resolved fields |
| `ResolvedLocation` | Location with resolved fields |
| `ResolvedSpecies` | Species with resolved includes chain |
| `ResolvedEnum` | Enum 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. **Action execution**: Interpret action nodes (e.g., `MoveTo`, `Attack`)
3. **Condition evaluation**: Evaluate expression nodes against current state
4. **Decorator state**: Maintain timer/counter state for stateful decorators
### Life Arc Execution
1. Track the current state for each life arc instance
2. Evaluate transition conditions each tick
3. Execute on-enter actions when transitioning
4. Maintain state persistence across ticks
### Schedule Execution
1. Get the current simulation time
2. Find the matching schedule block (considering temporal constraints and recurrences)
3. Execute the associated behavior tree action
### 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
- [SBIR Format](./21-sbir-format.md) - The compiled binary format
- [Validation Rules](../reference/19-validation.md) - What the compiler checks
- [Language Overview](../reference/09-overview.md) - Compilation pipeline

View File

@@ -0,0 +1,344 @@
# 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:
```storybook
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:
```storybook
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:
```storybook
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:
```storybook
// 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:
```storybook
// 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:
```storybook
// 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
```storybook
// 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
```storybook
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:
```storybook
// 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
```storybook
// 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:
```storybook
// 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
```storybook
// 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
```storybook
// 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
```storybook
// 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
```storybook
// 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
```storybook
// 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 }
}
```
### Group Related Blocks
```storybook
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
```storybook
// 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
```storybook
// 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. **Explicit over implicit**: Say what you mean. Use named nodes, explicit imports, and clear field names.
3. **Flat over deep**: Shallow hierarchies, short behavior trees, and focused files are easier to maintain.
4. **Composition over inheritance**: Prefer combining templates over building deep species hierarchies.
5. **Document with prose**: Prose blocks are a feature, not clutter. Use them to explain intent alongside data.
6. **One concept per declaration**: Each behavior tree, life arc, or schedule should have a single clear purpose.
## Cross-References
- [Design Patterns](./20-patterns.md) - Common structural patterns
- [Validation Rules](../reference/19-validation.md) - What the compiler checks
- [Language Overview](../reference/09-overview.md) - Language philosophy