NarrativeBoard: Unified Diagram System for EventFlow
Status: DRAFT
Authors: EventFlow Team
Created: 2025-12-16
Executive Summary
NarrativeBoard is a proposed unified diagram system for EventFlow that combines the best aspects of BPMN (swimlanes, flow visualization), CMMN (case management, event-driven flows), and DMN (decision tables, guard visualization) into a single, cohesive visualization.
Key Features
- Unified View: Replaces Lane + State + Combined diagrams with one comprehensive visualization
- Multi-level Collapsible Regions: Scenario-level and actor-level collapse/expand
- Test Integration: Built-in Given-When-Then visualization and coverage heatmaps
- Simulation Mode: Step-by-step and animated replay of scenarios
- Decision Diamonds: BPMN-style inline guard condition visualization
- Auto-generated: Derived from
.flowfiles with no manual editing required
Design Philosophy
"Your documentation tells a story. NarrativeBoard visualizes that story."
NarrativeBoard embraces EventFlow's natural language philosophy by treating diagrams as visual narratives that unfold as users interact with them.
Problem Statement
Current Diagram System Limitations
EventFlow currently offers three diagram types:
| Diagram | Purpose | Limitation |
|---|---|---|
| Lane Diagram | Actor communication | No state visibility |
| State Diagram | State transitions | No actor context |
| Combined Diagram | Both | Complex, no interactivity |
Pain Points:
- Context Switching: Users must switch between diagram types to understand the full picture
- No Test Visibility: Current diagrams don't show test coverage or scenario paths
- Static Only: No simulation or step-through capability
- Information Overload: Large systems become overwhelming without collapse/expand
- No Guard Details: Decision logic is hidden, not visualized
User Feedback
"I want to see HOW the machine moves between states while also seeing WHO is involved."
"When I'm debugging, I want to step through the flow like a debugger."
"For large systems, I need to focus on one scenario at a time."
Vision: NarrativeBoard
NarrativeBoard is a single, interactive diagram that tells the complete story of your EventFlow system.
┌─────────────────────────────────────────────────────────────────────────────────┐
│ │
│ ╔══════════════════════════════════════════════════════════════════════════╗ │
│ ║ N A R R A T I V E B O A R D ║ │
│ ╠══════════════════════════════════════════════════════════════════════════╣ │
│ ║ ║ │
│ ║ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ║ │
│ ║ │ @customer │ │ @order │ │ @payment │ │ @inventory │ ║ │
│ ║ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ ║ │
│ ║ │ │ │ │ ║ │
│ ║ EVENTS │ STATES │ DECISIONS │ TESTS │ ║ │
│ ║ ───────┼─────────────────┼─────────────────┼─────────────────┼─────── ║ │
│ ║ │ │ │ │ ║ │
│ ║ ▼ Scenario: checkout [▼ COLLAPSE] ║ │
│ ║ ├── Given: cart has items, customer logged in ║ │
│ ║ │ ║ │
│ ║ │ :checkout ────────▶ ◆ cart not empty ─────────▶ :payment_request ║ │
│ ║ │ │ ║ │
│ ║ │ └─[#awaiting_payment] ║ │
│ ║ │ ║ │
│ ║ │ :payment_success ◀──────────────────────────── ║ │
│ ║ │ └─[#paid]─────────────▶ :reserve_stock ║ │
│ ║ │ ║ │
│ ║ │ :stock_reserved ◀────────────────────────────────────────── ║ │
│ ║ │ └─[#confirmed] ✓ ║ │
│ ║ │ ║ │
│ ║ └── Expect: order is in #confirmed ✓ ║ │
│ ║ ║ │
│ ╚══════════════════════════════════════════════════════════════════════════╝ │
│ │
│ [ ◀ Prev ] [ ▶ Next ] [ ▶▶ Play ] [ ⏸ Pause ] [ Coverage: 94% ] │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘Design Principles
1. Single Source of Truth
One diagram type that shows everything:
- Actor lanes (WHO)
- Event flows (WHAT happens)
- State changes (WHERE it pauses)
- Guard conditions (WHY it branches)
- Test results (HOW it's verified)
2. Progressive Disclosure
Information is revealed progressively:
- Level 1: Scenario overview (collapsed)
- Level 2: Event flow within scenario (expanded scenario)
- Level 3: Handler details (expanded event)
- Level 4: Context changes (expanded handler)
3. Documentation-as-Code
NarrativeBoard is:
- Auto-generated from
.flowfiles - Read-only (no manual editing)
- Always synchronized with source code
- Version controlled alongside code
4. Test-First Visualization
Tests are not an afterthought:
- Scenarios ARE test cases
- Coverage is visible at a glance
- Simulation follows test execution
- Assertions are marked inline
5. Natural Language Alignment
Visual elements mirror EventFlow's natural language:
- Events read left-to-right like sentences
- Guards appear as decision questions
- States are labeled descriptively
- Actions read as natural statements
Visual Components
1. Actor Lanes
Vertical swimlanes for each actor, inspired by BPMN:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ @customer │ │ @order │ │ @payment │
│ │ │ │ │ │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │
│ ▼ │ │ ▼ │ │ ▼ │
│ │ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘Features:
- Actor name in header
- Vertical timeline (time flows down)
- Machine actors have a distinct border style
- External actors (like @customer) have a different style
- Collapsible: click header to hide lane
2. Event Flows
Horizontal arrows showing event communication:
@customer @order @payment
│ │ │
│ :checkout │ │
├────────────────────▶│ │
│ │ :payment_request │
│ ├────────────────────▶│
│ │ │
│ │ :payment_success │
│ │◀────────────────────┤
│ │ │Arrow Styles:
────▶Solid: Regular event- - -▶Dashed: Async event (emit async)═════▶Double: API event (api)- Color: Blue for normal, Green for success, Red for failure
3. Decision Diamonds
BPMN-style diamond shapes for guard conditions:
│
▼
┌────◆────┐
│ ? cart │
│not empty│
└────┬────┘
┌──────────┴──────────┐
│ true │ false
▼ ▼
┌──────────┐ ┌──────────┐
│ checkout │ │ :error │
└──────────┘ └──────────┘Diamond Features:
◆symbol marks the decision point?prefix shows this is a guard- Branches labeled with
true/falseor condition names - Multiple guards shown as nested diamonds or combined
4. State Badges
Inline state indicators on the timeline:
│
│ :checkout
├────────────────▶
│
│ ┌────────────────────┐
│ │ #awaiting_payment │ ← State badge
│ └────────────────────┘
│
│ :payment_success
│◀────────────────
│
│ ┌───────────┐
│ │ #paid │ ← State badge (green = terminal)
│ └───────────┘Badge Styles:
[#state]Yellow background: Waiting state[#state]Green background: Terminal success state[#state]Red background: Terminal failure state[#state]Gray border: Initial state
5. Test Markers
Pass/fail indicators for assertions:
┌── scenario: successful checkout ────────────────────────────┐
│ │
│ given: │
│ ✓ @customer is logged in │
│ ✓ cart has items │
│ │
│ :checkout ─────▶ ◆ ─────▶ :payment_request │
│ │
│ expect: │
│ ✓ order is in #awaiting_payment │
│ │
│ :payment_success ◀──── │
│ │
│ expect: │
│ ✓ order is in #paid │
│ ✓ @customer received :confirmation │
│ │
└─────────────────────────────────────────────────── PASS ✓ ──┘Marker Styles:
✓Green checkmark: Assertion passed✗Red X: Assertion failed○Gray circle: Not yet executed (during simulation)⏸Orange pause: Breakpoint
6. Wait Point Indicators
Highlighting where the system pauses for external input:
│
│ emit :payment_request to @payment
├─────────────────────────────────▶
│
│ ╔═══════════════════════════════╗
│ ║ ⏳ WAIT POINT ║
│ ║ waiting for: ║
│ ║ • :payment_success ║
│ ║ • :payment_failed ║
│ ╚═══════════════════════════════╝
│
│ :payment_success
│◀─────────────────────────────────7. Context Panel
Side panel showing variable changes:
┌─────────────────────────────────────────────────────────────┐
│ CONTEXT CHANGES │
├─────────────────────────────────────────────────────────────┤
│ │
│ After :checkout: │
│ $order_id: "ord-12345" (new) │
│ $total: 1225 (unchanged) │
│ │
│ After :payment_success: │
│ $paid_at: "2025-12-16T10:30:00Z" (new) │
│ $transaction_id: "txn-67890" (new) │
│ │
└─────────────────────────────────────────────────────────────┘Collapsible Regions
Multi-Level Hierarchy
NarrativeBoard supports three levels of collapsing:
▼ machine: @order [LEVEL 1: Machine]
│
├── ▼ scenario: checkout [LEVEL 2: Scenario]
│ │
│ ├── given: cart has items
│ │
│ ├── ▶ on :checkout (api) [LEVEL 3: Event - collapsed]
│ │
│ ├── ▼ on :payment_success [LEVEL 3: Event - expanded]
│ │ │
│ │ ├── order moves to #paid
│ │ ├── $paid_at becomes now
│ │ └── emit :confirmation to @customer
│ │
│ └── expect: order is in #paid
│
├── ▶ scenario: checkout with empty cart [LEVEL 2: Collapsed]
│
└── ▶ scenario: payment failure [LEVEL 2: Collapsed]Scenario-Level Collapse
Click scenario header to expand/collapse:
▶ scenario: successful checkout [3 events, 4 assertions] ✓
└── Click to expand...
▼ scenario: successful checkout [3 events, 4 assertions] ✓
├── given: @customer is logged in, cart has items
│
├── :checkout ─────▶ ◆ ─────▶ :payment_request
│ └─[#awaiting_payment]
│
├── :payment_success ◀────
│ └─[#paid]
│
└── expect: ✓ order is in #paidActor-Level Collapse
Hide/show specific actor lanes:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ ☑ @customer │ │ ☑ @order │ │ ☐ @payment │ ← Hidden
├──────────────┤ ├──────────────┤ └──────────────┘
│ │ │ │ │ │
│ ├───────│──│──────┤ │
│ │ │ │ │ │ Events to @payment
│ │ │ │ ├ - - - │─ shown as dotted
│ │ │ │ │ │Keyboard Shortcuts
| Shortcut | Action |
|---|---|
E | Expand all |
C | Collapse all |
1-9 | Toggle scenario N |
A | Toggle all actors |
Space | Toggle selected region |
Test Integration
Given-When-Then Visualization
Each scenario is visualized as a test case:
╔═══════════════════════════════════════════════════════════════════════════════╗
║ SCENARIO: customer can checkout with valid payment ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ ║
║ ┌─── GIVEN ───────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ ✓ @customer is logged in as "john@example.com" │ ║
║ │ ✓ @customer has verified payment method │ ║
║ │ ✓ cart contains: │ ║
║ │ | product | price | │ ║
║ │ | Laptop | 1200 | │ ║
║ │ | Mouse | 25 | │ ║
║ │ ✓ $total: number is 1225 │ ║
║ │ │ ║
║ └─────────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ ┌─── WHEN ────────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ @customer @order @payment │ ║
║ │ │ │ │ │ ║
║ │ │ :checkout │ │ │ ║
║ │ ├──────────────▶│ │ │ ║
║ │ │ │ │ │ ║
║ │ │ │◆─────────────▶│ :payment_request │ ║
║ │ │ │ │ │ ║
║ │ │ │◀──────────────│ :payment_success │ ║
║ │ │ │ │ │ ║
║ │ │◀──────────────│ │ :confirmation │ ║
║ │ │ │ │ │ ║
║ │ │ ║
║ └─────────────────────────────────────────────────────────────────────────┘ ║
║ ║
║ ┌─── THEN ────────────────────────────────────────────────────────────────┐ ║
║ │ │ ║
║ │ ✓ order is in #paid │ ║
║ │ ✓ @customer received :confirmation │ ║
║ │ ✓ $total equals 1225 │ ║
║ │ │ ║
║ └─────────────────────────────────────────────────────────────────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
[ PASS ✓ ]Scenario Path Overlay
Multiple scenarios shown as different paths through the same diagram:
@customer @order @payment
│ │ │
│ :checkout │ │
├────────────────────▶│ │
│ │ │
│ ◆ cart not empty? │
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ [true] [false] │
│ │ │ │
│ │ ═══════════════════════ │ ← Path: successful checkout
│ │ │ │
│ │ - - - - - - - -│- - - - - │ ← Path: empty cart (dashed)
│ │ │ │
│ ▼ ▼ │
│ #awaiting_payment :error │
│ │ │Path Legend:
═══Solid thick: Happy path (default)───Solid thin: Alternative success path---Dashed: Error path- Colors: Green (pass), Red (fail), Gray (not executed)
Assertion Markers
Inline markers show assertion status:
expect:
✓ order is in #paid │ Passed
✓ @customer received :confirmation│ Passed
✗ $total equals 1000 │ Failed: Expected 1000, got 1225
○ $discount applied │ Not executedSimulation Mode
Step-by-Step Navigation
Manual control of scenario execution:
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ SIMULATION: checkout scenario Step 3 of 7 │
│ │
│ @customer @order @payment │
│ │ │ │ │
│ │ :checkout │ │ │
│ ├────────────────────▶│ │ ← Step 1: Event sent │
│ │ │ │ │
│ │ ◆ cart not empty? │ ← Step 2: Guard │
│ │ │ │ │
│ │ │ :payment_request │ │
│ │ ├ ═══════════════════▶│ ← Step 3: CURRENT │
│ │ │ │ ▲ │
│ │ │ :payment_success │ │ │
│ │ │◀────────────────────┤ ← Step 4: Waiting │
│ │ │ │ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ [◀ Prev] [▶ Next] [▶▶ Auto-play] [⏸ Pause] [↻ Reset] │
│ │
│ Speed: [Slow] [Normal] [Fast] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘Animated Replay
Auto-play with configurable speed:
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ ▶▶ PLAYING: checkout scenario [⏸ Click to pause] │
│ │
│ Progress: ════════════════░░░░░░░░░░░░░░░░░░░░░░░░░░░ Step 3/7 │
│ │
│ @customer @order @payment │
│ │ │ │ │
│ │ :checkout │ │ │
│ ╞════════════════════▶│ │ ✓ Completed │
│ │ │ │ │
│ │ ◆ cart not empty? │ ✓ true → continue │
│ │ │ │ │
│ │ │ :payment_request │ │
│ │ ╞═════════════════ ▸ ▸│ ⟳ Animating... │
│ │ │ │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘Breakpoints
Pause at specific points:
on :checkout from @customer (api)
? cart is not empty ⏸ ← Breakpoint set
order moves to #awaiting_payment
emit :payment_request to @payment
Simulation paused at breakpoint:
Guard: ? cart is not empty
Result: true
Context: { cart: { items: [...] }, total: 1225 }
[Continue] [Step Into] [Skip Guard]Context Inspector
View context state at any simulation step:
┌───────────────────────────────────────────────────────────┐
│ CONTEXT INSPECTOR Step 3 of 7 │
├───────────────────────────────────────────────────────────┤
│ │
│ $order_id: "ord-abc123" (set at step 1) │
│ $customer: { id: "cust-456", email: "j@example.com" } │
│ $total: 1225 (unchanged) │
│ $items: ["Laptop", "Mouse"] (unchanged) │
│ │
│ STATE: #awaiting_payment (changed at step 2) │
│ │
│ PENDING: │
│ - Waiting for :payment_success from @payment │
│ - Waiting for :payment_failed from @payment │
│ │
└───────────────────────────────────────────────────────────┘Coverage Visualization
Coverage Heatmap
Overlay showing test coverage intensity:
┌─────────────────────────────────────────────────────────────────────────────┐
│ COVERAGE HEATMAP │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ @customer @order @payment │
│ │ │ │ │
│ │ :checkout │ │ │
│ ├═══════════════════▶│ │ ████ 7 tests │
│ │ │ │ │
│ │ ◆ cart not empty? │ ████ both branches │
│ │ │ │ │
│ │ │ :payment_request │ │
│ │ ├───────────────────▶│ ██░░ 2 tests │
│ │ │ │ │
│ │ │ :payment_success │ │
│ │ │◀────────────────────│ ██░░ 2 tests │
│ │ │ │ │
│ │ │ :payment_failed │ │
│ │ │◀--------------------│ ░░░░ 0 tests ⚠ │
│ │ │ │ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Legend: ████ High coverage ██░░ Medium ░░░░ None ⚠ Untested │
│ │
│ Overall: 85% events tested | 100% guards both branches | 90% states │
│ │
└─────────────────────────────────────────────────────────────────────────────┘Coverage Summary Panel
┌───────────────────────────────────────────────────────────┐
│ COVERAGE SUMMARY │
├───────────────────────────────────────────────────────────┤
│ │
│ Events: │
│ :checkout ████████████ 7 tests │
│ :payment_success ████░░░░░░░░ 2 tests │
│ :payment_failed ████░░░░░░░░ 2 tests │
│ :ship ████░░░░░░░░ 2 tests │
│ :cancel ░░░░░░░░░░░░ 0 tests ⚠ │
│ │
│ Guards: │
│ ? cart is not empty ✓ both branches │
│ ? payment successful ✓ both branches │
│ ? $total > 1000 ✓ both branches │
│ ? $retry_count < 3 ░ only true tested ⚠ │
│ │
│ States: │
│ #awaiting_payment ✓ entry/exit tested │
│ #paid ✓ entry tested │
│ #shipped ✓ entry tested │
│ #cancelled ░ not tested ⚠ │
│ │
├───────────────────────────────────────────────────────────┤
│ Total Coverage: 87% (26/30 paths) │
└───────────────────────────────────────────────────────────┘Untested Path Highlighting
@customer @order @payment
│ │ │
│ :checkout │ │
├────────────────────▶│ │
│ │ │
│ ◆ cart not empty? │
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ [true] [false] │
│ │ │ │
│ │ ┌─────────────────┐ │
│ │ │ UNTESTED PATH │ │ ← Red highlight
│ │ │ :empty_cart_err │ │
│ │ └─────────────────┘ │
│ │ │Technical Implementation
Rendering Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│ NarrativeBoard Renderer │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ .flow file │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Parser │ → AST (Abstract Syntax Tree) │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Analyzer │ → Graph Model (actors, events, states, guards) │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Layouter │ → Positioned Graph (x, y coordinates) │
│ └──────┬───────┘ │
│ │ │
│ ├─────────────────────┬─────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ SVG Render │ │ PNG Render │ │ HTML Render │ │
│ └──────────────┘ └──────────────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ │ ▼ │
│ │ │ ┌──────────────┐ │
│ │ │ │ Interactive │ │
│ │ │ │ Controls │ │
│ │ │ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ .svg .png .html │
│ │
└─────────────────────────────────────────────────────────────────────────────┘SVG Structure
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
<!-- Definitions -->
<defs>
<marker id="arrow" .../>
<marker id="async-arrow" .../>
<pattern id="diamond" .../>
</defs>
<!-- Actor Lanes -->
<g class="actor-lanes">
<g class="actor" data-actor="customer">
<rect class="lane-header" .../>
<text class="lane-title">@customer</text>
<line class="lane-timeline" .../>
</g>
<!-- More actors... -->
</g>
<!-- Scenarios (Collapsible) -->
<g class="scenario" data-scenario="checkout" data-collapsed="false">
<rect class="scenario-header" .../>
<text class="scenario-title">scenario: checkout</text>
<!-- Given Section -->
<g class="given-section">...</g>
<!-- Event Flows -->
<g class="event-flow">
<path class="event-arrow" d="..." marker-end="url(#arrow)"/>
<text class="event-label">:checkout</text>
</g>
<!-- Decision Diamond -->
<g class="decision">
<polygon class="diamond" points="..."/>
<text class="guard-label">? cart not empty</text>
</g>
<!-- State Badge -->
<g class="state-badge" data-state="awaiting_payment">
<rect class="badge-bg" .../>
<text class="badge-label">#awaiting_payment</text>
</g>
<!-- Expect Section -->
<g class="expect-section">...</g>
</g>
</svg>Interactive HTML Template
<!DOCTYPE html>
<html>
<head>
<title>NarrativeBoard: order.flow</title>
<style>
/* Collapsible regions */
.scenario[data-collapsed="true"] .scenario-content { display: none; }
.actor[data-hidden="true"] { opacity: 0.3; }
/* Test markers */
.assertion.pass { color: #40c057; }
.assertion.fail { color: #fa5252; }
/* Coverage heatmap */
.coverage-high { fill: #40c057; }
.coverage-medium { fill: #fab005; }
.coverage-low { fill: #fa5252; }
/* Simulation highlight */
.current-step { stroke-width: 3; stroke: #228be6; }
</style>
</head>
<body>
<!-- Controls -->
<div id="controls">
<button onclick="expandAll()">Expand All</button>
<button onclick="collapseAll()">Collapse All</button>
<button onclick="toggleCoverage()">Coverage</button>
<button onclick="startSimulation()">▶ Simulate</button>
</div>
<!-- Diagram -->
<div id="diagram-container">
<!-- SVG rendered here -->
</div>
<!-- Context Panel -->
<aside id="context-panel">
<h3>Context</h3>
<pre id="context-json"></pre>
</aside>
<!-- Simulation Controls -->
<div id="simulation-controls" style="display: none;">
<button onclick="prevStep()">◀ Prev</button>
<button onclick="nextStep()">▶ Next</button>
<button onclick="autoPlay()">▶▶ Play</button>
<input type="range" id="speed" min="1" max="10" value="5"/>
<button onclick="resetSimulation()">↻ Reset</button>
</div>
<script src="narrativeboard.js"></script>
</body>
</html>CLI Commands
Generate NarrativeBoard
# Default NarrativeBoard (replaces --type=combined)
eventflow diagram order.flow
# Explicit NarrativeBoard type
eventflow diagram order.flow --type=narrative
# Specific scenario only
eventflow diagram order.flow --type=narrative --scenario="checkout"
# Multiple scenarios
eventflow diagram order.flow --type=narrative --scenario="checkout,payment failure"
# Interactive HTML output
eventflow diagram order.flow --type=narrative --format=html
# Serve locally with hot reload
eventflow diagram order.flow --type=narrative --serve
# Export formats
eventflow diagram order.flow --type=narrative --format=svg --output=order-diagram.svg
eventflow diagram order.flow --type=narrative --format=png --output=order-diagram.png
eventflow diagram order.flow --type=narrative --format=pdf --output=order-diagram.pdfCoverage Mode
# Generate with coverage overlay
eventflow diagram order.flow --type=narrative --coverage
# Coverage from specific test file
eventflow diagram order.flow --type=narrative --coverage --tests=order.test.flow
# Coverage threshold warning
eventflow diagram order.flow --type=narrative --coverage --min-coverage=80Simulation Mode
# Open in simulation mode
eventflow diagram order.flow --type=narrative --simulate
# Simulate specific scenario
eventflow diagram order.flow --type=narrative --simulate --scenario="checkout"
# Auto-play simulation
eventflow diagram order.flow --type=narrative --simulate --autoplay
# Record simulation as GIF
eventflow diagram order.flow --type=narrative --simulate --record=simulation.gifCollapse Options
# Start with all scenarios collapsed
eventflow diagram order.flow --type=narrative --collapsed
# Expand specific scenario
eventflow diagram order.flow --type=narrative --expand="checkout"
# Hide specific actors
eventflow diagram order.flow --type=narrative --hide-actors="@inventory,@shipping"Examples
E-Commerce Checkout
Source: order.flow
machine: @order
scenario: successful checkout
given:
@customer is logged in
cart contains:
| product | price |
| Laptop | 1200 |
| Mouse | 25 |
$total: number is 1225
on :checkout from @customer (api)
? cart is not empty
order moves to #awaiting_payment
emit :payment_request to @payment
with $order_id, $total
expect:
= order is in #awaiting_payment
= :payment_request was emitted to @payment
on :payment_success from @payment
order moves to #paid
emit :reserve_stock to @inventory
with $order_id, $items
on :stock_reserved from @inventory
order moves to #confirmed
emit :confirmation to @customer
expect:
= order is in #confirmed
= @customer received :confirmationGenerated NarrativeBoard:
╔═══════════════════════════════════════════════════════════════════════════════════════════╗
║ @order · NarrativeBoard ║
╠═══════════════════════════════════════════════════════════════════════════════════════════╣
║ ║
║ ▼ scenario: successful checkout PASS ║
║ │ ║
║ │ given: ║
║ │ ✓ @customer is logged in ║
║ │ ✓ cart contains: Laptop ($1200), Mouse ($25) ║
║ │ ✓ $total is 1225 ║
║ │ ║
║ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ║
║ │ │ @customer │ │ @order │ │ @payment │ │ @inventory │ ║
║ │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ ║
║ │ │ │ │ │ ║
║ │ │ :checkout │ │ │ ║
║ │ ├═════════════════▶│ │ │ ║
║ │ │ │ │ │ ║
║ │ │ ◆ cart not empty? │ │ ║
║ │ │ │ [true] ✓ │ │ ║
║ │ │ │ │ │ ║
║ │ │ │[#awaiting_payment] │ ║
║ │ │ │ │ │ ║
║ │ │ │ :payment_request │ │ ║
║ │ │ ├─────────────────▶│ │ ║
║ │ │ │ │ │ ║
║ │ │ expect: ✓ order is in #awaiting_payment ║
║ │ │ ✓ :payment_request was emitted to @payment ║
║ │ │ │ │ │ ║
║ │ │ │ │ │ ║
║ │ │ │:payment_success │ │ ║
║ │ │ │◀─────────────────┤ │ ║
║ │ │ │ │ │ ║
║ │ │ │ [#paid] │ │ ║
║ │ │ │ │ │ ║
║ │ │ │ :reserve_stock │ ║
║ │ │ ├─────────────────────────────────────▶│ ║
║ │ │ │ │ │ ║
║ │ │ │ │ │ ║
║ │ │ │ :stock_reserved │ ║
║ │ │ │◀─────────────────────────────────────┤ ║
║ │ │ │ │ │ ║
║ │ │ │ [#confirmed] │ │ ║
║ │ │ │ │ │ ║
║ │ │ :confirmation │ │ │ ║
║ │ │◀═════════════════│ │ │ ║
║ │ │ │ │ │ ║
║ │ ║
║ │ expect: ║
║ │ ✓ order is in #confirmed ║
║ │ ✓ @customer received :confirmation ║
║ │ ║
║ └────────────────────────────────────────────────────────────────────────────────────────║
║ ║
║ ▶ scenario: checkout with empty cart PASS ║
║ ▶ scenario: payment failure PASS ║
║ ║
╠═══════════════════════════════════════════════════════════════════════════════════════════╣
║ [◀ Prev] [▶ Next] [▶▶ Play] [Coverage: 94%] [Expand All] [Collapse All] ║
╚═══════════════════════════════════════════════════════════════════════════════════════════╝SVG Rendering:
Migration from Current Diagrams
Compatibility
NarrativeBoard is designed as a replacement, not an addition:
| Current | NarrativeBoard | Notes |
|---|---|---|
--type=lane | Default view | Actor lanes are always shown |
--type=state | State badges inline | States shown within the flow |
--type=combined | Full NarrativeBoard | Everything in one view |
Deprecation Plan
- Phase 1: Introduce NarrativeBoard as
--type=narrative - Phase 2: Make NarrativeBoard the default (
--typedefaults tonarrative) - Phase 3: Deprecate
--type=lane,--type=state,--type=combinedwith warnings - Phase 4: Remove deprecated types (major version)
Configuration
# eventflow.yaml
diagram:
default_type: narrative # or lane/state/combined for backward compat
narrative:
default_collapsed: false
show_coverage: true
show_context_panel: trueRelated Proposals
- IMPLICIT_STATES_V2_PROPOSAL.md - State derivation that powers NarrativeBoard state badges
- LANE_STATE_DIAGRAMS_PROPOSAL.md - Previous combined diagram proposal (superseded by NarrativeBoard)
Open Questions
Performance: How to handle very large systems (50+ actors, 100+ events)?
- Proposed: Virtual scrolling, progressive loading, focus mode
Print Output: How should NarrativeBoard look when printed to PDF?
- Proposed: Auto-expand all, hide controls, optimize for A3 landscape
Dark Mode: Should NarrativeBoard support dark mode?
- Proposed: Yes, with CSS variables for theming
Accessibility: How to make NarrativeBoard accessible?
- Proposed: ARIA labels, keyboard navigation, screen reader support
Embedding: How to embed NarrativeBoard in external docs?
- Proposed:
<iframe>embed code, exported HTML, web components
- Proposed:
Changelog
| Version | Date | Changes |
|---|---|---|
| v1.0 | 2025-12-16 | Initial proposal |
Appendix: Visual Reference
Color Palette
| Color | Usage | Hex |
|---|---|---|
| Blue | Events, arrows | #228be6 |
| Green | Success states, passing tests | #40c057 |
| Red | Failure states, failing tests | #fa5252 |
| Yellow | Warning, pending | #fab005 |
| Gray | Neutral, disabled | #868e96 |
| White | Background | #ffffff |
| Dark | Text | #212529 |
Icon Reference
| Icon | Meaning |
|---|---|
▶ | Collapsed region |
▼ | Expanded region |
◆ | Decision/guard point |
✓ | Passed assertion |
✗ | Failed assertion |
○ | Not executed |
⏳ | Wait point |
⏸ | Breakpoint/pause |
Typography
| Element | Font | Size |
|---|---|---|
| Actor name | System UI, Bold | 12px |
| Event name | Monospace | 11px |
| State name | Monospace | 10px |
| Guard text | System UI, Italic | 10px |
| Assertion | System UI | 10px |