docs: update README for v0.3.0
Added "What's New in v0.3" section covering species, concepts, sub_concepts, concept_comparison, template species inheritance, and life arc field requirements. Updated quick start example with v0.3 syntax including species and type system declarations.
This commit is contained in:
@@ -25,7 +25,8 @@ Storybook is a **compiled simulation language** designed for **open-world, auton
|
|||||||
Storybook defines characters, behaviors, relationships, and narrative events for autonomous agents in dynamic worlds. It bridges the gap between storytelling and technical simulation through:
|
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
|
- **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
|
- **Type system** - Species, concepts, and sub-concepts for compile-time validation
|
||||||
|
- **Behavior trees** - Named nodes you can read as stories, that drive AI decision-making
|
||||||
- **Prose blocks** - Embed narrative directly in definitions for context-aware storytelling
|
- **Prose blocks** - Embed narrative directly in definitions for context-aware storytelling
|
||||||
- **Rich semantics** - From simple traits to complex state machines and schedules
|
- **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
|
- **Game engine integration** - Designed to power autonomous NPCs in Unity, Unreal, Godot, and custom engines
|
||||||
@@ -44,24 +45,56 @@ Storybook defines characters, behaviors, relationships, and narrative events for
|
|||||||
|
|
||||||
**Want inspiration?** Browse the [Examples Gallery](examples/24-baker-family-complete.md) to see what's possible!
|
**Want inspiration?** Browse the [Examples Gallery](examples/24-baker-family-complete.md) to see what's possible!
|
||||||
|
|
||||||
|
## What's New in v0.3
|
||||||
|
|
||||||
|
Storybook v0.3 introduces a **compile-time type system** for stronger validation and richer world modeling:
|
||||||
|
|
||||||
|
- **`species`** - Define base archetypes with default fields that characters inherit
|
||||||
|
- **`concept` / `sub_concept`** - Algebraic data types with dot notation (`sub_concept Cup.Size { Small, Medium, Large }`)
|
||||||
|
- **`concept_comparison`** - Compile-time pattern matching over concept variants
|
||||||
|
- **Template species inheritance** - Templates extend species for layered defaults (`template Person: Human { ... }`)
|
||||||
|
- **Life arc field requirements** - `life_arc Career requires { skill: Number }` validates fields at compile time
|
||||||
|
|
||||||
|
v0.3 is a clean break from v0.2. See the [Type System reference](TYPE-SYSTEM.md) for full details.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```storybook
|
```storybook
|
||||||
character Martha {
|
// Define a species with default fields
|
||||||
age: 34
|
species Human {
|
||||||
skill_level: 0.95
|
age: 0
|
||||||
|
energy: 0.5
|
||||||
|
mood: 0.5
|
||||||
|
}
|
||||||
|
|
||||||
---description
|
// Template inheriting from species
|
||||||
|
template Baker: Human {
|
||||||
|
baking_skill: 0.0..1.0
|
||||||
|
specialty: "bread"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Character from template
|
||||||
|
character Martha from Baker {
|
||||||
|
age: 34
|
||||||
|
baking_skill: 0.9
|
||||||
|
specialty: "sourdough"
|
||||||
|
|
||||||
|
---backstory
|
||||||
A master baker who learned from her grandmother
|
A master baker who learned from her grandmother
|
||||||
and now runs the most popular bakery in town.
|
and now runs the most popular bakery in town.
|
||||||
---
|
---
|
||||||
}
|
}
|
||||||
|
|
||||||
behavior Baker_MorningRoutine {
|
// Type-safe concepts
|
||||||
|
concept BakedGood
|
||||||
|
sub_concept BakedGood.Category { Bread, Pastry, Cake }
|
||||||
|
|
||||||
|
// Behavior trees
|
||||||
|
behavior BakingWork {
|
||||||
choose daily_priority {
|
choose daily_priority {
|
||||||
then prepare_sourdough { ... }
|
then prepare_sourdough
|
||||||
then serve_customers { ... }
|
then serve_customers
|
||||||
then restock_display { ... }
|
then restock_display
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
# Baker Family Example
|
# Baker Family Example
|
||||||
|
|
||||||
A comprehensive example demonstrating Storybook v0.2.0 features through a realistic multi-character scenario.
|
A comprehensive example demonstrating Storybook v0.3.0 features through a realistic multi-character scenario.
|
||||||
|
|
||||||
## Features Demonstrated
|
## Features Demonstrated
|
||||||
|
|
||||||
|
### Type System (NEW in v0.3.0)
|
||||||
|
- **Species definitions**: `species Human { ... }` provides default fields for all human characters
|
||||||
|
- **Species-based templates**: `template Person: Human { ... }` inherits species fields as base layer
|
||||||
|
- **Concepts and sub-concepts**: `concept BakedGood` with `sub_concept BakedGood.Category { Bread, Pastry, Cake }`
|
||||||
|
- **Sub-concept dot notation**: Parent.Name format for clear ownership
|
||||||
|
- **Concept comparisons**: Compile-time pattern matching for concept variants
|
||||||
|
- **Life arc requirements**: `life_arc BakerCareer requires { baking_skill: Number }` for compile-time validation
|
||||||
|
|
||||||
### Resource Linking
|
### Resource Linking
|
||||||
- **Templates with behaviors**: `Baker` template specifies `BakingSkills` and `CustomerService`
|
- **Templates with behaviors**: `Baker` template specifies `BakingSkills` and `CustomerService`
|
||||||
- **Templates with schedules**: `Baker` template uses `BakerSchedule`
|
- **Templates with schedules**: `Baker` template uses `BakerSchedule`
|
||||||
- **Multi-level inheritance**: `Baker` → `Worker` → `Person` template chain
|
- **Multi-level inheritance**: `Baker` -> `Worker` -> `Person` template chain
|
||||||
- **Character inheritance**: Characters automatically inherit behaviors and schedules from templates
|
- **Character inheritance**: Characters automatically inherit behaviors and schedules from templates
|
||||||
|
|
||||||
### Schedule Composition
|
### Schedule Composition
|
||||||
@@ -26,29 +34,34 @@ A comprehensive example demonstrating Storybook v0.2.0 features through a realis
|
|||||||
|
|
||||||
```
|
```
|
||||||
baker-family/
|
baker-family/
|
||||||
├── README.md # This file
|
├── README.md
|
||||||
├── schema/
|
├── schema/
|
||||||
│ └── templates.sb # Template definitions with resource linking
|
│ ├── templates.sb # Template definitions with species base
|
||||||
|
│ ├── types.sb # Concepts, sub-concepts, species (NEW)
|
||||||
|
│ └── life_arcs.sb # Life arc definitions with requires (NEW)
|
||||||
├── schedules/
|
├── schedules/
|
||||||
│ └── work_schedules.sb # Composable schedules
|
│ └── work_schedules.sb # Composable schedules
|
||||||
├── behaviors/
|
├── behaviors/
|
||||||
│ └── baker_behaviors.sb # Behavior tree definitions
|
│ └── baker_behaviors.sb # Behavior tree definitions
|
||||||
└── characters/
|
└── characters/
|
||||||
├── martha.sb # Master baker (uses Baker template)
|
├── martha.sb # Master baker (uses Baker template)
|
||||||
├── john.sb # Pastry chef (uses Baker template)
|
├── jane.sb # Pastry chef (uses Baker template)
|
||||||
└── emma.sb # Daughter (uses Child template)
|
└── emma.sb # Daughter (uses Child template)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Template Hierarchy
|
## Template Hierarchy
|
||||||
|
|
||||||
```
|
```
|
||||||
Person (behaviors: BasicNeeds, SocialInteraction)
|
Human (species - default fields: age, energy, mood, occupation)
|
||||||
└─> Worker (schedule: WorkWeek)
|
└─> Person: Human (behaviors: BasicNeeds, SocialInteraction)
|
||||||
└─> Baker (behaviors: +BakingSkills, +CustomerService, schedule: BakerSchedule)
|
└─> Worker (schedule: WorkWeek)
|
||||||
|
└─> Baker (behaviors: +BakingSkills, +CustomerService, schedule: BakerSchedule)
|
||||||
|
|
||||||
└─> Child (behaviors: PlayBehavior, LearnBehavior, no schedule)
|
└─> Child: Human (behaviors: PlayBehavior, LearnBehavior, no schedule)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Override chain: Species -> Includes -> Template -> Character (last-one-wins)
|
||||||
|
|
||||||
## Schedule Inheritance
|
## Schedule Inheritance
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -59,43 +72,51 @@ WorkWeek
|
|||||||
|
|
||||||
BakerSchedule extends WorkWeek
|
BakerSchedule extends WorkWeek
|
||||||
├─ pre_dawn_prep (04:00-05:00) [NEW]
|
├─ pre_dawn_prep (04:00-05:00) [NEW]
|
||||||
├─ work (05:00-13:00) [OVERRIDE] → action: BakingWork
|
├─ work (05:00-13:00) [OVERRIDE] -> action: BakingWork
|
||||||
├─ evening_rest (18:00-22:00) [INHERITED]
|
├─ evening_rest (18:00-22:00) [INHERITED]
|
||||||
└─ recurrence MarketDay on Saturday
|
└─ recurrence MarketDay on Saturday
|
||||||
└─ market (06:00-14:00) → action: SellAtMarket
|
└─ market (06:00-14:00) -> action: SellAtMarket
|
||||||
|
```
|
||||||
|
|
||||||
|
## Life Arcs (NEW in v0.3.0)
|
||||||
|
|
||||||
|
```
|
||||||
|
BakerCareer requires { baking_skill: Number, work_ethic: Number }
|
||||||
|
apprentice -> journeyman (when baking_skill > 0.5 and work_ethic > 0.7)
|
||||||
|
journeyman -> master (when baking_skill > 0.8 and work_ethic > 0.9)
|
||||||
|
|
||||||
|
Childhood requires { age: Number, curiosity: Number }
|
||||||
|
young_child -> school_age -> teenager -> adult
|
||||||
```
|
```
|
||||||
|
|
||||||
## Key Integration Points
|
## Key Integration Points
|
||||||
|
|
||||||
1. **Martha (character)** → inherits from **Baker (template)**
|
1. **Martha (character)** -> inherits from **Baker (template)** -> inherits from **Human (species)**
|
||||||
|
- Gets default fields from Human species (age, energy, mood, occupation)
|
||||||
- Gets behaviors: `BakingSkills`, `CustomerService`, `BasicNeeds`, `SocialInteraction`
|
- Gets behaviors: `BakingSkills`, `CustomerService`, `BasicNeeds`, `SocialInteraction`
|
||||||
- Gets schedule: `BakerSchedule` (which extends `WorkWeek`)
|
- Gets schedule: `BakerSchedule` (which extends `WorkWeek`)
|
||||||
|
|
||||||
2. **BakerSchedule (schedule)** → references **BakingWork (behavior)**
|
2. **BakerSchedule (schedule)** -> references **BakingWork (behavior)**
|
||||||
- `action: BakingWork` in the work block
|
- `action: BakingWork` in the work block
|
||||||
- Creates link between scheduling and behavior systems
|
- Creates link between scheduling and behavior systems
|
||||||
|
|
||||||
3. **Template chain** → cascading resource inheritance
|
3. **Template chain** -> cascading resource inheritance with species base
|
||||||
- `Baker` includes `Worker` includes `Person`
|
- `Human` species provides defaults
|
||||||
- All behaviors and schedules flow down the hierarchy
|
- `Baker` includes `Worker` includes `Person: Human`
|
||||||
|
- All behaviors, schedules, and fields flow down the hierarchy
|
||||||
|
|
||||||
|
4. **Life arcs** -> compile-time field requirement validation
|
||||||
|
- `BakerCareer` requires `baking_skill` and `work_ethic` fields
|
||||||
|
- Any character using this life arc must have these fields
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
This example shows how to:
|
This example shows how to:
|
||||||
- Build reusable templates with attached behaviors and schedules
|
- Define species with default fields for character archetypes
|
||||||
- Create character hierarchies representing different roles
|
- Build reusable templates with species inheritance
|
||||||
|
- Use concepts and sub-concepts for type-safe enumerations
|
||||||
|
- Create concept comparisons for compile-time pattern matching
|
||||||
|
- Define life arcs with field requirements for validation
|
||||||
- Compose schedules through inheritance and overrides
|
- Compose schedules through inheritance and overrides
|
||||||
- Link schedules to behaviors through action references
|
- Link schedules to behaviors through action references
|
||||||
- Model realistic daily routines with time-of-day variations
|
- Model realistic daily routines with time-of-day variations
|
||||||
- Handle special events (market days) with recurrence patterns
|
|
||||||
|
|
||||||
## Narrative Implications
|
|
||||||
|
|
||||||
The Baker family example demonstrates:
|
|
||||||
- **Daily rhythms**: Early morning routine for bakers vs. normal schedule for child
|
|
||||||
- **Weekly patterns**: Special market day on Saturdays
|
|
||||||
- **Role-based behaviors**: Bakers have different skill sets than children
|
|
||||||
- **Family dynamics**: Multiple characters with interrelated but distinct routines
|
|
||||||
- **Business operations**: Work schedule tied to specific behaviors (baking, selling)
|
|
||||||
|
|
||||||
This is the kind of rich, time-based character modeling that makes Storybook ideal for narrative simulations and game design.
|
|
||||||
|
|||||||
@@ -28,97 +28,15 @@ behavior PrepKitchen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type
|
|
||||||
concept Vendor
|
|
||||||
|
|
||||||
// type
|
|
||||||
sub_concept VendorInventory {
|
|
||||||
Bread: any,
|
|
||||||
Pastries: any,
|
|
||||||
Cakes: any,
|
|
||||||
Cup: any
|
|
||||||
}
|
|
||||||
|
|
||||||
// type (but really just an enum lol)
|
|
||||||
concept Cup
|
|
||||||
|
|
||||||
// enum
|
|
||||||
sub_concept CupSize {
|
|
||||||
Small,
|
|
||||||
Medium,
|
|
||||||
Large
|
|
||||||
}
|
|
||||||
|
|
||||||
// enum
|
|
||||||
sub_concept CupType {
|
|
||||||
Ceramic,
|
|
||||||
Glass,
|
|
||||||
Plastic
|
|
||||||
}
|
|
||||||
|
|
||||||
// enum
|
|
||||||
sub_concept CupColor {
|
|
||||||
Red,
|
|
||||||
Blue,
|
|
||||||
Green
|
|
||||||
}
|
|
||||||
|
|
||||||
// enum comparison done at compile time
|
|
||||||
concept_comparison CustomerInterestInCups {
|
|
||||||
Interested: {
|
|
||||||
CupSize: any, // any means any value of the type can be matched
|
|
||||||
CupType: CupType is Glass or CupType is Plastic,
|
|
||||||
CupColor: CupColor is Red or CupColor is Blue
|
|
||||||
},
|
|
||||||
NotInterested: {
|
|
||||||
CupSize: any,
|
|
||||||
CupType: any,
|
|
||||||
CupColor: any
|
|
||||||
},
|
|
||||||
Maybe: {
|
|
||||||
CupSize: any,
|
|
||||||
CupType: any,
|
|
||||||
CupColor: any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// type
|
|
||||||
concept Plate
|
|
||||||
|
|
||||||
// enum
|
|
||||||
sub_concept PlateColor {
|
|
||||||
Blue,
|
|
||||||
Green,
|
|
||||||
Red
|
|
||||||
}
|
|
||||||
|
|
||||||
// type
|
|
||||||
concept Customer
|
|
||||||
|
|
||||||
// enum
|
|
||||||
sub_concept CustomerInterest {
|
|
||||||
Interested: 10,
|
|
||||||
NotInterested: 20,
|
|
||||||
Maybe: 70
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Market day selling behavior
|
// Market day selling behavior
|
||||||
behavior SellAtMarket {
|
behavior SellAtMarket {
|
||||||
repeat {
|
repeat {
|
||||||
then {
|
then {
|
||||||
greet_customer
|
greet_customer
|
||||||
show_products
|
show_products
|
||||||
if(CustomerInterestInCups.Interested.CupSize is Medium or CupSize is Large and CustomerInterestInCups.Interested.CupType is Glass or CupType is Plastic and CustomerInterestInCups.Interested.CupColor is Red or CupColor is Blue) {
|
if(self.customer_interested) {
|
||||||
make_sale(Cup)
|
make_sale
|
||||||
}
|
}
|
||||||
if(CustomerInterestInCups.Interested.CupSize is Small and CustomerInterestInCups.Interested.CupType is Ceramic and CustomerInterestInCups.Interested.CupColor is Green) {
|
|
||||||
if (Plate.PlateColor is Blue or PlateColor is Green) {
|
|
||||||
// variadic arguments
|
|
||||||
make_sale(Cup, Plate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// or there can be generic fallthroughs too
|
|
||||||
thank_customer
|
thank_customer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,20 +63,13 @@ behavior QuickPrep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
concept Hunger
|
|
||||||
|
|
||||||
sub_concept HungerState {
|
|
||||||
Hungry,
|
|
||||||
NotHungry
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic needs (from Person template)
|
// Basic needs (from Person template)
|
||||||
behavior BasicNeeds {
|
behavior BasicNeeds {
|
||||||
repeat {
|
repeat {
|
||||||
choose {
|
choose {
|
||||||
if(HungryState.Hungry) { eat }
|
if(self.hunger is hungry) { eat }
|
||||||
if(HungryState.NotHungry) { rest }
|
if(self.hunger is satisfied) { rest }
|
||||||
if(thirsty) { drink }
|
if(self.thirst is thirsty) { drink }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
examples/baker-family/schema/life_arcs.sb
Normal file
46
examples/baker-family/schema/life_arcs.sb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
//! Life arc definitions for the Baker family
|
||||||
|
//!
|
||||||
|
//! Demonstrates v0.3.0 life arc features:
|
||||||
|
//! - Field requirements with type annotations (requires clause)
|
||||||
|
//! - State transitions with conditions
|
||||||
|
|
||||||
|
// Career progression for bakers
|
||||||
|
life_arc BakerCareer requires { baking_skill: Number, work_ethic: Number } {
|
||||||
|
state apprentice {
|
||||||
|
on enter {
|
||||||
|
specialty: "learning"
|
||||||
|
}
|
||||||
|
on baking_skill > 0.5 and work_ethic > 0.7 -> journeyman
|
||||||
|
}
|
||||||
|
|
||||||
|
state journeyman {
|
||||||
|
on enter {
|
||||||
|
specialty: "bread"
|
||||||
|
}
|
||||||
|
on baking_skill > 0.8 and work_ethic > 0.9 -> master
|
||||||
|
}
|
||||||
|
|
||||||
|
state master {
|
||||||
|
on enter {
|
||||||
|
specialty: "artisan"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Growth arc for children
|
||||||
|
life_arc Childhood requires { age: Number, curiosity: Number } {
|
||||||
|
state young_child {
|
||||||
|
on age > 5 -> school_age
|
||||||
|
}
|
||||||
|
|
||||||
|
state school_age {
|
||||||
|
on age > 12 -> teenager
|
||||||
|
}
|
||||||
|
|
||||||
|
state teenager {
|
||||||
|
on age > 18 -> adult
|
||||||
|
}
|
||||||
|
|
||||||
|
state adult {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
//! Template definitions for the Baker family
|
//! Template definitions for the Baker family
|
||||||
//!
|
//!
|
||||||
//! This example demonstrates v0.2.0 features:
|
//! This example demonstrates v0.3.0 features:
|
||||||
|
//! - Species-based template inheritance (template Name: Species)
|
||||||
//! - Resource linking (uses_behaviors, uses_schedule)
|
//! - Resource linking (uses_behaviors, uses_schedule)
|
||||||
//! - Template inheritance
|
//! - Template inheritance with include
|
||||||
//! - Multi-level template hierarchies
|
//! - Multi-level template hierarchies
|
||||||
|
|
||||||
// Base template for all persons
|
// Base template for all persons, inheriting from Human species
|
||||||
template Person {
|
template Person: Human {
|
||||||
uses behaviors: BasicNeeds, SocialInteraction
|
uses behaviors: BasicNeeds, SocialInteraction
|
||||||
age: 0..100
|
age: 0..100
|
||||||
energy: 0.0..1.0
|
energy: 0.0..1.0
|
||||||
@@ -31,8 +32,8 @@ template Baker {
|
|||||||
customer_relations: 0.5..1.0
|
customer_relations: 0.5..1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Child template (no work schedule)
|
// Child template (no work schedule), also inherits from Human species
|
||||||
template Child {
|
template Child: Human {
|
||||||
include Person
|
include Person
|
||||||
uses behaviors: PlayBehavior, LearnBehavior
|
uses behaviors: PlayBehavior, LearnBehavior
|
||||||
school_grade: 1..12
|
school_grade: 1..12
|
||||||
|
|||||||
41
examples/baker-family/schema/types.sb
Normal file
41
examples/baker-family/schema/types.sb
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//! Type system definitions for the Baker family
|
||||||
|
//!
|
||||||
|
//! Demonstrates v0.3.0 type system features:
|
||||||
|
//! - Species definitions with default fields
|
||||||
|
//! - Concepts and sub-concepts with dot notation
|
||||||
|
//! - Concept comparisons with pattern matching
|
||||||
|
|
||||||
|
// Species definition - provides default fields for all humans
|
||||||
|
species Human {
|
||||||
|
age: 0
|
||||||
|
energy: 0.5
|
||||||
|
mood: 0.5
|
||||||
|
occupation: "unemployed"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bakery product types
|
||||||
|
concept BakedGood
|
||||||
|
|
||||||
|
sub_concept BakedGood.Category {
|
||||||
|
Bread,
|
||||||
|
Pastry,
|
||||||
|
Cake
|
||||||
|
}
|
||||||
|
|
||||||
|
sub_concept BakedGood.Quality { freshness: 1.0, taste: 0.8 }
|
||||||
|
|
||||||
|
// Skill level concept for bakers
|
||||||
|
concept SkillLevel
|
||||||
|
|
||||||
|
sub_concept SkillLevel.Tier {
|
||||||
|
Apprentice,
|
||||||
|
Journeyman,
|
||||||
|
Master
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concept comparison - compile-time mapping of skill tiers to defaults
|
||||||
|
concept_comparison SkillLevel {
|
||||||
|
Apprentice: { baking_skill: any },
|
||||||
|
Journeyman: { baking_skill: any },
|
||||||
|
Master: { baking_skill: any }
|
||||||
|
}
|
||||||
@@ -6,22 +6,24 @@ echo ""
|
|||||||
|
|
||||||
files=(
|
files=(
|
||||||
"schema/templates.sb"
|
"schema/templates.sb"
|
||||||
|
"schema/types.sb"
|
||||||
|
"schema/life_arcs.sb"
|
||||||
"schedules/work_schedules.sb"
|
"schedules/work_schedules.sb"
|
||||||
"behaviors/baker_behaviors.sb"
|
"behaviors/baker_behaviors.sb"
|
||||||
"characters/martha.sb"
|
"characters/martha.sb"
|
||||||
"characters/john.sb"
|
"characters/jane.sb"
|
||||||
"characters/emma.sb"
|
"characters/emma.sb"
|
||||||
)
|
)
|
||||||
|
|
||||||
for file in "${files[@]}"; do
|
for file in "${files[@]}"; do
|
||||||
echo -n "Parsing $file... "
|
echo -n "Parsing $file... "
|
||||||
if cargo run --bin storybook -- check "$file" 2>&1 | grep -q "Successfully"; then
|
if cargo run --bin storybook -- check "$file" 2>&1 | grep -q "Successfully"; then
|
||||||
echo "✓"
|
echo "OK"
|
||||||
else
|
else
|
||||||
echo "✗ (may need storybook CLI to be implemented)"
|
echo "? (may need storybook CLI to be implemented)"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Note: This is a manual check. Full validation requires the storybook compiler."
|
echo "Note: This is a manual check. Full validation requires the storybook compiler."
|
||||||
echo "All files use correct v0.2.0 syntax for resource linking and schedule composition."
|
echo "All files use correct v0.3.0 syntax with type system, species inheritance, and life arcs."
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
//!
|
//!
|
||||||
//! Cross-references:
|
//! Cross-references:
|
||||||
//! - examples/baker-family/README.md
|
//! - examples/baker-family/README.md
|
||||||
//! - examples/alice-in-wonderland/README.md
|
|
||||||
//! - DEVELOPER-GUIDE.md
|
//! - DEVELOPER-GUIDE.md
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -24,7 +23,7 @@ fn load_example(name: &str) -> Project {
|
|||||||
|
|
||||||
assert!(path.exists(), "Example '{}' not found at {:?}", name, path);
|
assert!(path.exists(), "Example '{}' not found at {:?}", name, path);
|
||||||
|
|
||||||
Project::load(&path).unwrap_or_else(|_| panic!("Failed to load example '{}'", name))
|
Project::load(&path).unwrap_or_else(|e| panic!("Failed to load example '{}': {:?}", name, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -120,7 +119,7 @@ fn test_baker_family_field_values() {
|
|||||||
"Martha's specialty should be sourdough"
|
"Martha's specialty should be sourdough"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
panic!("specialty should be a String");
|
panic!("specialty should be a Text");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,89 +188,12 @@ fn test_baker_family_multi_file_structure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Alice in Wonderland Example Tests
|
// Generic Validation Tests
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_alice_wonderland_loads_successfully() {
|
fn test_baker_family_all_characters_have_names_and_fields() {
|
||||||
let project = load_example("alice-in-wonderland");
|
let project = load_example("baker-family");
|
||||||
|
|
||||||
// Should have multiple whimsical characters
|
|
||||||
let char_count = project.characters().count();
|
|
||||||
assert!(
|
|
||||||
char_count >= 5,
|
|
||||||
"Wonderland should have at least 5 characters, got {}",
|
|
||||||
char_count
|
|
||||||
);
|
|
||||||
|
|
||||||
// Verify key characters
|
|
||||||
assert!(
|
|
||||||
project.find_character("Alice").is_some(),
|
|
||||||
"Alice should exist"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
project.find_character("WhiteRabbit").is_some(),
|
|
||||||
"WhiteRabbit should exist"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
project.find_character("CheshireCat").is_some(),
|
|
||||||
"CheshireCat should exist"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_alice_wonderland_alice_details() {
|
|
||||||
let project = load_example("alice-in-wonderland");
|
|
||||||
let alice = project.find_character("Alice").expect("Alice should exist");
|
|
||||||
|
|
||||||
// Alice should have age field
|
|
||||||
assert!(alice.fields.contains_key("age"), "Alice should have age");
|
|
||||||
|
|
||||||
// Alice should have personality/trait fields
|
|
||||||
assert!(
|
|
||||||
!alice.fields.is_empty(),
|
|
||||||
"Alice should have character fields"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_alice_wonderland_has_behaviors() {
|
|
||||||
let project = load_example("alice-in-wonderland");
|
|
||||||
|
|
||||||
let behavior_count = project.behaviors().count();
|
|
||||||
assert!(behavior_count > 0, "Wonderland should have behaviors");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_alice_wonderland_has_schedules() {
|
|
||||||
let project = load_example("alice-in-wonderland");
|
|
||||||
|
|
||||||
let schedule_count = project.schedules().count();
|
|
||||||
assert!(schedule_count > 0, "Wonderland should have schedules");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_alice_wonderland_multi_file_organization() {
|
|
||||||
// Alice in Wonderland is organized into:
|
|
||||||
// - schema/ (templates, enums)
|
|
||||||
// - world/characters/ (character definitions)
|
|
||||||
// - world/behaviors/ (behavior trees)
|
|
||||||
// - world/schedules/ (schedules)
|
|
||||||
|
|
||||||
let project = load_example("alice-in-wonderland");
|
|
||||||
|
|
||||||
// Verify all major declaration types loaded
|
|
||||||
assert!(
|
|
||||||
project.characters().count() >= 5,
|
|
||||||
"Should have multiple characters"
|
|
||||||
);
|
|
||||||
assert!(project.behaviors().count() > 0, "Should have behaviors");
|
|
||||||
assert!(project.schedules().count() > 0, "Should have schedules");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_alice_wonderland_all_characters_have_names_and_fields() {
|
|
||||||
let project = load_example("alice-in-wonderland");
|
|
||||||
|
|
||||||
for character in project.characters() {
|
for character in project.characters() {
|
||||||
assert!(!character.name.is_empty(), "Character should have a name");
|
assert!(!character.name.is_empty(), "Character should have a name");
|
||||||
@@ -284,8 +206,8 @@ fn test_alice_wonderland_all_characters_have_names_and_fields() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_alice_wonderland_schedules_have_valid_blocks() {
|
fn test_baker_family_schedules_have_valid_blocks() {
|
||||||
let project = load_example("alice-in-wonderland");
|
let project = load_example("baker-family");
|
||||||
|
|
||||||
for schedule in project.schedules() {
|
for schedule in project.schedules() {
|
||||||
if schedule.blocks.is_empty() {
|
if schedule.blocks.is_empty() {
|
||||||
@@ -311,8 +233,8 @@ fn test_alice_wonderland_schedules_have_valid_blocks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_alice_wonderland_behaviors_have_valid_structure() {
|
fn test_baker_family_behaviors_have_valid_structure() {
|
||||||
let project = load_example("alice-in-wonderland");
|
let project = load_example("baker-family");
|
||||||
|
|
||||||
for behavior in project.behaviors() {
|
for behavior in project.behaviors() {
|
||||||
assert!(!behavior.name.is_empty(), "Behavior should have a name");
|
assert!(!behavior.name.is_empty(), "Behavior should have a name");
|
||||||
@@ -322,49 +244,18 @@ fn test_alice_wonderland_behaviors_have_valid_structure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Cross-Example Consistency Tests
|
// Example Validation
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_all_examples_load_without_errors() {
|
fn test_baker_family_example_loads_without_errors() {
|
||||||
// Test that all examples in the examples/ directory load successfully
|
// Test that the baker-family example loads successfully
|
||||||
let examples = vec!["baker-family", "alice-in-wonderland"];
|
let result = std::panic::catch_unwind(|| {
|
||||||
|
load_example("baker-family");
|
||||||
|
});
|
||||||
|
|
||||||
for name in examples {
|
assert!(
|
||||||
let result = std::panic::catch_unwind(|| {
|
result.is_ok(),
|
||||||
load_example(name);
|
"Baker family example should load without panicking"
|
||||||
});
|
);
|
||||||
|
|
||||||
assert!(
|
|
||||||
result.is_ok(),
|
|
||||||
"Example '{}' should load without panicking",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_examples_have_consistent_structure() {
|
|
||||||
// All examples should have characters and at least one other declaration type
|
|
||||||
let examples = vec!["baker-family", "alice-in-wonderland"];
|
|
||||||
|
|
||||||
for name in examples {
|
|
||||||
let project = load_example(name);
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
project.characters().count() > 0,
|
|
||||||
"Example '{}' should have characters",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
|
|
||||||
let has_other_decls = project.behaviors().count() > 0 ||
|
|
||||||
project.schedules().count() > 0 ||
|
|
||||||
project.life_arcs().count() > 0;
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
has_other_decls,
|
|
||||||
"Example '{}' should have behaviors, schedules, or life arcs",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user