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
This commit is contained in:
2026-02-13 21:52:03 +00:00
parent 80332971b8
commit 16deb5d237
290 changed files with 90316 additions and 5827 deletions

View File

@@ -0,0 +1,210 @@
# Behavior Tree Keyword Implementation Status
**Task:** #7 - Implement behavior tree keyword transformation system
**Status:** In Progress (60% complete)
**Date:** February 12, 2026
---
## ✅ Completed Work
### 1. Tree-sitter Grammar (`tree-sitter-storybook/grammar.js`)
- ✅ Updated `selector_node` to use `choose` keyword with optional label
- ✅ Updated `sequence_node` to use `then` keyword with optional label
- ✅ Added `condition_node` for `if(expr)` and `when(expr)`
- ✅ Added `decorator_node` with full parameter support
- ✅ Added `decorator_keyword` enumeration
- ✅ Added `decorator_params` for all parameter types
- ✅ Updated `subtree_node` to use `include` keyword
- ✅ Extended `duration` pattern to support days (`d`)
### 2. AST Structures (`src/syntax/ast.rs` + `storybook/src/syntax/ast.rs`)
- ✅ Restructured `BehaviorNode::Selector` with label support
- ✅ Restructured `BehaviorNode::Sequence` with label support
- ✅ Added `BehaviorNode::Decorator` with typed decorators
- ✅ Created `DecoratorType` enum with 10 variants
- ✅ Created `Duration` struct with `DurationUnit` enum
- ✅ Implemented `Duration::to_milliseconds()` conversion
### 3. LALRPOP Parser (`src/syntax/parser.lalrpop`)
- ✅ Updated `BehaviorNode` choice to include new node types
- ✅ Implemented `SelectorNode` with `choose` keyword and optional label
- ✅ Implemented `SequenceNode` with `then` keyword and optional label
- ✅ Implemented `ConditionNode` for `if`/`when` expressions
- ✅ Implemented all 10 decorator parsers:
- `DecoratorRepeat` (infinite)
- `DecoratorRepeatN(n)`
- `DecoratorRepeatRange(min..max)`
- `DecoratorInvert`
- `DecoratorRetry(n)`
- `DecoratorTimeout(duration)`
- `DecoratorCooldown(duration)`
- `DecoratorGuard(expr)`
- `DecoratorSucceedAlways`
- `DecoratorFailAlways`
- ✅ Updated `SubTreeNode` to use `include` keyword
### 4. Lexer Tokens (`src/syntax/lexer.rs` + `storybook/src/syntax/lexer.rs`)
- ✅ Added `Choose` token
- ✅ Added `Then` token
- ✅ Added `If` token
- ✅ Added `When` token
- ✅ Added `Repeat` token
- ✅ Added `Invert` token
- ✅ Added `Retry` token
- ✅ Added `Timeout` token
- ✅ Added `Cooldown` token
- ✅ Added `Guard` token
- ✅ Added `SucceedAlways` token
- ✅ Added `FailAlways` token
### 5. Example Files
- ✅ Created `examples/new-syntax-demo.sb` with comprehensive demonstrations
---
## 🚧 In Progress / Pending
### 6. Fix Compilation Errors
The AST changes will break existing code that pattern-matches on `BehaviorNode`:
- [ ] Update all `match BehaviorNode::Selector(nodes)` to `BehaviorNode::Selector { label, children }`
- [ ] Update all `match BehaviorNode::Sequence(nodes)` to `BehaviorNode::Sequence { label, children }`
- [ ] Update all `match BehaviorNode::Decorator(name, child)` to `BehaviorNode::Decorator { decorator_type, child }`
- [ ] Check files:
- `src/resolve/validate.rs`
- `src/resolve/types.rs`
- `src/types.rs`
- LSP code in `storybook/src/lsp/`
- Test files
### 7. Compiler / SBIR Generation
- [ ] Update SBIR node type encoding for decorators
- [ ] Implement serialization for `DecoratorType` variants
- [ ] Implement `Duration` serialization
- [ ] Update compiler to handle new AST structures
- [ ] Test SBIR output for correctness
### 8. Testing
- [ ] Rebuild Tree-sitter grammar (`npm run build` or similar)
- [ ] Test parsing `examples/new-syntax-demo.sb`
- [ ] Add unit tests for each decorator type
- [ ] Add integration tests for nested decorators
- [ ] Test round-trip: parse → compile → decompile
### 9. Example Migration
- [ ] Migrate `examples/alice-in-wonderland/world/characters/white_rabbit.sb`
- [ ] Migrate `examples/alice-in-wonderland/world/characters/mad_tea_party.sb` (add `repeat` decorator)
- [ ] Migrate `examples/alice-in-wonderland/world/characters/cheshire_cat.sb` (add decorators)
- [ ] Migrate `examples/alice-in-wonderland/world/characters/royal_court.sb` (add `repeat` decorators)
- [ ] Migrate `examples/alice-in-wonderland/world/characters/caterpillar.sb`
- [ ] Migrate `tests/examples/behavior_and_lifearc.sb`
- [ ] Update test corpus in `tree-sitter-storybook/test/corpus/behaviors.txt`
### 10. Documentation
- [ ] Update `design.md` Section 6 with new syntax
- [ ] Create migration guide
- [ ] Add tutorial examples highlighting named nodes
- [ ] Update CHANGELOG with breaking changes
- [ ] Prepare handoff notes for language documentation agent
---
## 📊 Progress Metrics
**Overall Completion:** 60%
**By Phase:**
- Phase 1 (Grammar & Parser): 100% ✅
- Phase 2 (AST & Compiler): 70% (AST done, compiler pending)
- Phase 3 (Examples & Tests): 10% (example created, migration pending)
- Phase 4 (Documentation): 0%
**By Component:**
- Grammar: 100% ✅
- AST: 100% ✅
- Lexer: 100% ✅
- Parser: 100% ✅
- Compilation fixes: 0%
- Compiler/SBIR: 0%
- Testing: 10%
- Migration: 0%
- Documentation: 0%
---
## 🎯 Next Immediate Actions
1. **Find and fix compilation errors** from AST changes
2. **Update compiler** to handle new `DecoratorType` enum
3. **Test parsing** the new syntax example
4. **Migrate one example** (White Rabbit) to validate end-to-end
5. **Add unit tests** for decorator parsing
---
## 📝 Design Decisions Implemented
Following Sienna's feedback from design review:
**Use `choose` only** (not `selector`)
**Use `then` only** (not `sequence`)
**Remove @ prefix for actions**
**Use `include` for subtrees**
**Named nodes are prominent** (optional label on choose/then)
**Decorators approved** (all 10 types implemented)
**No backward compatibility** (clean break from symbolic syntax)
---
## 🔄 Files Modified
**Grammar:**
- `tree-sitter-storybook/grammar.js`
**AST:**
- `src/syntax/ast.rs`
- `storybook/src/syntax/ast.rs`
**Parser:**
- `src/syntax/parser.lalrpop`
**Lexer:**
- `src/syntax/lexer.rs`
- `storybook/src/syntax/lexer.rs`
**Examples:**
- `examples/new-syntax-demo.sb` (new)
---
## 🐛 Known Issues / Blockers
**Compilation Errors Expected:**
The AST structure changes will cause compilation errors in any code that pattern-matches on `BehaviorNode`. These need to be fixed before the code will compile.
**Files Likely Affected:**
- `src/resolve/validate.rs` - behavior tree validation
- `src/resolve/types.rs` - type resolution
- `src/types.rs` - type definitions
- `storybook/src/lsp/semantic_tokens.rs` - LSP highlighting
- `storybook/src/lsp/navigation_tests.rs` - LSP tests
- Test files with behavior tree examples
**Resolution Strategy:**
1. Attempt to compile
2. Fix each compilation error by updating pattern matches
3. Test that fixes maintain correct behavior
4. Coordinate with LSP agent if LSP changes are extensive
---
## 📚 Resources
**Design Document:** `/Users/sienna/Development/storybook/design/behavior-tree-keywords-design.md`
**Example File:** `/Users/sienna/Development/storybook/examples/new-syntax-demo.sb`
**TEAM PLAN:** `/Users/sienna/Development/storybook/TEAM_PLAN.md` (Task #7)
---
**Last Updated:** 2026-02-12
**Next Update:** After fixing compilation errors

File diff suppressed because it is too large Load Diff

160
design/color-palette.md Normal file
View File

@@ -0,0 +1,160 @@
# Storybook Editor Color Palette
> Aubergine sophistication meets gold energy
## Primary Colors (Aubergine Foundation)
```
████ aubergine-900 #1a0f1e RGB(26, 15, 30) Background (darkest)
████ aubergine-800 #2b1a33 RGB(43, 26, 51) Surface (panels, cards)
████ aubergine-750 #382444 RGB(56, 36, 68) Alternate row color
████ aubergine-700 #3d2447 RGB(61, 36, 71) Surface hover
████ aubergine-600 #4f2e5b RGB(79, 46, 91) Borders, dividers
████ aubergine-500 #61386f RGB(97, 56, 111) Subtle highlights
████ aubergine-400 #805793 RGB(128, 87, 147) Active elements
████ aubergine-300 #9f76a7 RGB(159,118,167) Muted text, info
```
## Accent Colors (Gold/Orange)
```
████ gold-600 #e89350 RGB(232,147, 80) Deeper accent (optional)
████ gold-500 #f4a261 RGB(244,162, 97) PRIMARY ACCENT ⭐
████ gold-400 #f6b47a RGB(246,180,122) Hover state
████ gold-300 #f8c594 RGB(248,197,148) Pressed/active state
████ gold-200 #fad6ad RGB(250,214,173) Very subtle highlight
```
## Neutral Colors
```
████ cream #fdf8f3 RGB(253,248,243) Primary text, high contrast
████ warm-gray-100 #e8e3dd RGB(232,227,221) Secondary text
████ warm-gray-200 #d1cbc3 RGB(209,203,195) Tertiary text
████ warm-gray-400 #8b8680 RGB(139,134,128) Muted text, placeholders
████ warm-gray-700 #4a4845 RGB(74, 72, 69) Disabled elements
████ charcoal #1f1f1f RGB(31, 31, 31) Pure dark (code bg)
```
## Semantic Colors
```
████ success-light #8ab864 RGB(138,184,100) Success hover
████ success #6a994e RGB(106,153, 78) Validation passed, success ✓
████ success-dark #558039 RGB(85, 128, 57) Success pressed
████ warning-light #f6b47a RGB(246,180,122) Warning hover (reuse gold-400)
████ warning #f4a261 RGB(244,162, 97) Warning, attention ⚠
████ warning-dark #e89350 RGB(232,147, 80) Warning pressed
████ error-light #e54545 RGB(229, 69, 69) Error hover
████ error #d62828 RGB(214, 40, 40) Parse errors, failures ✗
████ error-dark #b81e1e RGB(184, 30, 30) Error pressed
████ info #9f76a7 RGB(159,118,167) Info, hints (reuse aubergine-300)
```
## Color Combinations (Contrast Ratios)
### Text on Backgrounds
| Foreground | Background | Ratio | Grade | Use |
|------------|------------|-------|-------|-----|
| cream | aubergine-900 | 15.2:1 | AAA | Primary text |
| warm-gray-100 | aubergine-900 | 11.8:1 | AAA | Secondary text |
| warm-gray-400 | aubergine-900 | 4.9:1 | AA | Muted text |
| gold-500 | aubergine-900 | 7.1:1 | AA Large | Accent text |
| aubergine-900 | gold-500 | 7.1:1 | AA Large | Gold buttons |
### Interactive Elements
| Element | Default | Hover | Active | Focus |
|---------|---------|-------|--------|-------|
| Primary Button | gold-500 bg | gold-400 bg | gold-300 bg | gold-500 + glow |
| Secondary Button | transparent | aubergine-700 | aubergine-600 | gold-500 border |
| Input Field | aubergine-800 | - | - | gold-500 border |
| List Item | transparent | aubergine-700 | aubergine-600 | gold-500 left border |
## Usage Guidelines
### Do's ✓
- Use **aubergine-900** for main background
- Use **aubergine-800** for panels and cards
- Use **cream** for all primary text
- Use **gold-500** sparingly for accents (buttons, highlights, selected states)
- Use semantic colors (success, error, warning) only for their purpose
- Maintain visual hierarchy with size + weight + color
### Don'ts ✗
- Don't use gold for large backgrounds (overwhelming)
- Don't use more than 2-3 colors in a single component
- Don't rely on color alone for information (use icons + text)
- Don't use pure black (#000) or pure white (#fff)
- Don't mix warm and cool grays
## Code Syntax Highlighting
Muted versions of semantic colors on dark background:
```rust
// Example syntax theme
Keywords: #f4a261 (gold-500) - fn, let, pub, impl
Types: #9f76a7 (aubergine-300) - String, Vec, Option
Functions: #fad6ad (gold-200) - function_name()
Strings: #8ab864 (success-light) - "hello"
Numbers: #f6b47a (gold-400) - 42, 3.14
Comments: #8b8680 (warm-gray-400) - // comment
Operators: #e8e3dd (warm-gray-100) - +, =, ->
Punctuation: #d1cbc3 (warm-gray-200) - {}, (), ;
```
## Gradients (Optional, Use Sparingly)
```
Gold Shimmer (for loading states):
linear-gradient(90deg,
gold-500 0%,
gold-400 50%,
gold-500 100%)
Aubergine Depth (for hero sections):
linear-gradient(180deg,
aubergine-800 0%,
aubergine-900 100%)
```
## Opacity Scale
For overlays and transparency:
```
10%: rgba(color, 0.1) - Very subtle tint
20%: rgba(color, 0.2) - Subtle overlay
40%: rgba(color, 0.4) - Muted element
60%: rgba(color, 0.6) - Semi-transparent
80%: rgba(color, 0.8) - Mostly opaque
```
## Color Psychology
| Color | Emotion | Usage |
|-------|---------|-------|
| Aubergine | Sophisticated, creative, mysterious | Base, establishes tone |
| Gold | Energetic, optimistic, valuable | Accents, calls-to-action |
| Cream | Calm, clean, readable | Text, content |
| Green | Success, growth, go | Validation, success states |
| Red | Error, stop, urgent | Errors, destructive actions |
## Accessibility Notes
- All text meets **WCAG AAA** for contrast
- Gold accent meets **WCAG AA** for large text
- Focus indicators are clearly visible (gold-500 + glow)
- Never use color as the only indicator (pair with icons/text)
- Test with colorblind simulators (deuteranopia, protanopia)
---
*Pair this palette with Geist (UI) and Monaspace Neon (code) for optimal effect.*

365
design/layout-mockup.txt Normal file
View File

@@ -0,0 +1,365 @@
STORYBOOK EDITOR - LAYOUT MOCKUPS
═══════════════════════════════════════════════════════════════════════════════
Color Legend:
████ aubergine-900 (background)
████ aubergine-800 (panels)
████ gold-500 (accents)
OPTION 1: THREE-COLUMN LAYOUT (Wide Screen Focus)
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ ⚡ Storybook ◉ ○ ○ [Validate] [Save] │ aubergine-800
├─────────┬───────────────────────────────────────────────────┬───────────────┤
│ FILES │ EDITOR │ INSPECTOR │
│ │ │ │
│ 📁 alice│ character WhiteRabbit: Rabbit from Wonderland... │ WhiteRabbit │
│ └─ 📁 w│ │ ─────────────│
│ ├─ ch│ use schema::core_enums::{Size, EmotionalState}; │ │
│ ├─ ch│ use schema::templates::WonderlandCreature; │ Type: │
│ └─ wh│ │ Character │
│ 📁 schem│ character WhiteRabbit: Rabbit from WonderlandCr...│ │
│ └─ temp│ // Physical traits │ Species: │
│ │ current_size: small │ Rabbit │
│ [Search]│ wears_waistcoat: true │ │
│ │ has_pocket_watch: true │ Templates: │
│ Recent │ │ • WonderlandC.│
│ ───── │ // Personality │ • CourtMember │
│ • white│ emotional_state: frightened │ │
│ • alice│ awareness_of_absurdity: 0.3 │ Fields: 12 │
│ │ │ Prose: 1 │
│ │ ---backstory │ │
│ │ Always late, always anxious. Herald of │ Validation │
│ │ the Queen, perpetually checking his │ ─────────────│
│ │ pocket watch. │ ✓ All valid │
│ │ --- │ │
│ 240px │ │ 320px │
├─────────┴───────────────────────────────────────────────────┴───────────────┤
│ 🟢 Ready alice-in-wonderland (main) 12 characters, 7 relationships │
└─────────────────────────────────────────────────────────────────────────────┘
OPTION 2: TWO-COLUMN WITH BOTTOM DIAGNOSTICS
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ ⚡ Storybook Editor 🔍 Search ✓ Validate 💾 Save ⚙️ │
├─────────┬───────────────────────────────────────────────────────────────────┤
│ FILES │ EDITOR │
│ │ │
│ 📂 world│ character MadHatter: Human from MadTeaPartyMember { │
│ ├─ 📂 c│ │
│ │ ├─ a│ // Physical traits │
│ │ ├─ w│ current_size: normal │
│ │ └─ m│ wears_top_hat: true ┌──────────────┐│
│ ├─ 📂 i│ hat_size_label: "10/6" │ QUICK ACTIONS││
│ └─ 📂 r│ │ ────────────│││
│ │ // Personality │ Add Field ││
│ 📂 schema│ emotional_state: confused │ Add Prose ││
│ ├─ core│ follows_logic: false │ Duplicate ││
│ ├─ temp│ awareness_of_absurdity: 0.1 │ Delete Char ││
│ └─ spec│ │ View Graph ││
│ │ // Tea party state └──────────────┘│
│ [+ New] │ stuck_at_teatime: true │
│ │ current_seat_position: 1 │
│ 280px │ │
├─────────┼───────────────────────────────────────────────────────────────────┤
│ DIAGNOSTICS & VALIDATION │
│ ──────────────────────────────────────────────────────────────────────────│
│ ✓ No errors (validated 0.3s ago) [Run Tests] │
│ │
│ INFO: MadHatter inherits 8 fields from MadTeaPartyMember │
│ INFO: Cross-file reference to schema/templates.sb resolved │
│ │
│ 180px │
└─────────────────────────────────────────────────────────────────────────────┘
OPTION 3: FOCUSED SINGLE-PANEL (Mobile/Compact)
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ ☰ WhiteRabbit.sb ✓ Valid 💾 Save │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ use schema::templates::WonderlandCreature; │
│ │
│ character WhiteRabbit: Rabbit from WonderlandCreature { │
│ // Physical traits │
│ current_size: small │
│ wears_waistcoat: true │
│ has_pocket_watch: true │
│ │
│ // Personality │
│ emotional_state: frightened │
│ awareness_of_absurdity: 0.3 │
│ │
│ ---backstory │
│ Always late, always anxious. │
│ --- │
│ } │
│ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ ← Back to Files Templates: WonderlandCreature, CourtMember │
└─────────────────────────────────────────────────────────────────────────────┘
DETAILED THREE-COLUMN BREAKDOWN
═══════════════════════════════════════════════════════════════════════════════
┌──────────────────────── TITLE BAR (48px) ───────────────────────────────────┐
│ │
│ ⚡ Storybook Editor alice-in-wonderland ◉ Validate │
│ ↑ ↑ ↑ │
│ Logo + Title Project Name Primary CTA │
│ (gold accent) (muted) (gold button)│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────── LEFT: FILE BROWSER (240-320px, resizable) ─────────────────────┐
│ │
│ FILES [🔍] [+] │
│ ═════ │
│ │
│ 📂 alice-in-wonderland ← Project root │
│ ├─ 📂 world ← Expandable tree │
│ │ ├─ 📂 characters │
│ │ │ ├─ 📄 alice.sb │
│ │ │ ├─ 📄 white_rabbit.sb ← Selected (gold left border) │
│ │ │ ├─ 📄 cheshire_cat.sb │
│ │ │ └─ 📄 mad_tea_party.sb │
│ │ ├─ 📂 institutions │
│ │ └─ 📂 relationships │
│ └─ 📂 schema │
│ ├─ 📄 core_enums.sb │
│ ├─ 📄 templates.sb │
│ └─ 📄 beings.sb │
│ │
│ ───────────────────────── │
│ │
│ RECENT ← Collapsible section │
│ • white_rabbit.sb │
│ • alice.sb │
│ • wonderland_relationships.sb │
│ │
│ ───────────────────────── │
│ │
│ [+ New Character] ← Quick actions │
│ [+ New Relationship] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────── CENTER: CODE EDITOR (flex, main area) ─────────────────────┐
│ │
│ white_rabbit.sb Modified • Auto-save: on │
│ ━━━━━━━━━━━━━━━━ ↑ File tab │
│ ↑ Status indicators │
│ ┌─ Line numbers │
│ │ │
│ 1 //! White Rabbit: The anxious herald of Wonderland │
│ 2 │
│ 3 use schema::core_enums::{Size, EmotionalState}; │
│ 4 use schema::templates::WonderlandCreature; │
│ 5 │
│ 6 character WhiteRabbit: Rabbit from WonderlandCreature { │
│ 7 // Physical traits │
│ 8 current_size: small │
│ 9 wears_waistcoat: true │
│ 10 has_pocket_watch: true │
│ 11 │
│ 12 // Personality │
│ 13 emotional_state: frightened │
│ 14 awareness_of_absurdity: 0.3 │
│ 15 │
│ 16 ---backstory ← Prose block marker │
│ 17 Always late, always anxious. Herald of (gold accent) │
│ 18 the Queen of Hearts, perpetually checking │
│ 19 his pocket watch and muttering about time. │
│ 20 --- │
│ 21 } │
│ 22 │
│ │
│ ┌─ Inline validation indicators │
│ └─ Line 6: ✓ WonderlandCreature template resolved │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌───────────── RIGHT: INSPECTOR/METADATA (280-400px, resizable) ─────────────┐
│ │
│ INSPECTOR [⚙️] │
│ ═════════ │
│ │
│ WhiteRabbit ← Current entity │
│ ━━━━━━━━━━━━ (gold underline) │
│ │
│ Type: Character │
│ Species: Rabbit │
│ File: world/characters/white_rabbit.sb │
│ │
│ ───────────────────────── │
│ │
│ TEMPLATES │
│ • WonderlandCreature [View] ← Clickable │
│ • CourtMember [View] │
│ │
│ FIELDS (12) │
│ • current_size: small │
│ • wears_waistcoat: true │
│ • has_pocket_watch: true │
│ • emotional_state: frightened │
│ • awareness_of_absurdity: 0.3 │
│ • loyalty_to_queen: 0.95 │
│ ... [6 more] │
│ │
│ PROSE BLOCKS (1) │
│ • backstory (47 words) │
│ │
│ ───────────────────────── │
│ │
│ VALIDATION ✓ │
│ All checks passed │
│ Last validated: 2s ago │
│ │
│ [◉ Validate Now] ← Gold button │
│ │
│ ───────────────────────── │
│ │
│ RELATIONSHIPS (2) │
│ • AliceAndWhiteRabbit [View] │
│ • WhiteRabbit_Anxiety [View] │
│ │
│ [+ Add Relationship] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────── BOTTOM: STATUS BAR (32px) ──────────────────────────┐
│ │
│ 🟢 Ready alice-in-wonderland (main) 12 char 7 rel Ln 14 Col 8│
│ ↑ ↑ ↑ ↑ │
│ Status Project & Branch Stats Cursor │
│ (green) (muted text) (muted) (muted) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
ALTERNATIVE: RELATIONSHIP GRAPH VIEW
═══════════════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────────────────┐
│ ⚡ Storybook Editor Relationship Graph [Code] [Graph] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ●─────── pursuer ────────● │
│ Alice WhiteRabbit │
│ ● ● │
│ ╲
│ ╲ seeker_of_
│ ╲ guidance
│ ╲
│ ●─────────────● │
│ CheshireCat │
│ ● │
│ │ │
│ amused │
│ observer │
│ │ │
│ ● │
│ MadHatter ●────●────● MarchHare │
│ co- │
│ conspirators │
│ │
│ [Legend: ● Character ── Relationship Gold = Selected] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
UI ELEMENT DETAILS
═══════════════════════════════════════════════════════════════════════════════
┌─ Button Styles ──────────────────────────────────────────────────────────┐
│ │
│ PRIMARY (Gold): [◉ Validate] │
│ ↑ gold-500 bg, aubergine-900 text │
│ │
│ SECONDARY (Ghost): [○ Save] │
│ ↑ transparent bg, aubergine-600 border │
│ │
│ TERTIARY (Text): View Edit Delete │
│ ↑ gold-500 text, no background │
│ │
│ ICON ONLY: [🔍] [+] [⚙️] │
│ ↑ 32x32px touch target │
│ │
└───────────────────────────────────────────────────────────────────────────┘
┌─ Input Field ────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Search files... │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↑ aubergine-800 bg, warm-gray-400 placeholder │
│ ↑ Focus: gold-500 border + glow │
│ │
└───────────────────────────────────────────────────────────────────────────┘
┌─ List Item States ───────────────────────────────────────────────────────┐
│ │
│ 📄 alice.sb ← Default (transparent bg) │
│ 📄 white_rabbit.sb ← Hover (aubergine-700 bg) │
│ ┃ 📄 cheshire_cat.sb ← Selected (gold-500 left border) │
│ 📄 mad_tea_party.sb │
│ │
└───────────────────────────────────────────────────────────────────────────┘
┌─ Toast Notification ─────────────────────────────────────────────────────┐
│ │
│ ┌───────────────────────────────────────────────────┐ ← Top-right │
│ │ ✓ Validation passed [×] │ position │
│ │ All 12 characters valid │ │
│ └───────────────────────────────────────────────────┘ │
│ ↑ aubergine-700 bg, green icon, auto-dismiss 3s │
│ │
└───────────────────────────────────────────────────────────────────────────┘
SPACING REFERENCE (8px grid)
═══════════════════════════════════════════════════════════════════════════════
Panel Padding: 24px (3 × 8px)
Section Spacing: 16px (2 × 8px)
Element Spacing: 8px (1 × 8px)
Tight Spacing: 4px (0.5 × 8px)
Button Padding: 8px × 16px (vertical × horizontal)
Input Padding: 8px × 12px
List Item Height: 32px (4 × 8px)
Title Bar: 48px (6 × 8px)
Status Bar: 32px (4 × 8px)
INTERACTION PATTERNS
═══════════════════════════════════════════════════════════════════════════════
File Selection:
Click file → Highlight with gold border → Load in editor → Show metadata
Validation:
Press Validate → Spinner appears → Success/error toast → Update badges
Auto-save:
Type → 2s debounce → Save indicator → "Saved" confirmation
Panel Resize:
Hover divider → Cursor changes → Drag → Live resize → Snap to min/max
Focus Navigation:
Tab → Next focusable → Visible gold outline
Shift+Tab → Previous focusable
Escape → Close modal/blur input
═══════════════════════════════════════════════════════════════════════════════
END OF MOCKUPS
Which layout speaks to you? We can mix and match elements.
The three-column is great for wide screens, two-column is more focused.

View File

@@ -0,0 +1,486 @@
# Template Merge Implementation Notes
**Author:** Resource Linking Architect
**Date:** 2026-02-12
**Purpose:** Implementation planning for Phase 3 (Resolution)
---
## Core Merge Algorithm
### Data Structures
```rust
// In resolve/merge.rs
/// Tracks behavior links during merge to detect overrides
struct BehaviorMergeContext {
seen_behaviors: HashMap<String, BehaviorLink>, // behavior_name -> link
result: Vec<BehaviorLink>,
warnings: Vec<MergeWarning>,
}
enum MergeWarning {
DefaultConflict {
character_behavior: String,
template_behavior: String,
},
PriorityConflict {
behavior: String,
character_priority: Priority,
template_priority: Priority,
},
}
```
### Merge Function Signature
```rust
pub fn merge_behavior_links(
character_links: Vec<BehaviorLink>,
template_links: Vec<BehaviorLink>,
character_name: &str,
template_name: &str,
) -> Result<(Vec<ResolvedBehaviorLink>, Vec<MergeWarning>), MergeError> {
// Implementation
}
```
### Step-by-Step Algorithm
```rust
fn merge_behavior_links(
character_links: Vec<BehaviorLink>,
template_links: Vec<BehaviorLink>,
character_name: &str,
template_name: &str,
) -> Result<(Vec<ResolvedBehaviorLink>, Vec<MergeWarning>), MergeError> {
let mut ctx = BehaviorMergeContext {
seen_behaviors: HashMap::new(),
result: Vec::new(),
warnings: Vec::new(),
};
// Step 1: Add all character links (highest precedence)
for link in character_links {
let behavior_name = link.tree.join("::");
// Check for duplicate behavior in character itself
if ctx.seen_behaviors.contains_key(&behavior_name) {
return Err(MergeError::DuplicateBehavior {
behavior: behavior_name,
source: character_name.to_string(),
});
}
ctx.seen_behaviors.insert(behavior_name.clone(), link.clone());
ctx.result.push(link);
}
// Step 2: Add template links that aren't overridden
for link in template_links {
let behavior_name = link.tree.join("::");
if let Some(char_link) = ctx.seen_behaviors.get(&behavior_name) {
// Character overrides this behavior - check for conflicts
// Check priority conflict
if let (Some(char_pri), Some(tmpl_pri)) = (&char_link.priority, &link.priority) {
if char_pri != tmpl_pri {
ctx.warnings.push(MergeWarning::PriorityConflict {
behavior: behavior_name.clone(),
character_priority: char_pri.clone(),
template_priority: tmpl_pri.clone(),
});
}
}
// Skip template link (already have character's version)
continue;
}
// No override, add template link
ctx.result.push(link);
}
// Step 3: Check for default conflicts
let char_defaults: Vec<_> = ctx.result.iter()
.filter(|link| link.is_default)
.take(2) // Only need to check if >1
.collect();
if char_defaults.len() > 1 {
ctx.warnings.push(MergeWarning::DefaultConflict {
// ... warning details
});
}
Ok((ctx.result, ctx.warnings))
}
```
### Multi-Level Template Merge
```rust
pub fn resolve_template_hierarchy(
character: &Character,
templates: &HashMap<String, Template>,
) -> Result<(Vec<BehaviorLink>, Vec<ScheduleLink>), MergeError> {
// Step 1: Build template chain (deepest first)
let mut template_chain = Vec::new();
let mut current_template_name = character.template.clone();
while let Some(tmpl_name) = current_template_name {
let template = templates.get(&tmpl_name)
.ok_or(MergeError::UnresolvedTemplate { name: tmpl_name.clone() })?;
template_chain.push(template);
current_template_name = template.parent_template.clone();
}
// Step 2: Merge from deepest template up to character
template_chain.reverse(); // Now [deepest, ..., direct parent]
let mut merged_behaviors = Vec::new();
let mut merged_schedules = Vec::new();
for template in template_chain {
let (behaviors, warnings) = merge_behavior_links(
merged_behaviors,
template.behavior_links.clone(),
character.name,
&template.name,
)?;
merged_behaviors = behaviors;
// TODO: emit warnings
// Same for schedules...
}
// Step 3: Merge character on top
let (final_behaviors, warnings) = merge_behavior_links(
character.behavior_links.clone(),
merged_behaviors,
character.name,
"character",
)?;
Ok((final_behaviors, merged_schedules))
}
```
---
## Complex Merge Scenarios to Test
### Scenario 1: Simple Override
```storybook
template Worker {
uses behaviors: [A, B, C]
}
character Martha from Worker {
uses behaviors: [B, D] // Override B, add D
}
// Expected: [B(Martha), D, A, C]
// A and C come from Worker, B is Martha's version
```
### Scenario 2: Multi-Level with Overrides
```storybook
template Base {
uses behaviors: [A, B]
}
template Mid from Base {
uses behaviors: [B, C] // Override B from Base
}
character Char from Mid {
uses behaviors: [C, D] // Override C from Mid
}
// Merge order:
// 1. Base: [A, B(Base)]
// 2. Mid merges on Base: [B(Mid), C, A]
// 3. Char merges on Mid: [C(Char), D, B(Mid), A]
```
### Scenario 3: Priority Changes Through Chain
```storybook
template Base {
uses behaviors: [{ tree: Rest, priority: high }]
}
template Mid from Base {
uses behaviors: [{ tree: Rest, priority: normal }] // Warning!
}
character Char from Mid {
uses behaviors: [{ tree: Rest, priority: low }] // Warning!
}
// Expected: [Rest(low)]
// Warnings:
// - Mid changed Rest priority from high to normal
// - Char changed Rest priority from normal to low
```
### Scenario 4: Condition Overrides
```storybook
template Worker {
uses behaviors: [
{ tree: Work, when: employed }
]
}
character Martha from Worker {
uses behaviors: [
{ tree: Work, when: at_bakery } // Override condition
]
}
// Expected: [Work(when: at_bakery)]
// Template's Work(when: employed) is completely replaced
```
### Scenario 5: Default Conflicts
```storybook
template Worker {
uses behaviors: [
{ tree: Idle, default: true }
]
}
character Martha from Worker {
uses behaviors: [
{ tree: Rest, default: true }
]
}
// Expected: [Rest(default), Idle(not default)]
// Warning: Both template and character define defaults
```
### Scenario 6: Empty Array Edge Case
```storybook
template Worker {
uses behaviors: [A, B, C]
}
character Martha from Worker {
uses behaviors: [] // What does this mean?
}
// If empty = "clear all": []
// If empty = "ignore, inherit": [A, B, C]
// Waiting for Sienna's decision (Question 1)
```
### Scenario 7: Diamond Inheritance (Not Supported)
```storybook
template A { uses behaviors: [X] }
template B from A { uses behaviors: [Y] }
template C from A { uses behaviors: [Z] }
template D from B, C { ... } // ERROR: Multiple inheritance not supported
```
**Decision:** Single inheritance only (one parent template max).
---
## Error Message Design
### Error: Duplicate Behavior in Same Context
```
error: duplicate behavior definition
┌─ characters/martha.sb:10:9
10 │ { tree: BakeryWork, priority: normal }
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11 │ { tree: BakeryWork, priority: high }
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
= note: behavior 'BakeryWork' is already defined in this character
= help: remove one of the duplicate definitions or use different behaviors
```
### Warning: Priority Conflict in Template Merge
```
warning: behavior priority changed from template
┌─ characters/martha.sb:9:9
9 │ { tree: Rest, priority: low }
│ ^^^^^^^^^^^^^^^^
= note: template 'Worker' defines 'Rest' with priority 'high'
= note: character's priority (low) will override template's (high)
= help: if this is intentional, no action needed
```
### Warning: Multiple Defaults
```
warning: multiple default behaviors defined
┌─ characters/martha.sb:10:9
10 │ { tree: Rest, default: true }
│ ^^^^^^^^^^^^^^^
= note: template 'Worker' also defines a default behavior: 'Idle'
= note: character's default (Rest) will be used; template's (Idle) remains as non-default
= help: only one default is active at runtime
```
### Error: Unresolved Template
```
error: unresolved template reference
┌─ characters/martha.sb:1:25
1 │ character Martha from Workerr {
│ ^^^^^^^ template 'Workerr' not found
= help: did you mean 'Worker'? (defined in templates/worker.sb)
```
### Warning: Condition Override
```
warning: behavior condition changed from template
┌─ characters/martha.sb:9:9
9 │ { tree: Work, when: at_bakery }
│ ^^^^^^^^^^^^^^^^^^^
= note: template 'Worker' defines 'Work' with condition 'employed'
= note: character's condition will replace template's condition
```
---
## Testing Strategy
### Unit Tests
```rust
#[cfg(test)]
mod merge_tests {
use super::*;
#[test]
fn test_simple_merge() {
let char_links = vec![
behavior_link("BakeryWork", None, None),
];
let tmpl_links = vec![
behavior_link("BasicNeeds", Some(Priority::Critical), None),
behavior_link("Rest", Some(Priority::Normal), None),
];
let (result, warnings) = merge_behavior_links(
char_links, tmpl_links, "Martha", "Worker"
).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].tree, "BakeryWork");
assert_eq!(result[1].tree, "BasicNeeds");
assert_eq!(result[2].tree, "Rest");
assert!(warnings.is_empty());
}
#[test]
fn test_override_priority() {
let char_links = vec![
behavior_link("Rest", Some(Priority::Low), None),
];
let tmpl_links = vec![
behavior_link("Rest", Some(Priority::High), None),
];
let (result, warnings) = merge_behavior_links(
char_links, tmpl_links, "Martha", "Worker"
).unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0].priority, Some(Priority::Low));
assert_eq!(warnings.len(), 1);
assert!(matches!(warnings[0], MergeWarning::PriorityConflict { .. }));
}
#[test]
fn test_multi_level_merge() {
// Base -> Mid -> Char
// Test that merging works through chain
}
#[test]
fn test_default_conflict() {
// Both template and character define defaults
}
#[test]
fn test_empty_array() {
// Waiting for Sienna's decision on semantics
}
}
```
### Integration Tests
```rust
#[test]
fn test_resolve_alice_wonderland() {
// Load Alice example with WonderlandCreature template
// Verify merged behaviors are correct
}
#[test]
fn test_three_level_inheritance() {
// Mortal -> Worker -> Baker -> Martha
// Verify all behaviors present and priorities correct
}
```
---
## Performance Considerations
### Merge Complexity
- Single template: O(n + m) where n=char links, m=template links
- k-level templates: O(k * (n + m))
- Typical case: k=1-3, n+m < 20, negligible overhead
### Optimization Opportunities
1. **Cache merged templates**: If Template X is used by multiple characters, cache its fully-merged result
2. **Early termination**: If character defines no links, skip merge entirely
3. **Lazy merging**: Only merge when links are actually accessed at runtime
**Decision:** Start with simple O(k*n) implementation. Optimize only if profiling shows bottleneck.
---
## Edge Cases Checklist
- [x] Character overrides all template behaviors
- [x] Character overrides some template behaviors
- [x] Character adds new behaviors to template
- [x] Multi-level template chain
- [x] Priority conflicts through chain
- [x] Condition overrides
- [x] Multiple defaults
- [ ] Empty array semantics (awaiting Sienna)
- [x] Diamond inheritance (not supported, single parent only)
- [x] Circular template references (should be caught in validation)
- [x] Template references non-existent parent (error)
- [x] Behavior name resolution fails (error)
---
**Status:** Implementation notes complete, awaiting Checkpoint 2 approval to begin coding.

View File

@@ -0,0 +1,658 @@
# Resource Linking System - Checkpoint 2 Addendum
**Author:** Resource Linking Architect
**Date:** 2026-02-12
**Status:** Draft for Checkpoint 2 Review
**Version:** 0.3
**Addresses:** Checkpoint 1 feedback from Sienna
---
## Changes from Checkpoint 1
This addendum addresses two required changes from Sienna's Checkpoint 1 review:
1. **Template Merging Support** (instead of all-or-nothing replacement)
2. **Dual Operator Support** (`==` and `is` both work)
---
## 1. Template Merging Design
### 1.1 The Problem
**Original Design (Rejected):**
```storybook
template Worker {
uses behaviors: [HandleBasicNeeds, RestWhenTired]
}
character Martha: Human from Worker {
uses behaviors: [BakeryWork] // REPLACES Worker behaviors entirely
}
// Result: Only [BakeryWork] - lost HandleBasicNeeds and RestWhenTired
```
**Requested Behavior:**
Martha should get BOTH Worker behaviors AND her own behaviors, composed together.
### 1.2 Proposed Merge Algorithm
**Merge Semantics:**
- Template links and character links are **concatenated**
- Character links come **first** (evaluated before template links) (no template links come first since that's the "base class")
- If same behavior appears in both, character's version **overrides** template's version
- Priority and conditions are preserved from each source
**Example:**
```storybook
template Worker {
uses behaviors: [
{ tree: HandleBasicNeeds, priority: critical }
{ tree: RestWhenTired, priority: normal }
{ tree: Idle, priority: low }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: BakeryWork, priority: normal }
{ tree: Idle, priority: normal } // Overrides Worker's Idle
]
}
// Merged result:
// [
// { tree: BakeryWork, priority: normal } // From Martha
// { tree: Idle, priority: normal } // From Martha (overrides template)
// { tree: HandleBasicNeeds, priority: critical } // From Worker
// { tree: RestWhenTired, priority: normal } // From Worker
// ]
```
### 1.3 Merge Rules
**Rule 1: Concatenation**
- Merge = `character_links ++ template_links`
- Character links are evaluated first at runtime (higher precedence)
**Rule 2: Override by Name**
- If character defines a link to behavior `X`, template's link to `X` is ignored
- Match by behavior tree name (not by priority or condition)
- Allows character to "replace" template's version of a behavior
**Rule 3: Preserve Priority**
- Priority values are NOT automatically adjusted
- Character can define same behavior with different priority than template
- Runtime selection uses declared priorities as-is
**Rule 4: Preserve Conditions**
- Conditions are NOT merged with boolean operators
- Each link keeps its own condition
- If both have same behavior with different conditions, character's wins (override)
**Rule 5: Default Behavior**
- If both character and template define `default: true` for same link type, character's default wins
- Warning issued if both define defaults (even for different behaviors)
### 1.4 Conflict Resolution
**Conflict Type 1: Same Behavior, Different Priority**
```storybook
template Worker {
uses behaviors: [
{ tree: Rest, priority: high }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: Rest, priority: normal } // Character overrides
]
}
// Result: Martha's Rest(normal) wins, template's Rest(high) ignored
```
**Conflict Type 2: Same Behavior, Different Conditions**
```storybook
template Worker {
uses behaviors: [
{ tree: Work, when: employed }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: Work, when: at_bakery } // Character overrides
]
}
// Result: Martha's Work(when: at_bakery) wins
```
**Conflict Type 3: Multiple Defaults**
```storybook
template Worker {
uses behaviors: [
{ tree: Idle, default: true }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: Rest, default: true } // Warning!
]
}
// Warning: Both template and character define default behaviors
// Resolution: Character's default wins (Rest), template's Idle kept but not default
```
### 1.5 Multi-Level Template Inheritance
Templates can inherit from templates:
```storybook
template LivingBeing {
uses behaviors: [
{ tree: Breathe, priority: critical }
{ tree: Eat, priority: high }
]
}
template Worker from LivingBeing {
uses behaviors: [
{ tree: Work, priority: normal }
{ tree: Rest, priority: normal }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: BakeryWork, priority: normal }
]
}
// Merge chain: LivingBeing -> Worker -> Martha
// Result (in evaluation order):
// [
// BakeryWork(normal), // Martha
// Work(normal), // Worker
// Rest(normal), // Worker
// Breathe(critical), // LivingBeing
// Eat(high) // LivingBeing
// ]
```
**Merge Algorithm for Multi-Level:**
1. Start with deepest template (LivingBeing)
2. Merge next template (Worker) on top
3. Merge character on top
4. At each level, apply override-by-name rule
### 1.6 Explicit Override Syntax (Future Extension)
If we want more control, we could add explicit `override` keyword:
```storybook
character Martha: Human from Worker {
uses behaviors: [
{ tree: Rest, priority: low, override: true } // Explicit override
{ tree: BakeryWork, priority: normal }
]
}
```
**Recommendation:** Start without `override` keyword. Add later if needed.
### 1.7 Empty Array Semantics
**Question:** What if character defines empty array?
```storybook
template Worker {
uses behaviors: [HandleBasicNeeds, Rest]
}
character Martha: Human from Worker {
uses behaviors: [] // Empty!
}
```
**Option A:** Empty array means "use no behaviors" (clear template behaviors)
**Option B:** Empty array is treated as "not defined", inherit from template
**Recommendation:** **Option B** - Only non-empty arrays trigger override/merge. Empty arrays are same as omitted field. (empty array just means "empty array", i think if it's a zero-length array then we would treat it as "not defined")
### 1.8 Updated Merge Pseudocode
```rust
fn merge_behavior_links(
character_links: Vec<BehaviorLink>,
template_links: Vec<BehaviorLink>
) -> Vec<BehaviorLink> {
let mut result = Vec::new();
let mut seen_behaviors = HashSet::new();
// Add character links first (higher precedence)
for link in character_links {
let behavior_name = link.tree.join("::");
seen_behaviors.insert(behavior_name.clone());
result.push(link);
}
// Add template links that don't conflict
for link in template_links {
let behavior_name = link.tree.join("::");
if !seen_behaviors.contains(&behavior_name) {
result.push(link);
}
// else: skip, character already defined this behavior
}
result
}
fn merge_character_with_template(
char: Character,
template: Template
) -> ResolvedCharacter {
// Recursively merge if template has parent template
let template_links = if let Some(parent_template) = template.parent {
merge_behavior_links(template.behavior_links, parent_template.behavior_links)
} else {
template.behavior_links
};
// Merge character on top of (potentially already merged) template
let behavior_links = if !char.behavior_links.is_empty() {
merge_behavior_links(char.behavior_links, template_links)
} else {
template_links // Character doesn't define any, inherit all
};
// Same logic for schedule_links...
ResolvedCharacter { behavior_links, schedule_links, ... }
}
```
### 1.9 Validation Rules
**New Validations:**
1. **Warn on default conflicts:**
```
warning: multiple default behaviors defined
┌─ characters/martha.sb:8:5
8 │ uses behaviors: [
9 │ { tree: Rest, default: true }
= note: template 'Worker' also defines a default behavior: Idle
= help: only one default is used at runtime (character's takes precedence)
```
2. **Warn on priority conflicts (optional):**
```
warning: behavior priority changed from template
┌─ characters/martha.sb:9:9
9 │ { tree: Rest, priority: low }
= note: template 'Worker' defines Rest with priority: high
= help: character's priority (low) will override template's (high)
```
### 1.10 Examples
**Example 1: Simple Composition**
```storybook
template Villager {
uses behaviors: [
{ tree: BasicNeeds, priority: critical }
{ tree: Socialize, priority: normal }
{ tree: Sleep, priority: normal }
]
}
character Martha: Human from Villager {
uses behaviors: [
{ tree: BakeryWork, priority: normal }
]
}
// Martha gets: [BakeryWork, BasicNeeds, Socialize, Sleep]
```
**Example 2: Selective Override**
```storybook
template Villager {
uses behaviors: [
{ tree: BasicNeeds, priority: critical }
{ tree: Sleep, priority: normal }
]
uses schedule: VillagerSchedule
}
character Martha: Human from Villager {
uses behaviors: [
{ tree: Sleep, priority: low } // Override just Sleep
]
uses schedule: BakerSchedule // Override schedule
}
// Behaviors: [Sleep(low), BasicNeeds(critical)]
// Schedule: BakerSchedule (replaces VillagerSchedule)
```
**Example 3: Multi-Level Inheritance**
```storybook
template Mortal {
uses behaviors: [{ tree: Age, priority: critical }]
}
template Worker from Mortal {
uses behaviors: [{ tree: Work, priority: normal }]
}
template Baker from Worker {
uses behaviors: [{ tree: BakeBreed, priority: normal }]
}
character Martha: Human from Baker {
uses behaviors: [{ tree: ManageBakery, priority: normal }]
}
// Result: [ManageBakery, BakeBread, Work, Age]
```
---
## 2. Dual Operator Support (`==` and `is`)
### 2.1 The Request
Sienna wants both `==` and `is` to work for equality comparisons (like Python).
**Examples:**
```storybook
uses behaviors: [
{ tree: Giant, when: current_size == huge } // C-style
{ tree: Tiny, when: current_size is tiny } // Python-style
]
```
### 2.2 Semantic Equivalence
Both operators mean **equality test**:
- `current_size == huge` → true if current_size equals huge
- `current_size is tiny` → true if current_size equals tiny
- No distinction between "identity" and "equality" (like Python's `is` vs `==`)
- They're syntactic alternatives for readability
### 2.3 Grammar Update
```lalrpop
// In parser.lalrpop
CompOp: CompOp = {
">=" => CompOp::Gte,
"<=" => CompOp::Lte,
"==" => CompOp::Eq,
"is" => CompOp::Eq, // NEW - maps to same enum variant
"!=" => CompOp::Neq,
">" => CompOp::Gt,
"<" => CompOp::Lt,
};
```
**AST Representation:**
```rust
pub enum CompOp {
Eq, // Both == and is map to this
Neq,
Lt,
Gt,
Lte,
Gte,
}
```
No AST change needed - both `==` and `is` produce the same `CompOp::Eq`.
### 2.4 Negation
**Question:** Should we support `is not` as well as `!=`? (yes i want this)
```storybook
when: current_size is not huge // Python style
when: current_size != huge // C style
```
**Recommendation:** **Yes**, support `is not` for consistency with Python:
```lalrpop
CompOp: CompOp = {
">=" => CompOp::Gte,
"<=" => CompOp::Lte,
"==" => CompOp::Eq,
"is" => CompOp::Eq,
"is" "not" => CompOp::Neq, // NEW
"!=" => CompOp::Neq,
">" => CompOp::Gt,
"<" => CompOp::Lt,
};
```
### 2.5 Updated Examples
**All valid:**
```storybook
uses behaviors: [
{ tree: Giant, when: size == huge }
{ tree: Giant, when: size is huge }
{ tree: Tiny, when: size != tiny }
{ tree: Tiny, when: size is not tiny }
]
```
### 2.6 Documentation Update
Update language docs to show both styles:
> **Condition Expressions**
>
> Use `when:` clauses to specify conditions for link selection:
>
> ```storybook
> when: emotional_state == frightened // C-style equality
> when: emotional_state is frightened // Python-style equality
> when: size != normal // C-style inequality
> when: size is not normal // Python-style inequality
> ```
>
> Both `==` and `is` mean equality. Both `!=` and `is not` mean inequality.
> Choose whichever reads more naturally for your condition.
---
## 3. Updated Implementation Plan
### Phase 1: AST Extension (Week 1) - UNCHANGED
No changes from original design.
### Phase 2: Parser Implementation (Week 1-2) - UPDATED
**Original:**
1. Implement `BehaviorLinkStmt` and `ScheduleLinkStmt` grammar
2. Implement `BehaviorLinkSpec` and `ScheduleLinkSpec` parsing
3. Add link parsing to character, institution, template productions
4. Write parser tests for all link variations
**Updated:**
1. Implement `BehaviorLinkStmt` and `ScheduleLinkStmt` grammar
2. Implement `BehaviorLinkSpec` and `ScheduleLinkSpec` parsing
3. Add link parsing to character, institution, template productions
4. **Add `is` and `is not` to `CompOp` production** ← NEW
5. Write parser tests for all link variations
6. **Write tests for both `==`/`is` and `!=`/`is not`** ← NEW
### Phase 3: Resolution (Week 2) - UPDATED
**Original:**
1. Implement behavior/schedule name resolution in `resolve/names.rs`
2. Add priority validation
3. Add condition expression validation
4. Implement template merge logic for links in `resolve/merge.rs`
5. Write resolution tests
**Updated:**
1. Implement behavior/schedule name resolution in `resolve/names.rs`
2. Add priority validation
3. Add condition expression validation
4. **Implement template merge algorithm with override-by-name** ← UPDATED
5. **Add multi-level template merge support** ← NEW
6. **Add validation warnings for default/priority conflicts** ← NEW
7. Write resolution tests
8. **Write tests for merge edge cases** ← NEW
### Phase 4: Resolved Types (Week 2) - UNCHANGED
No changes from original design.
### Phase 5: Validation & Diagnostics (Week 3) - UPDATED
**Original:**
1. Implement semantic validation (single default, etc.)
2. Add helpful error messages with fuzzy matching
3. Add warnings for incomplete condition coverage
4. Write validation tests
**Updated:**
1. Implement semantic validation (single default, etc.)
2. Add helpful error messages with fuzzy matching
3. Add warnings for incomplete condition coverage
4. **Add warnings for merge conflicts (defaults, priorities)** ← NEW
5. Write validation tests
### Phase 6: Integration & Documentation (Week 3) - UPDATED
**Original:**
1. Update examples to use new linking syntax
2. Update language documentation
3. Run full test suite
4. Create migration examples (if backward compatibility breaks)
**Updated:**
1. Update examples to use new linking syntax
2. **Update examples to show template merging** ← NEW
3. **Update examples to show both `==` and `is` operators** ← NEW
4. Update language documentation
5. **Document merge algorithm for users** ← NEW
6. Run full test suite
7. Create migration examples (if backward compatibility breaks)
**Total Estimate:** Still 3 weeks (merge adds complexity but not significant time)
---
## 4. Updated Success Criteria
### Must Have
- [x] Unified `uses` keyword for behaviors and schedules
- [x] Single-link syntax works (`uses behavior: Name`)
- [x] Multi-link syntax works (`uses behaviors: [...]`)
- [x] Conditions supported (`when: expression`)
- [x] **Both `==` and `is` operators supported** ← NEW
- [x] **Both `!=` and `is not` operators supported** ← NEW
- [x] Priorities supported for behaviors
- [x] Default fallback supported (`default: true`)
- [x] **Template merging works (concatenation + override)** ← UPDATED
- [x] **Multi-level template inheritance works** ← NEW
- [x] Character linking works
- [x] Institution linking works
- [x] Parser produces correct AST
- [x] Resolver validates references
- [x] **Warnings for merge conflicts** ← NEW
- [x] Clear error messages
- [x] SBIR format defined
---
## 5. Open Questions for Sienna (Checkpoint 2)
### Question 1: Empty Array Semantics ("not defined)
What should this mean?
```storybook
template Worker {
uses behaviors: [HandleNeeds, Rest]
}
character Martha: Human from Worker {
uses behaviors: [] // Empty array!
}
```
**Option A:** Empty = clear template behaviors (Martha has NO behaviors)
**Option B:** Empty = ignore, inherit from template (same as omitting field)
**Recommendation:** Option B
### Question 2: Priority Conflict Warnings (lsp warning is more than fine, yellow squiggly, internal behavior is to override at the character level)
Should we warn when character changes priority of template behavior?
```storybook
template Worker { uses behaviors: [{ tree: Rest, priority: high }] }
character Martha from Worker { uses behaviors: [{ tree: Rest, priority: low }] }
```
**Option A:** Silent override (no warning)
**Option B:** Warn about priority change
**Option C:** Error (must use same priority)
**Recommendation:** Option A (silent) or Option B (warning)
### Question 3: `is not` Support (absolutely yes)
Should we support `is not` alongside `!=`?
**Recommendation:** Yes, for consistency with Python
### Question 4: Merge Validation Level (um... strict is prolly best tbh)
How strict should merge conflict validation be?
**Option A:** Errors on any conflict (strict)
**Option B:** Warnings only (permissive)
**Option C:** Silent (trust user)
**Recommendation:** Option B (warnings)
---
## 6. Summary of Changes
### From Checkpoint 1 to Checkpoint 2:
**Major Change 1: Template Merging**
- ❌ Old: All-or-nothing replacement
- ✅ New: Concatenation with override-by-name
- Character links evaluated first
- Template links added if not overridden
- Multi-level inheritance supported
**Major Change 2: Operator Support**
- ✅ Added: `is` as synonym for `==`
- ✅ Added: `is not` as synonym for `!=`
- No AST changes needed
- Parser accepts both styles
**Minor Changes:**
- Added merge conflict warnings
- Updated examples to show composition
- Updated implementation plan phases
---
**End of Checkpoint 2 Addendum**
**Next Step:** Review with user (Sienna) for approval, then proceed to implementation (Task #9).

View File

@@ -0,0 +1,921 @@
# Resource Linking System Design
**Author:** Resource Linking Architect
**Date:** 2026-02-12
**Status:** Ready for Checkpoint 1 Review
**Version:** 0.2
**Keyword Decision:** `uses` (approved by Sienna)
---
## Executive Summary
This document proposes a unified `uses` keyword system for associating behaviors and schedules with characters and institutions in the Storybook DSL. The design enables:
- Characters using one or more behaviors
- Characters using one or more schedules
- Institutions using behaviors (for institutional operations)
- Institutions using schedules (operating hours, seasonal variations)
- Conditional/contextual selection of linked resources
- Priority-based behavior selection at runtime
---
## 1. Design Goals
### Primary Goals
1. **Unified Syntax**: Single `uses` keyword for both behaviors and schedules
2. **Simple Default Case**: Most common use case should be simple one-liner
3. **Powerful When Needed**: Support complex multi-link scenarios with conditions
4. **Clear Semantics**: Unambiguous about which behavior/schedule applies when
5. **Backward Compatible**: Existing .sb files continue to parse and work
### Non-Goals
1. **Not for Relationships**: Relationship linking remains separate (already exists)
2. **Not Inline Definitions**: Can only link to named behaviors/schedules, not define inline
3. **Not Dynamic Composition**: Links are static at author-time, selection is runtime
---
## 2. Syntax Design
### 2.1 Simple Single Link
The most common case: a character has one primary behavior and one schedule.
```storybook
character Martha: Human {
age: 34
uses behavior: WorkAtBakery
uses schedule: BakerSchedule
}
```
**AST Representation:**
```rust
// Add to Character struct in ast.rs
pub struct Character {
pub name: String,
pub species: Option<String>,
pub fields: Vec<Field>,
pub template: Option<Vec<String>>,
pub behavior_links: Vec<BehaviorLink>, // NEW
pub schedule_links: Vec<ScheduleLink>, // NEW
pub span: Span,
}
```
### 2.2 Multiple Links with Priorities
Characters may have multiple behaviors that activate based on context:
```storybook
character Alice: Human {
age: 7
uses behaviors: [
{ tree: HandleUrgentNeeds, priority: critical }
{ tree: CuriousExplorer, priority: normal }
{ tree: Idle, priority: low }
]
}
```
**Semantics:**
- Higher priority behaviors preempt lower priority ones
- Within same priority, declaration order determines evaluation
- `critical` > `high` > `normal` > `low`
### 2.3 Conditional Links
Links can have `when` conditions for context-based selection:
```storybook
character Alice: Human {
uses behaviors: [
{ tree: HandleUrgentNeeds, priority: critical }
{ tree: GiantBehavior, when: current_size == huge }
{ tree: TinyBehavior, when: current_size == tiny }
{ tree: NormalExploring, default: true }
]
uses schedules: [
{ schedule: SleepSchedule, when: emotional_state == exhausted }
{ schedule: AdventureSchedule, default: true }
]
}
```
**Condition Evaluation:**
- Conditions use the existing expression language (see design.md §5)
- `default: true` means "use this if no condition matches"
- Only one `default` allowed per link type
- Runtime evaluates conditions top-to-bottom
### 2.4 Institution Links
Institutions can link to behaviors and schedules:
```storybook
institution Bakery {
type: commercial
uses behavior: BakeryOperations
uses schedule: BakeryHours
}
```
**Multiple Schedules for Seasons:**
```storybook
institution Bakery {
uses schedules: [
{ schedule: SummerHours, when: season == summer }
{ schedule: WinterHours, when: season == winter }
{ schedule: StandardHours, default: true }
]
}
```
### 2.5 Template Inheritance
Templates can define default links that characters inherit:
```storybook
template WonderlandCreature {
uses behavior: WonderlandBehavior
uses schedule: WonderlandSchedule
}
character CheshireCat: Cat from WonderlandCreature {
// Inherits WonderlandBehavior and WonderlandSchedule
// Can override:
uses behavior: CheshireBehavior // Replaces WonderlandBehavior
}
```
**Override Semantics:**
- If character defines `uses behavior:`, it replaces template's behavior link entirely
- If character defines `uses behaviors: [...]`, it replaces template's behavior links
- No merging—it's full replacement (consistent with current template override system)
---
## 3. AST Design
### 3.1 New AST Types
```rust
// In src/syntax/ast.rs
/// A link to a behavior tree
#[derive(Debug, Clone, PartialEq)]
pub struct BehaviorLink {
pub tree: Vec<String>, // Qualified path to behavior
pub priority: Option<String>, // critical, high, normal, low
pub condition: Option<Expr>, // when clause
pub is_default: bool, // default: true
pub span: Span,
}
/// A link to a schedule
#[derive(Debug, Clone, PartialEq)]
pub struct ScheduleLink {
pub schedule: Vec<String>, // Qualified path to schedule
pub condition: Option<Expr>, // when clause
pub is_default: bool, // default: true
pub span: Span,
}
// Priority levels (could be enum or validated string)
pub enum Priority {
Critical,
High,
Normal,
Low,
}
```
### 3.2 Modified AST Structs
```rust
// Character gains link fields
pub struct Character {
pub name: String,
pub species: Option<String>,
pub fields: Vec<Field>,
pub template: Option<Vec<String>>,
pub behavior_links: Vec<BehaviorLink>, // NEW
pub schedule_links: Vec<ScheduleLink>, // NEW
pub span: Span,
}
// Institution gains link fields
pub struct Institution {
pub name: String,
pub fields: Vec<Field>,
pub behavior_links: Vec<BehaviorLink>, // NEW
pub schedule_links: Vec<ScheduleLink>, // NEW
pub span: Span,
}
// Template can also have links
pub struct Template {
pub name: String,
pub fields: Vec<Field>,
pub includes: Vec<Vec<String>>,
pub behavior_links: Vec<BehaviorLink>, // NEW
pub schedule_links: Vec<ScheduleLink>, // NEW
pub span: Span,
}
```
---
## 4. Parser Design (LALRPOP)
### 4.1 Grammar Productions
```lalrpop
// In parser.lalrpop
// Character definition with optional links
pub Character: Character = {
"character" <name:Ident> <species:SpeciesClause?> <template:TemplateClause?> "{"
<items:CharacterItem*>
"}" => {
let mut fields = vec![];
let mut behavior_links = vec![];
let mut schedule_links = vec![];
for item in items {
match item {
CharacterItem::Field(f) => fields.push(f),
CharacterItem::BehaviorLink(bl) => behavior_links.extend(bl),
CharacterItem::ScheduleLink(sl) => schedule_links.extend(sl),
}
}
Character { name, species, fields, template, behavior_links, schedule_links, span }
}
};
CharacterItem: CharacterItem = {
<Field> => CharacterItem::Field(<>),
<BehaviorLinkStmt> => CharacterItem::BehaviorLink(<>),
<ScheduleLinkStmt> => CharacterItem::ScheduleLink(<>),
};
// Behavior link statement
BehaviorLinkStmt: Vec<BehaviorLink> = {
// Single link: uses behavior: BehaviorName
"uses" "behavior" ":" <path:QualifiedPath> => {
vec![BehaviorLink {
tree: path,
priority: None,
condition: None,
is_default: false,
span,
}]
},
// Multiple links: uses behaviors: [...]
"uses" "behaviors" ":" "[" <links:Comma<BehaviorLinkSpec>> "]" => links,
};
BehaviorLinkSpec: BehaviorLink = {
// { tree: Name, priority: normal, when: condition, default: true }
"{" <fields:Comma<BehaviorLinkField>> "}" => {
let mut tree = None;
let mut priority = None;
let mut condition = None;
let mut is_default = false;
for field in fields {
match field {
BehaviorLinkField::Tree(path) => tree = Some(path),
BehaviorLinkField::Priority(p) => priority = Some(p),
BehaviorLinkField::Condition(c) => condition = Some(c),
BehaviorLinkField::Default => is_default = true,
}
}
BehaviorLink {
tree: tree.expect("tree field required"),
priority,
condition,
is_default,
span,
}
},
};
BehaviorLinkField: BehaviorLinkField = {
"tree" ":" <QualifiedPath> => BehaviorLinkField::Tree(<>),
"priority" ":" <Ident> => BehaviorLinkField::Priority(<>),
"when" ":" <Expr> => BehaviorLinkField::Condition(<>),
"default" ":" "true" => BehaviorLinkField::Default,
};
// Schedule link statement (parallel structure)
ScheduleLinkStmt: Vec<ScheduleLink> = {
"uses" "schedule" ":" <path:QualifiedPath> => {
vec![ScheduleLink {
schedule: path,
condition: None,
is_default: false,
span,
}]
},
"uses" "schedules" ":" "[" <links:Comma<ScheduleLinkSpec>> "]" => links,
};
ScheduleLinkSpec: ScheduleLink = {
"{" <fields:Comma<ScheduleLinkField>> "}" => {
let mut schedule = None;
let mut condition = None;
let mut is_default = false;
for field in fields {
match field {
ScheduleLinkField::Schedule(path) => schedule = Some(path),
ScheduleLinkField::Condition(c) => condition = Some(c),
ScheduleLinkField::Default => is_default = true,
}
}
ScheduleLink {
schedule: schedule.expect("schedule field required"),
condition,
is_default,
span,
}
},
};
ScheduleLinkField: ScheduleLinkField = {
"schedule" ":" <QualifiedPath> => ScheduleLinkField::Schedule(<>),
"when" ":" <Expr> => ScheduleLinkField::Condition(<>),
"default" ":" "true" => ScheduleLinkField::Default,
};
```
---
## 5. Resolution & Validation
### 5.1 Name Resolution
During the resolution pass (Pass 3 in design.md §4.7), the resolver must:
1. **Resolve Behavior Paths**: Each `tree: BehaviorName` must reference a valid `behavior` declaration
2. **Resolve Schedule Paths**: Each `schedule: ScheduleName` must reference a valid `schedule` declaration
3. **Validate Priorities**: Priority values must be one of {critical, high, normal, low}
4. **Validate Conditions**: Expressions in `when` clauses must be valid and type-check
**Error Examples:**
```
error: unresolved behavior reference
┌─ characters/alice.sb:12:23
12 │ uses behavior: CuriousExporer
│ ^^^^^^^^^^^^^^ no behavior named `CuriousExporer` exists
= help: did you mean `CuriousExplorer`? (defined in behaviors/alice_behaviors.sb)
```
### 5.2 Semantic Validation
1. **At Most One Default**: Each link array can have at most one `default: true`
2. **Priority + Default Conflicts**: If `default: true`, priority should be `low` or omitted
3. **Condition Completeness**: Warn if conditions are not exhaustive (no default + gaps in conditions)
**Warning Example:**
```
warning: conditions may not cover all cases
┌─ characters/alice.sb:8:5
8 │ uses behaviors: [
9 │ { tree: GiantBehavior, when: current_size == huge }
10 │ { tree: TinyBehavior, when: current_size == tiny }
11 │ ]
= note: no default behavior specified and conditions don't cover all size values
= help: add a default behavior: { tree: NormalBehavior, default: true }
```
### 5.3 Template Merge Logic
When a character uses `from Template`, behavior and schedule links are merged:
```rust
// Pseudocode for merge logic
fn merge_character_with_template(char: Character, template: Template) -> ResolvedCharacter {
let behavior_links = if !char.behavior_links.is_empty() {
char.behavior_links // Character overrides completely
} else {
template.behavior_links // Inherit from template
};
let schedule_links = if !char.schedule_links.is_empty() {
char.schedule_links
} else {
template.schedule_links
};
// ... merge fields, etc.
}
```
**Key Rule**: If character defines ANY behavior links, template's behavior links are ignored entirely. Same for schedules. This is all-or-nothing replacement, not merging. (no, i like merging. idk how we'll handle conflicts, but i want to support that kinda composition)
---
## 6. Resolved Type Representation
### 6.1 Resolved Link Types
```rust
// In src/types.rs
/// Resolved behavior link with all references resolved
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedBehaviorLink {
pub tree_name: String, // Fully qualified behavior name
pub priority: Priority, // Resolved to enum
pub condition: Option<Expr>, // Validated expression
pub is_default: bool,
}
/// Resolved schedule link
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedScheduleLink {
pub schedule_name: String, // Fully qualified schedule name
pub condition: Option<Expr>,
pub is_default: bool,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Priority {
Critical = 3,
High = 2,
Normal = 1,
Low = 0,
}
```
### 6.2 Updated Resolved Structs
```rust
pub struct ResolvedCharacter {
pub name: String,
pub species: Option<String>,
pub fields: HashMap<String, Value>,
pub prose_blocks: HashMap<String, ProseBlock>,
pub behavior_links: Vec<ResolvedBehaviorLink>, // NEW
pub schedule_links: Vec<ResolvedScheduleLink>, // NEW
pub span: Span,
}
pub struct ResolvedInstitution {
pub name: String,
pub fields: HashMap<String, Value>,
pub behavior_links: Vec<ResolvedBehaviorLink>, // NEW
pub schedule_links: Vec<ResolvedScheduleLink>, // NEW
pub span: Span,
}
```
---
## 7. SBIR Representation Proposal
### 7.1 CHARACTERS Section Extension
Currently, the CHARACTERS section (called ENTITIES in some specs) stores character data. We extend it:
```
CHARACTERS Section:
- count: u32
- characters: [Character...]
Character:
- name: String
- species: Option<String>
- fields: Map<String, Value>
- behavior_links: [BehaviorLink...] <-- NEW
- schedule_links: [ScheduleLink...] <-- NEW
BehaviorLink:
- behavior_id: u32 (index into BEHAVIORS section)
- priority: u8 (0=low, 1=normal, 2=high, 3=critical)
- condition: Option<Expression>
- is_default: bool
ScheduleLink:
- schedule_id: u32 (index into SCHEDULES section)
- condition: Option<Expression>
- is_default: bool
Expression:
- (Existing expression bytecode format from design.md §5)
```
### 7.2 INSTITUTIONS Section Extension
```
INSTITUTIONS Section:
- count: u32
- institutions: [Institution...]
Institution:
- name: String
- fields: Map<String, Value>
- behavior_links: [BehaviorLink...] <-- NEW
- schedule_links: [ScheduleLink...] <-- NEW
```
### 7.3 BEHAVIORS and SCHEDULES Sections
These sections remain unchanged—they define the behavior trees and schedules. Links reference them by index.
**Index Resolution:**
- During compilation, behavior/schedule names are resolved to their index in the respective section
- At runtime, the engine uses the index to look up the behavior/schedule definition
---
## 8. Runtime Link Resolution Algorithm
### 8.1 Behavior Selection
When the engine needs to select a behavior for a character:
```rust
fn select_behavior(character: &Character, context: &RuntimeContext) -> Option<&Behavior> {
let mut candidates: Vec<_> = character.behavior_links
.iter()
.filter(|link| {
// Evaluate condition if present
link.condition.is_none() || evaluate_condition(&link.condition, context)
})
.collect();
if candidates.is_empty() {
return None;
}
// Sort by priority (descending)
candidates.sort_by(|a, b| b.priority.cmp(&a.priority));
// Return highest priority candidate
// (If multiple same priority, declaration order is preserved by stable sort)
let selected = candidates[0];
Some(get_behavior_by_id(selected.behavior_id))
}
```
**Key Properties:**
- Priority-based selection: higher priority wins
- Conditions filter candidates before priority sorting
- `default: true` only matters if no conditions match (it's implicitly `when: true`)
- Deterministic: same context always yields same behavior
### 8.2 Schedule Selection
```rust
fn select_schedule(entity: &Entity, context: &RuntimeContext) -> Option<&Schedule> {
for link in &entity.schedule_links {
if link.is_default {
continue; // Skip default, check it last
}
if link.condition.is_none() || evaluate_condition(&link.condition, context) {
return Some(get_schedule_by_id(link.schedule_id));
}
}
// No conditions matched, use default if present
entity.schedule_links
.iter()
.find(|link| link.is_default)
.map(|link| get_schedule_by_id(link.schedule_id))
}
```
**Key Properties:**
- First-match semantics: first condition that evaluates to true wins
- Default is fallback: only used if no condition matches
- Order matters: earlier links are checked first
---
## 9. Examples
### 9.1 Simple Character with Behavior and Schedule
```storybook
behavior BakerBehavior {
> {
check_oven
serve_customers
clean_workspace
}
}
schedule BakerSchedule {
block work { 5:00 - 13:00 }
block lunch { 13:00 - 14:00 }
block home { 14:00 - 22:00 }
block sleep { 22:00 - 5:00 }
}
character Martha: Human {
age: 34
occupation: baker
uses behavior: BakerBehavior
uses schedule: BakerSchedule
}
```
### 9.2 Character with Multiple Context-Dependent Behaviors
```storybook
character Alice: Human {
age: 7
current_size: normal
emotional_state: curious
uses behaviors: [
{ tree: PanicBehavior, priority: critical, when: emotional_state == frightened }
{ tree: GiantBehavior, when: current_size == huge }
{ tree: TinyBehavior, when: current_size == tiny }
{ tree: BraveBehavior, when: emotional_state == brave }
{ tree: CuriousExplorer, default: true }
]
uses schedules: [
{ schedule: SleepingSchedule, when: emotional_state == exhausted }
{ schedule: AdventureSchedule, default: true }
]
}
```
### 9.3 Institution with Seasonal Schedules
```storybook
schedule SummerHours {
block open { 6:00 - 20:00 }
block closed { 20:00 - 6:00 }
}
schedule WinterHours {
block open { 7:00 - 18:00 }
block closed { 18:00 - 7:00 }
}
institution Bakery {
type: commercial
uses behavior: BakeryOperations
uses schedules: [
{ schedule: SummerHours, when: season == summer }
{ schedule: WinterHours, when: season == winter }
]
}
```
### 9.4 Template with Default Links
```storybook
behavior WonderlandBehavior {
> {
speak_nonsense
violate_logic
}
}
schedule WonderlandSchedule {
block awake { 0:00 - 24:00 } // Always awake in dreams
}
template WonderlandCreature {
uses behavior: WonderlandBehavior
uses schedule: WonderlandSchedule
}
character CheshireCat: Cat from WonderlandCreature {
// Inherits WonderlandBehavior and WonderlandSchedule
can_vanish: true
}
character Alice: Human from WonderlandCreature {
// Overrides behavior but keeps schedule
uses behavior: CuriousExplorer
}
```
---
## 10. Open Questions for User Review (Checkpoint 1)
### Question 1: Priority vs. Declaration Order
**Current Design:** Priority determines order, then declaration order breaks ties.
**Alternative:** Remove priority, use only declaration order (simpler but less expressive).
**Recommendation:** Keep priority. It's more explicit and handles common use cases like "urgent needs always trump routine activities." (i guess priority is fine)
### Question 2: Condition Syntax Sugar
**Current Design:** Full condition expressions.
**Alternative:** Add syntactic sugar for common patterns:
```storybook
uses behaviors: [
{ tree: GiantBehavior, when: current_size == huge }
// vs.
{ tree: GiantBehavior, when current_size: huge } // shorter
]
```
**Recommendation:** Start with full expressions, add sugar if usage reveals patterns. (use `==` or `is`, support both like python does.)
### Question 3: Schedule-Behavior Integration
**Current Design:** Behaviors and schedules are separate links. Schedule determines WHEN, behavior determines WHAT.
**Alternative:** Allow schedules to specify behaviors inline:
```storybook
schedule WorkSchedule {
block work { 9:00 - 17:00, behavior: WorkBehavior }
}
```
**Recommendation:** Defer inline behaviors to schedule system design (Task #8). Keep linking separate for now. (yeah that's fine)
### Question 4: Link Override Semantics
**Current Design:** If character defines any behavior links, template's links are completely replaced.
**Alternative:** Merge character and template links (character links come first, then template links).
**Recommendation:** Keep replacement semantics. It's clearer and matches existing override system. (sure? i don't remember the nuances tbh)
### Question 5: Multiple Defaults
**Current Design:** At most one `default: true` per link type.
**Alternative:** Allow multiple defaults with priority order.
**Recommendation:** Keep single default. Multiple defaults creates ambiguity. (single default makes sense?)
---
## 11. Implementation Plan (for Task #6)
### Phase 1: AST Extension (Week 1)
1. Add `BehaviorLink` and `ScheduleLink` structs to `ast.rs`
2. Add link fields to `Character`, `Institution`, `Template`
3. Update `Declaration` enum if needed
### Phase 2: Parser Implementation (Week 1-2)
1. Implement `BehaviorLinkStmt` and `ScheduleLinkStmt` grammar
2. Implement `BehaviorLinkSpec` and `ScheduleLinkSpec` parsing
3. Add link parsing to character, institution, template productions
4. Write parser tests for all link variations
### Phase 3: Resolution (Week 2)
1. Implement behavior/schedule name resolution in `resolve/names.rs`
2. Add priority validation
3. Add condition expression validation
4. Implement template merge logic for links in `resolve/merge.rs`
5. Write resolution tests
### Phase 4: Resolved Types (Week 2)
1. Add `ResolvedBehaviorLink` and `ResolvedScheduleLink` to `types.rs`
2. Update `ResolvedCharacter` and `ResolvedInstitution`
3. Implement conversion in `resolve/convert.rs`
4. Write conversion tests
### Phase 5: Validation & Diagnostics (Week 3)
1. Implement semantic validation (single default, etc.)
2. Add helpful error messages with fuzzy matching
3. Add warnings for incomplete condition coverage
4. Write validation tests
### Phase 6: Integration & Documentation (Week 3)
1. Update examples to use new linking syntax
2. Update language documentation
3. Run full test suite
4. Create migration examples (if backward compatibility breaks)
**Total Estimate:** 3 weeks implementation after design approval.
---
## 12. Success Criteria
### Must Have
- [x] Unified `uses` keyword for behaviors and schedules
- [x] Single-link syntax works (`uses behavior: Name`)
- [x] Multi-link syntax works (`uses behaviors: [...]`)
- [x] Conditions supported (`when: expression`)
- [x] Priorities supported for behaviors
- [x] Default fallback supported (`default: true`)
- [x] Template inheritance works
- [x] Character linking works
- [x] Institution linking works
- [x] Parser produces correct AST
- [x] Resolver validates references
- [x] Clear error messages
- [x] SBIR format defined
### Should Have
- [ ] Warning for incomplete condition coverage
- [ ] Examples for all use cases
- [ ] Migration guide if needed
- [ ] Runtime selection algorithm specification
- [ ] Performance characteristics documented
### Nice to Have
- [ ] Visual editor support design
- [ ] Auto-completion for behavior/schedule names
- [ ] Link refactoring tools
---
## 13. Risks & Mitigation
| Risk | Likelihood | Impact | Mitigation |
|------|-----------|--------|------------|
| Syntax conflicts with relationship linking | Low | Medium | Different syntax context—parser can disambiguate |
| Complex condition expressions hard to debug | Medium | Medium | Good error messages, warnings for non-exhaustive conditions |
| Priority system confusing for users | Medium | Low | Clear documentation, examples, default priority=normal |
| Template override semantics unclear | Medium | Medium | Explicit documentation, validation warnings |
| SBIR encoding inefficient | Low | Low | Use indices for references, compress expressions |
| Runtime selection too slow | Low | Medium | Profile early, cache selections if needed |
---
## Appendix A: Comparison with Relationship Linking
**Relationship Linking** (existing):
- Top-level `relationship` declarations
- Participants within relationships
- Bidirectional by nature
- `self`/`other` blocks for asymmetry
**Resource Linking** (this design):
- Links within character/institution definitions
- References to external behaviors/schedules
- Unidirectional (character → behavior)
- Conditions/priorities for selection
These are complementary systems serving different purposes. No conflict.
---
## Appendix B: Grammar Sketch (Full)
```lalrpop
// Simplified grammar showing link integration
Character: Character = {
"character" <name:Ident> <species:SpeciesClause?> <template:TemplateClause?>
"{" <items:CharacterItem*> "}" => // ... construct Character
};
CharacterItem = {
Field,
BehaviorLinkStmt,
ScheduleLinkStmt,
ProseBlock,
};
BehaviorLinkStmt: Vec<BehaviorLink> = {
"uses" "behavior" ":" <QualifiedPath> => // single link
"uses" "behaviors" ":" "[" <Comma<BehaviorLinkSpec>> "]" => // multi link
};
BehaviorLinkSpec: BehaviorLink = {
"{" <Comma<BehaviorLinkField>> "}" => // parse fields into BehaviorLink
};
BehaviorLinkField = {
"tree" ":" QualifiedPath,
"priority" ":" Ident,
"when" ":" Expr,
"default" ":" "true",
};
// Parallel structure for schedules...
```
---
**End of Design Document**
**Next Step:** Present to user (Sienna) for Checkpoint 1 review and approval.

387
design/ui-architecture.md Normal file
View File

@@ -0,0 +1,387 @@
# Storybook Editor UI Architecture
> Structured creative tools for non-technical storytelling
## Design Philosophy
**Primary User (Lonni)**: Creative writer who thinks in characters, relationships, and narrative arcs—NOT files and syntax.
**Secondary User (Sienna)**: Developer who needs access to raw `.sb` files for behavior trees, schemas, and engine integration.
**Core Principle**: The editor should feel like **writing**, not coding. Structured panes guide creation. The file editor is "manual mode" for power users.
## Application Structure
```
┌─────────────────────────────────────────────────────────────────────┐
│ Storybook Editor - examples/alice-in-wonderland/ │
├──────────────┬──────────────────────────────────────┬───────────────┤
│ │ │ │
│ Entity │ Character Editor │ Quick │
│ Browser │ │ Actions │
│ │ ┌─────────────────────────────────┐ │ │
│ Characters │ │ Name: Alice │ │ ✓ Validate │
│ ├─ Alice │ │ Age: 7 │ │ ⎇ Versions │
│ ├─ Rabbit │ │ Species: Human │ │ ⊕ New Char │
│ └─ Queen │ │ │ │ ⊕ New Rel │
│ │ │ Traits │ │ ⊕ New Place │
│ Relations │ │ curiosity: 0.95 [━━━━━━━━━•─] │ │ │
│ ├─ Alice │ │ politeness: 0.75 [━━━━━━━•───] │ │ 🔍 Search... │
│ │ ↔ Rabbit │ │ │ │ │
│ └─ Queen │ │ Backstory │ │ Git │
│ ↔ King │ │ ┌─────────────────────────────┐ │ │ main │
│ │ │ │ Alice was beginning to get │ │ │ 3m ago │
│ Places │ │ │ very tired of sitting by │ │ │ 12 changes │
│ ├─ Rabbit │ │ │ her sister on the bank... │ │ │ │
│ │ Hole │ │ │ │ │ └───────────────┘
│ └─ Tea │ │ └─────────────────────────────┘ │
│ Party │ │ │
│ │ │ [Portrait slot: click to add] │
│ Schedules │ │ │
│ Templates │ │ [Save Character] │
│ Behaviors │ └─────────────────────────────────┘
│ │ │
│ [Manual] │ Tabs: Traits | Backstory | Schedule│
│ │ Relationships | Behavior │
└──────────────┴──────────────────────────────────────┴───────────────┘
```
## Primary Views (Structured Editing)
### 1. Character Editor
**Purpose**: Create and edit characters through forms and rich text, NOT raw `.sb` syntax.
**Layout**:
- **Header**: Name input (large, prominent)
- **Metadata Row**: Age, species, template dropdowns
- **Traits Section**: Sliders for numeric traits, chips for tags
- **Prose Sections**: Tabbed rich text areas for backstory, appearance, personality
- **Portrait**: Image upload with preview
- **Relationships**: Quick list with "Edit" buttons
- **Schedule**: Mini timeline preview with "Edit Full Schedule" button
**Interaction**:
- All changes auto-save to `.sb` file (no explicit save button for small edits)
- Git auto-commit on major milestones (e.g., "Update Alice: added backstory")
- Validation errors show inline (e.g., red border + tooltip for out-of-range trait)
**Example**:
```
┌─────────────────────────────────────────────────────┐
│ Name: Alice [Portrait]│
│ Age: 7 Species: Human Template: Child │
├─────────────────────────────────────────────────────┤
│ Traits │
│ curiosity 0.95 [━━━━━━━━━━━━━━━•─] │
│ politeness 0.75 [━━━━━━━━━━━•─────] │
│ fear_of_queen 0.10 [━•──────────────────] │
│ │
│ Tags: [imaginative] [brave] [+ Add Tag] │
├─────────────────────────────────────────────────────┤
│ ⎔ Backstory │ Appearance │ Personality │
├─────────────────────────────────────────────────────┤
│ Alice was beginning to get very tired of sitting │
│ by her sister on the bank, and of having nothing │
│ to do... │
│ │
│ [Rich text editor with basic formatting] │
└─────────────────────────────────────────────────────┘
```
### 2. Relationship Editor
**Purpose**: Visually connect characters and define relationship properties.
**Layout**:
- **Graph View**: Force-directed graph with character nodes
- **Edge Selection**: Click edge to edit relationship details
- **Properties Panel**: Bond strength, coordination level, bond type
- **Asymmetric Fields**: "From Alice's perspective" / "From Rabbit's perspective"
**Interaction**:
- Drag nodes to rearrange
- Click edge → properties panel appears
- Slider for bond strength (0.0 to 1.0)
- Dropdown for bond type (romantic, familial, friendship, etc.)
**Example**:
```
┌─────────────────────────────────────────────────────────────┐
│ Relationship: Alice ↔ White Rabbit │
├─────────────────────────────────────────────────────────────┤
│ Bond Strength: 0.65 [━━━━━━━•──────] │
│ Bond Type: friendship │
│ Coordination: ad_hoc │
├─────────────────────────────────────────────────────────────┤
│ From Alice's perspective: │
│ Respect for punctuality: 0.80 [━━━━━━━━•──] │
│ │
│ From White Rabbit's perspective: │
│ Anxiety about lateness: 0.95 [━━━━━━━━━━━•─] │
├─────────────────────────────────────────────────────────────┤
│ [Graph View] │
│ │
│ Alice ●━━━━━━● White Rabbit │
│ │
│ Queen ●━━━━━━━━━━● King │
│ ╲
│ ●━━━━━━━━━━● │
│ Guards │
└─────────────────────────────────────────────────────────────┘
```
### 3. Schedule Builder
**Purpose**: Visual timeline for daily routines (no typing time codes!).
**Layout**:
- **Timeline**: Horizontal 24-hour view with draggable blocks
- **Activity Palette**: Drag activities from sidebar onto timeline
- **Activity Editor**: Click block to edit parameters
**Interaction**:
- Drag edges to resize time blocks
- Drag from palette to add new activity
- Snap to 15-minute increments
- Validation: overlapping blocks show warning
**Example**:
```
┌─────────────────────────────────────────────────────────────┐
│ Schedule: Alice's Day │
├────┬────────────────────────────────────────────────────────┤
│ │ 00:00 06:00 12:00 18:00 24:00 │
│ ├───────────────────────────────────────────────────────┤
│ Su │ ████Sleep████│Breakfast│Play│Tea│Study│Play│█Sleep██ │
│ Mo │ ████Sleep████│Breakfast│School██████│Play│██Sleep███ │
│ └───────────────────────────────────────────────────────┘
│ │
│ Palette: │
│ [Sleep] [Eat] [Play] [Study] [Social] [+ Custom] │
│ │
│ Selected: Tea Party (16:00 → 17:00) │
│ Location: Garden │
│ Participants: Mad Hatter, March Hare, Dormouse │
└─────────────────────────────────────────────────────────────┘
```
### 4. Behavior Tree Builder (Advanced)
**Purpose**: Visual node graph for programmable behaviors (Sienna's domain, but approachable for Lonni).
**Layout**:
- **Canvas**: Infinite 2D space for nodes
- **Node Palette**: Selector, Sequence, Condition, Action, Decorator
- **Inspector**: Selected node's properties
**Interaction**:
- Drag nodes from palette
- Connect with edges (parent → children)
- Right-click node → context menu (delete, duplicate, etc.)
- Validation: orphan nodes, missing actions show errors
**Example**:
```
┌─────────────────────────────────────────────────────────────┐
│ Behavior: WorkAtBakery │
├─────────────────────────────────────────────────────────────┤
│ Palette: [Selector] [Sequence] [?Condition] [→Action] │
│ │
│ Canvas: │
│ │
│ ┌─────────────┐ │
│ │ Selector │ │
│ └──────┬──────┘ │
│ ┌────────┼────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ Prep │ │ Bake │ │ Sell │ │
│ │ Dough│ │Bread │ │ Bread│ │
│ └──────┘ └──────┘ └──────┘ │
│ │
│ Selected: PrepDough │
│ Action: knead_dough │
│ Duration: 30 minutes │
│ Required Skill: baking > 0.5 │
└─────────────────────────────────────────────────────────────┘
```
## Secondary View (Manual Mode)
### File Editor
**Purpose**: Direct `.sb` syntax editing for power users and edge cases.
**When to Use**:
- Behavior trees (until visual editor is built)
- Templates with ranges
- Advanced features not yet in GUI
- Bulk find-replace across characters
**Layout**:
- Syntax-highlighted text editor (Monaspace Neon)
- Live validation with inline errors
- File tree on left
**Interaction**:
- Standard text editor keybindings
- Ctrl+S saves (git auto-commit)
- Errors show inline with gold underline
- Click error → jump to diagnostic
## Entity Browser (Left Sidebar)
**Purpose**: Navigate the storybook's content hierarchy.
**Structure**:
```
📂 characters/
├─ 👤 Alice
├─ 🐰 White Rabbit
├─ 👑 Queen of Hearts
└─ 👑 King of Hearts
💑 relationships/
├─ Alice ↔ White Rabbit
├─ Queen ↔ King
└─ Queen → Subjects (all)
📍 locations/
├─ 🕳️ Rabbit Hole
├─ 🫖 Tea Party Garden
└─ 🏰 Queen's Castle
📋 templates/
├─ WonderlandCreature
├─ PlayingCard
└─ CourtMember
🎭 behaviors/
├─ WorkAtBakery
└─ AttendTeaParty
📅 schedules/
└─ DailyRoutine
```
**Interaction**:
- Click entity → load in main panel
- Right-click → context menu (delete, duplicate, etc.)
- Drag-drop to reorder or move files
- Search box filters by name
## Quick Actions Pane (Right Sidebar)
**Purpose**: Common tasks and project status at fingertips.
**Sections**:
1. **Actions**
- ✓ Validate All
- ⊕ New Character
- ⊕ New Relationship
- ⊕ New Location
- 🔍 Search Everything
2. **Git Status**
- Current branch: `main`
- Last change: `3 minutes ago`
- Uncommitted changes: `12 files`
- [View History] button → timeline view
3. **Diagnostics**
- ✓ No errors
- ⚠ 2 warnings
- Click to expand inline
4. **Project Info**
- Characters: 12
- Relationships: 7
- Locations: 5
## Responsive Behavior
### Wide Screen (> 1440px)
Three columns: Entity Browser | Main Editor | Quick Actions
### Standard (10241440px)
Two columns: Entity Browser | Main Editor
Quick Actions → collapsible panel
### Compact (< 1024px)
Single column focus mode
Entity Browser → drawer (slides in from left)
Quick Actions → toolbar at top
## Technical Implementation Notes
### Iced Framework
- Use `iced::widget::*` for built-in components
- Custom widgets for:
- Timeline (schedule builder)
- Graph (relationship map)
- Node Canvas (behavior tree builder)
- Trait Slider (with live value display)
### File Synchronization
- Watch `.sb` files for external changes
- Reload editor state on change
- Warn if unsaved changes conflict
### Git Integration
- Auto-commit on save with descriptive messages:
- "Update Alice: modified backstory"
- "Add relationship: Alice ↔ White Rabbit"
- "Create character: Cheshire Cat"
- Use `git2` crate (no shell commands)
- Expose branches as "versions" in UI
### Theme Application
- Load colors from `design/color-palette.md`
- Apply 8px grid to all spacing
- Use Monaspace Neon for code blocks
- Geist for UI text
- Gradient background: aubergine (sides) → cream (center) in main editor panel
## User Workflows
### Lonni Creates a New Character
1. Click "⊕ New Character" in Quick Actions
2. Fill in name, age, species (dropdowns guided by schema)
3. Adjust trait sliders (validation prevents out-of-range)
4. Write backstory in rich text area
5. Upload portrait image
6. Click "Save" → `.sb` file created, git commit happens
7. Character appears in Entity Browser
### Lonni Builds a Relationship
1. Click "⊕ New Relationship"
2. Select two characters from dropdowns
3. Drag bond strength slider
4. Pick bond type from predefined options
5. Fill in asymmetric fields (Alice's view vs. Rabbit's view)
6. Save → `.sb` file updated, git commit
### Sienna Edits a Behavior Tree
1. Click behavior in Entity Browser
2. See visual node graph
3. Drag new "Action" node from palette
4. Connect to parent Sequence
5. Set action parameters in inspector
6. Save → `.sb` file updated
### Both Users Check Validation
1. Quick Actions shows "⚠ 2 warnings"
2. Click to expand → shows inline errors
3. Click error → jumps to problematic entity
4. Fix in structured editor
5. Validation updates live
---
*This architecture prioritizes Lonni's creative flow while keeping power-user features accessible for Sienna.*

429
design/visual-design.md Normal file
View File

@@ -0,0 +1,429 @@
# Storybook Editor Visual Design System
> A synthesis of Teenage Engineering's bold minimalism and Dieter Rams' functionalist precision.
## Design Principles
### Core Tenets
1. **Functional First** - Every element serves a purpose. No decoration for decoration's sake.
2. **Grid-Based Precision** - All elements align to an 8px base grid. Spacing is deliberate.
3. **Restrained + Energetic** - Sophisticated aubergine foundation with bold gold accents.
4. **Tactile Clarity** - Interactions feel deliberate. Buttons have weight. Feedback is immediate.
5. **Honest Materials** - Code is monospace. Text is sans-serif. No skeuomorphism.
6. **Long-Lasting** - Timeless aesthetic that won't feel dated in 5 years.
### The Rams x TE Synthesis
| Dieter Rams (Braun) | Teenage Engineering | Our Synthesis |
|---------------------|---------------------|---------------|
| "Less, but better" | Bold, playful color | Minimal structure, bold accents |
| Neutral grays | Signature orange | Aubergine + gold |
| Pure function | Emotional response | Functional with character |
| Unobtrusive | Visual delight | Delightful when needed |
| Grid systems | Grid systems | 8px base grid |
## Color System
### Primary Palette
```
Aubergine Foundation:
├─ aubergine-900 #1a0f1e Background (darkest)
├─ aubergine-800 #2b1a33 Surface (cards, panels)
├─ aubergine-700 #3d2447 Surface hover
├─ aubergine-600 #4f2e5b Borders
├─ aubergine-500 #61386f Subtle highlights
├─ aubergine-400 #805793 Active elements
└─ aubergine-300 #9f76a7 Muted text
Gold Accents:
├─ gold-500 #f4a261 Primary accent (TE orange-gold)
├─ gold-400 #f6b47a Hover state
└─ gold-300 #f8c594 Pressed state
Supporting:
├─ cream #fdf8f3 High contrast text
├─ warm-gray-100 #e8e3dd Secondary text
├─ warm-gray-400 #8b8680 Muted text
└─ warm-gray-700 #4a4845 Disabled elements
```
### Semantic Colors
```
Success: #6a994e Muted olive green (validation passed)
Warning: #f4a261 Gold (reuse accent)
Error: #d62828 Deep red (parse errors)
Info: #9f76a7 Light aubergine (hints)
```
### Usage Guidelines
- **Backgrounds**: Always aubergine-900 or aubergine-800
- **Text**: Cream for primary, warm-gray-100 for secondary
- **Accents**: Gold only for interactive elements and key information
- **Borders**: aubergine-600 for subtle division, gold-500 for focus
- **Code**: Syntax highlighting uses muted versions of semantic colors
## Typography
### Typeface Stack
```
UI Text (Sans-Serif):
Primary: Geist, system-ui, -apple-system, sans-serif
Weights: 400 (regular), 500 (medium), 600 (semibold)
Code (Monospace):
Primary: "Monaspace Neon", "Monaspace", monospace
Weights: 400 (regular), 600 (semibold)
Features: Enable 'calt' for texture healing, ligatures
Fallback: "JetBrains Mono", "Fira Code", Consolas, monospace
Headings (Sans-Serif):
Primary: Same as UI but always semibold (600)
```
### Type Scale (8px base grid)
```
Heading 1: 24px / 32px semibold (Panel titles)
Heading 2: 20px / 28px semibold (Section headers)
Heading 3: 16px / 24px semibold (Subsections)
Body: 14px / 20px regular (Default text)
Body Small: 12px / 16px regular (Secondary info)
Caption: 11px / 16px regular (Labels, metadata)
Code: 13px / 20px regular (Monospace content)
```
### Guidelines
- **Line Height**: 1.41.6 for readability
- **Letter Spacing**: Default for body, +0.02em for labels/captions
- **Hierarchy**: Size + weight + color (don't rely on size alone)
- **Monospace**: Only for code, file paths, and data values
## Spacing System
### 8px Base Grid
```
Micro: 4px (Icon padding, tight spacing)
Small: 8px (Default gap between related elements)
Medium: 16px (Section spacing)
Large: 24px (Panel padding)
XLarge: 32px (Major section separation)
XXLarge: 48px (Page margins, hero spacing)
```
### Application
- All element sizes divisible by 8px
- Padding and margins follow the scale above
- Icons are 16px or 24px
- Buttons have 8px vertical padding, 16px horizontal
- Panel padding is 24px
## Component Patterns
### Buttons
```
Primary (Gold):
├─ Background: gold-500
├─ Text: aubergine-900 (dark text on light button)
├─ Padding: 8px 16px
├─ Border Radius: 4px
├─ Hover: gold-400
└─ Active: gold-300
Secondary (Ghost):
├─ Background: transparent
├─ Border: 1px solid aubergine-600
├─ Text: cream
├─ Hover: aubergine-700 background
└─ Active: aubergine-600 background
Tertiary (Text Only):
├─ Background: transparent
├─ Text: gold-500
├─ Hover: gold-400
└─ Underline on hover
```
### Input Fields
```
Text Input:
├─ Background: aubergine-800
├─ Border: 1px solid aubergine-600
├─ Text: cream
├─ Placeholder: warm-gray-400
├─ Focus: Border gold-500, glow 0 0 0 2px gold-500/20%
├─ Padding: 8px 12px
└─ Border Radius: 4px
Code Input (Textarea):
├─ Background: aubergine-900
├─ Font: JetBrains Mono 13px
├─ Padding: 16px
└─ Syntax highlighting with muted semantic colors
```
### Panels/Cards
```
Surface:
├─ Background: aubergine-800
├─ Border: 1px solid aubergine-600
├─ Border Radius: 8px
├─ Padding: 24px
└─ Shadow: 0 2px 8px rgba(0,0,0,0.3)
Nested Surface:
├─ Background: aubergine-700
└─ Same border/radius but lighter
```
### Lists
```
File List / Tree:
├─ Item height: 32px (divisible by 8)
├─ Hover: aubergine-700 background
├─ Selected: aubergine-600 + gold-500 left border (4px)
├─ Text: cream for name, warm-gray-400 for metadata
└─ Indent: 16px per level
Data List:
├─ Row height: 40px
├─ Alternating backgrounds: aubergine-800 / aubergine-750
├─ Border: 1px solid aubergine-600 between rows
└─ Hover: gold-500/10% overlay
```
### Status Indicators
```
Validation Badge:
├─ Success: 20px circle, green background, white checkmark
├─ Error: 20px circle, red background, white X
├─ Warning: 20px circle, gold background, dark !
└─ Position: Top-right corner of validated element
Loading Spinner:
├─ Size: 16px or 24px
├─ Color: gold-500
├─ Animation: Smooth rotation, 1s duration
└─ Use sparingly (only for async operations)
```
## Layout Architecture
### Grid System
```
Base Grid: 8px
Columns: 12 or 24 column system
Gutter: 16px
Max Width: 1600px (ultra-wide consideration)
```
### Panel Proportions
```
Three-Column Layout (File Browser | Editor | Inspector):
├─ File Browser: 240px320px (fixed, resizable)
├─ Editor: Flex-grow (takes remaining space)
└─ Inspector: 280px400px (fixed, resizable)
Two-Column Layout (File Browser | Editor):
├─ File Browser: 240px320px
└─ Editor: Flex-grow
Diagnostics Panel (Bottom):
├─ Height: 200px400px (resizable)
└─ Full width
```
### Z-Index Layers
```
1. Base (0): Background, surfaces
2. Content (1): Text, images, forms
3. Overlays (10): Dropdowns, tooltips
4. Modals (100): Dialogs, confirmations
5. Notifications (1000): Toast messages, alerts
```
## Interaction Design
### Animation Principles
1. **Fast but Noticeable** - 150200ms for most transitions
2. **Easing**: ease-out for entrances, ease-in for exits
3. **Purpose-Driven** - Animate only to provide feedback or guide attention
4. **Consistent** - Same animation for same action across the app
### Micro-interactions
```
Button Click:
└─ 100ms scale down to 0.98, then return
Hover:
└─ 150ms background color transition
Focus:
└─ Immediate gold border + glow (no delay)
Panel Resize:
└─ Live (no animation) - functional over flashy
Tab Switch:
└─ 200ms fade (crossfade if content changes)
```
### Feedback Patterns
- **Click**: Immediate visual response (scale/color change)
- **Hover**: Subtle background change (150ms transition)
- **Success**: Green flash + success icon (500ms)
- **Error**: Red border pulse + shake animation (300ms)
- **Loading**: Gold spinner appears after 300ms delay (don't flash for quick ops)
## Accessibility
### Contrast Ratios
- **Body text (cream on aubergine-900)**: 15.2:1 (AAA)
- **Secondary text (warm-gray-100 on aubergine-900)**: 11.8:1 (AAA)
- **Gold accent on aubergine-900**: 7.1:1 (AA Large)
- **Buttons**: Ensure 4.5:1 minimum
### Keyboard Navigation
- **Tab order**: Logical, follows visual layout
- **Focus indicators**: Gold border + glow (always visible)
- **Shortcuts**: Display in tooltips, use standard conventions
- **Escape**: Always closes modals/dialogs
### Screen Readers
- Semantic HTML where possible
- ARIA labels for custom components
- Status announcements for validation/errors
- Descriptive button text (no "click here")
## Icon System
### Style
- **Outline style** (not filled) - more Rams than TE
- **Stroke width**: 1.5px
- **Sizes**: 16px, 24px (following grid)
- **Color**: Inherits text color unless accent needed
### Common Icons
```
Navigation:
├─ Folder (closed/open)
├─ File
├─ Search
├─ Settings
└─ Home
Actions:
├─ Plus (add)
├─ X (close/remove)
├─ Check (confirm)
├─ Edit (pencil)
└─ Save (disk or checkmark)
States:
├─ Success (checkmark circle)
├─ Error (X circle)
├─ Warning (! triangle)
└─ Info (i circle)
```
## Dark Mode (Primary Mode)
The aubergine palette is designed dark-first. Light mode is not planned for v1, but if needed:
```
Light Mode Palette (Future):
├─ Background: cream (#fdf8f3)
├─ Surface: warm-gray-100 (#f5f1ec)
├─ Text: aubergine-900
├─ Accent: Slightly deeper gold (#e89350)
└─ Borders: warm-gray-400
```
## Responsive Considerations
### Breakpoints
```
Compact: < 1024px (Single panel focus mode)
Standard: 10241440px (Two panels)
Wide: > 1440px (Three panels comfortable)
```
### Adaptive Layout
- **< 1024px**: File browser as overlay/drawer
- **10241440px**: Two-panel default (browser + editor)
- **> 1440px**: Three-panel comfortable
## Implementation Notes
### Iced Styling
```rust
// Example theme structure
pub struct StorybookTheme {
pub palette: Palette,
pub spacing: Spacing,
pub typography: Typography,
}
pub struct Palette {
pub aubergine_900: Color,
pub gold_500: Color,
// etc.
}
```
### File Organization
```
storybook-editor/src/
├─ theme/
│ ├─ mod.rs (Theme struct)
│ ├─ colors.rs (Color constants)
│ ├─ typography.rs (Font definitions)
│ └─ components.rs (Component styles)
├─ components/
│ ├─ button.rs
│ ├─ input.rs
│ └─ panel.rs
└─ ui/
└─ (Application views)
```
## References
- **Teenage Engineering**: Bold minimalism, grid precision, playful accents
- **Dieter Rams**: "Less but better", functionalism, longevity
- **Apple HIG**: Clarity, depth, deference
- **Linear**: Modern dev tool aesthetic
- **Figma**: Panel-based interface patterns
---
*Version 1.0 - Initial design system for Storybook Editor*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff