Files
storybook/docs/tutorial/02-creating-characters.md

314 lines
7.7 KiB
Markdown

# Creating Characters
Characters are the heart of every Storybook world. In this chapter, you will learn how to define characters with fields, prose blocks, species, and templates.
## A Simple Character
The simplest character has a name and some fields:
```storybook
character Martha {
age: 34
skill_level: 0.95
is_open: true
}
```
Fields use the `name: value` format. Storybook supports several value types:
| Type | Example | Description |
|------|---------|-------------|
| Number | `42` | Whole numbers |
| Decimal | `0.85` | Decimal numbers |
| String | `"hello"` | Text in double quotes |
| Boolean | `true` / `false` | Yes or no values |
| Time | `14:30` | Clock times |
| Duration | `2h30m` | Time intervals |
| List | `[1, 2, 3]` | Ordered collections |
## Adding Descriptions with Prose Blocks
Prose blocks embed narrative text directly alongside data. They start and end with `---` and have a tag name:
```storybook
character Martha {
age: 34
skill_level: 0.95
---backstory
Martha learned to bake from her grandmother, starting at age
twelve with simple bread recipes. She mastered sourdough and
pastries, eventually opening the most popular bakery in town.
---
---appearance
A confident woman in her mid-thirties, usually dusted with
flour. Her hands are calloused from years of kneading dough.
---
}
```
You can use any tag name you like. Common ones include `backstory`, `appearance`, `personality`, `motivation`, and `secrets`.
## Defining Species
Species define what a character fundamentally *is*. Define them separately, then reference them with the `:` syntax:
```storybook
species Human {
lifespan: 70
---description
Bipedal mammals with complex language and tool use.
---
}
species Cat {
lifespan: 15
---description
Domestic cats make loyal companions and effective
pest control for bakeries.
---
}
```
Now use species when creating characters:
```storybook
character Martha: Human {
age: 34
}
character Whiskers: Cat {
friendly: true
catches_mice: true
}
```
The `: Human` part says "Martha is a Human." She inherits the species' fields (like `lifespan: 70`) automatically.
A character can have only one species -- you cannot be both Human and Cat.
### But what about hybrids?
If you want a character that combines traits from different sources, use **composition with templates** instead:
```storybook
species Human {
lifespan: 70
reasoning_ability: 1.0
}
template CulinaryExpert {
palate_sensitivity: 0.5..1.0
recipes_mastered: 0..500
can_identify_ingredients: true
}
template BusinessOwner {
business_acumen: 0.0..1.0
manages_finances: true
leadership: 0.0..1.0
}
// A character combining species with multiple templates
character Martha: Human from CulinaryExpert, BusinessOwner {
age: 34
// From CulinaryExpert
palate_sensitivity: 0.9
recipes_mastered: 150
can_identify_ingredients: true
// From BusinessOwner
business_acumen: 0.8
manages_finances: true
leadership: 0.85
// Unique traits
specialty: "sourdough"
years_experience: 22
---personality
A perfectionist in the kitchen who demands the best from her
ingredients and her team. Warm with customers but exacting
with her apprentices.
---
}
```
By combining a species with templates, you can achieve any combination you need. The species defines *what* the character fundamentally is, while templates add *traits* from other sources.
## Reusing Traits with Templates
Templates define reusable sets of attributes. Characters inherit from them using the `from` keyword:
```storybook
template SkilledWorker {
skill_level: 0.0..1.0
years_experience: 0..50
}
template Baker {
include SkilledWorker
specialty: "general"
recipes_mastered: 0..500
}
```
Notice the `0.0..1.0` syntax -- that is a **range**. When a character uses this template, a specific value within that range is selected. Ranges are only valid in templates.
Characters can inherit from multiple templates:
```storybook
character Martha: Human from Baker, BusinessOwner {
age: 34
skill_level: 0.95
specialty: "sourdough"
recipes_mastered: 150
}
```
The `from Baker, BusinessOwner` part says "Martha has the traits from both templates." You can override any inherited field by specifying it directly.
## Species vs. Templates
Understanding the difference is important:
| | Species (`:`) | Templates (`from`) |
|--|--------------|-------------------|
| **Meaning** | What the character *is* | What the character *has* |
| **Count** | Exactly one | Zero or more |
| **Example** | `: Human` | `from Baker, BusinessOwner` |
Think of it this way: a character **is** a Human, but **has** baking skills and business acumen.
## Field Resolution
When a character inherits from multiple sources, fields are resolved in priority order:
1. **Species fields** (lowest priority)
2. **Template fields** (left to right in the `from` clause)
3. **Character fields** (highest priority -- always wins)
```storybook
species Human {
speed: 1.0
}
template Warrior {
speed: 1.5
strength: 10
}
template Berserker {
speed: 2.0
strength: 15
}
character Conan: Human from Warrior, Berserker {
strength: 20
}
// Resolved: speed = 2.0 (Berserker), strength = 20 (Conan)
```
## Using Enums for Controlled Values
Enums define a fixed set of named values. They prevent typos and ensure consistency:
```storybook
enum SkillLevel {
Novice,
Beginner,
Intermediate,
Advanced,
Expert,
Master
}
enum Specialty {
Sourdough,
Pastries,
Cakes,
Bread,
Confections
}
```
Use enum values as field values:
```storybook
character Martha: Human {
skill_level: Master
specialty: Sourdough
}
```
If you write `skill_level: Professional`, the compiler will catch the mistake because `Professional` is not defined in the `SkillLevel` enum.
## Importing Across Files
Real projects split definitions across multiple files. Use the `use` statement to import:
```storybook
// In world/characters/martha.sb
use schema::core_enums::{SkillLevel, Specialty};
use schema::templates::Baker;
use schema::beings::Human;
character Martha: Human from Baker {
skill_level: Master
specialty: Sourdough
}
```
The `use schema::core_enums::{SkillLevel, Specialty}` line imports two enums from the `schema/core_enums.sb` file. You can also import everything with `use schema::core_enums::*`.
## Putting It All Together
Here is a complete character definition with all the features:
```storybook
use schema::core_enums::{SkillLevel, Specialty};
use schema::templates::{Baker, BusinessOwner};
use schema::beings::Human;
character Martha: Human from Baker, BusinessOwner {
// Core identity
age: 34
skill_level: Master
specialty: Sourdough
// Professional
years_experience: 22
recipes_mastered: 150
can_teach: true
// Business
business_acumen: 0.8
leadership: 0.85
---backstory
Martha learned to bake from her grandmother, starting at age
twelve with simple bread recipes. She mastered sourdough and
pastries, eventually opening the most popular bakery in town.
---
---personality
A perfectionist in the kitchen who demands the best from her
ingredients and her team. Warm with customers but exacting
with her apprentices. Known for arriving at 4 AM to start
the morning batch.
---
}
```
## Next Steps
Now that Martha exists, let us give her something to do. In [Your First Behavior Tree](./03-first-behavior-tree.md), you will learn how characters make decisions.
---
**Reference**: For complete character syntax details, see the [Characters Reference](../reference/10-characters.md).