Files
storybook/docs/reference/11-behavior-trees.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

766 lines
17 KiB
Markdown

# 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
```bnf
<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. If succeeds -> return success
3. If fails -> try next child
4. If all fail -> return failure
**Use case:** "Try A, if that fails try B, if that fails try C..."
```storybook
behavior GuardBehavior {
choose guard_actions {
AttackIntruder // Try first
SoundAlarm // If attack fails, sound alarm
FleeInPanic // If alarm fails, flee
}
}
```
**Named selectors:**
```storybook
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. If fails -> return failure
3. If succeeds -> run next child
4. If all succeed -> return success
**Use case:** "Do A, then B, then C... all must succeed"
```storybook
behavior BrewingSequence {
then brew_potion {
GatherIngredients // Must succeed
MixIngredients // Then this must succeed
Boil // Then this must succeed
BottlePotion // Finally this
}
}
```
**Named sequences:**
```storybook
then prepare_sourdough {
MixDough
KneadDough
ShapeLoaves
}
```
### Nesting Composites
Composite nodes can nest arbitrarily deep:
```storybook
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:
```storybook
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
```storybook
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](./17-expressions.md) for complete expression syntax.
## Action Nodes
Actions are leaf nodes that execute concrete behaviors. They reference action implementations in the runtime.
### Basic Actions
```storybook
behavior SimpleActions {
then do_things {
MoveForward
TurnLeft
Attack
}
}
```
### Actions with Parameters
Actions can have named parameters using parenthesis syntax:
```storybook
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](./18-value-types.md) supported
- Runtime validates parameter types
```storybook
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](./12-decorators.md) for complete reference.
### Common Decorators
```storybook
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
```storybook
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
```storybook
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:
```storybook
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
```storybook
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
```storybook
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
```storybook
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
```storybook
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
```storybook
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:
```storybook
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](./10-characters.md#behavior-integration) 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. **Traverse** down to leaves based on composite logic
3. **Execute** leaf nodes (conditions, actions)
4. **Return** success/failure up the tree
5. **Repeat** next tick
### 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:
```storybook
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. **Composite children**: `choose` and `then` require at least one child
3. **Decorator child**: Decorators require exactly one child
4. **Action exists**: Action names must reference registered actions in runtime
5. **Subtree exists**: `include` must reference a defined `behavior` declaration
6. **Expression validity**: Condition expressions must be well-formed
7. **Duration format**: Decorator durations must be valid (e.g., `5s`, `10m`)
8. **Unique labels**: Node labels (if used) should be unique within their parent
9. **Parameter types**: Action parameters must match expected types
## Best Practices
### 1. Prefer Shallow Trees
**Avoid:**
```storybook
choose {
then { then { then { then { Action } } } } // Too deep!
}
```
**Prefer:**
```storybook
choose root {
include combat_tree
include exploration_tree
include social_tree
}
```
### 2. Use Named Nodes for Clarity
**Avoid:**
```storybook
choose {
then {
IsHungry
FindFood
Eat
}
Wander
}
```
**Prefer:**
```storybook
choose survival {
then eat_if_hungry {
IsHungry
FindFood
Eat
}
Wander
}
```
### 3. Subtrees for Reusability
**Avoid:** Duplicating logic across behaviors
**Prefer:**
```storybook
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:**
```storybook
timeout(10s) {
ComplexTask
}
cooldown(30s) {
SpecialAbility
}
```
### 5. Guard for Preconditions
**Avoid:**
```storybook
then problematic {
ExpensiveAction // Always runs even if inappropriate
}
```
**Prefer:**
```storybook
if(can_afford_action) {
ExpensiveAction // Only runs when condition passes
}
```
## Cross-References
- [Decorators](./12-decorators.md) - Complete decorator reference
- [Characters](./10-characters.md) - Linking behaviors to characters
- [Expression Language](./17-expressions.md) - Condition expression syntax
- [Value Types](./18-value-types.md) - Parameter value types
- [Design Patterns](../advanced/20-patterns.md) - Common behavior tree patterns
## Related Concepts
- **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