Files
storybook/docs/advanced/23-best-practices.md
Sienna Meridian Satterwhite 16deb5d237 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
2026-02-13 21:52:03 +00:00

7.6 KiB

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. 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