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
345 lines
7.6 KiB
Markdown
345 lines
7.6 KiB
Markdown
# 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
|