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:
210
design/behavior-tree-implementation-status.md
Normal file
210
design/behavior-tree-implementation-status.md
Normal 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
|
||||
1357
design/behavior-tree-keywords-design.md
Normal file
1357
design/behavior-tree-keywords-design.md
Normal file
File diff suppressed because it is too large
Load Diff
160
design/color-palette.md
Normal file
160
design/color-palette.md
Normal 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
365
design/layout-mockup.txt
Normal 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.
|
||||
486
design/merge-implementation-notes.md
Normal file
486
design/merge-implementation-notes.md
Normal 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.
|
||||
658
design/resource-linking-checkpoint2-addendum.md
Normal file
658
design/resource-linking-checkpoint2-addendum.md
Normal 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).
|
||||
921
design/resource-linking-system.md
Normal file
921
design/resource-linking-system.md
Normal 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
387
design/ui-architecture.md
Normal 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 (1024–1440px)
|
||||
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
429
design/visual-design.md
Normal 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.4–1.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: 240px–320px (fixed, resizable)
|
||||
├─ Editor: Flex-grow (takes remaining space)
|
||||
└─ Inspector: 280px–400px (fixed, resizable)
|
||||
|
||||
Two-Column Layout (File Browser | Editor):
|
||||
├─ File Browser: 240px–320px
|
||||
└─ Editor: Flex-grow
|
||||
|
||||
Diagnostics Panel (Bottom):
|
||||
├─ Height: 200px–400px (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** - 150–200ms 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: 1024–1440px (Two panels)
|
||||
Wide: > 1440px (Three panels comfortable)
|
||||
```
|
||||
|
||||
### Adaptive Layout
|
||||
|
||||
- **< 1024px**: File browser as overlay/drawer
|
||||
- **1024–1440px**: 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*
|
||||
1151
design/year-long-schedule-system-revision.md
Normal file
1151
design/year-long-schedule-system-revision.md
Normal file
File diff suppressed because it is too large
Load Diff
1016
design/year-long-schedule-system.md
Normal file
1016
design/year-long-schedule-system.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user