Skip to content

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 .flow files 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:

DiagramPurposeLimitation
Lane DiagramActor communicationNo state visibility
State DiagramState transitionsNo actor context
Combined DiagramBothComplex, no interactivity

Pain Points:

  1. Context Switching: Users must switch between diagram types to understand the full picture
  2. No Test Visibility: Current diagrams don't show test coverage or scenario paths
  3. Static Only: No simulation or step-through capability
  4. Information Overload: Large systems become overwhelming without collapse/expand
  5. 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 .flow files
  • 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 / false or 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 #paid

Actor-Level Collapse

Hide/show specific actor lanes:

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ ☑ @customer  │  │ ☑ @order     │  │ ☐ @payment   │ ← Hidden
├──────────────┤  ├──────────────┤  └──────────────┘
│      │       │  │      │       │
│      ├───────│──│──────┤       │
│      │       │  │      │       │  Events to @payment
│      │       │  │      ├ - - - │─ shown as dotted
│      │       │  │      │       │

Keyboard Shortcuts

ShortcutAction
EExpand all
CCollapse all
1-9Toggle scenario N
AToggle all actors
SpaceToggle 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 executed

Simulation 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

xml
<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

html
<!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

bash
# 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.pdf

Coverage Mode

bash
# 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=80

Simulation Mode

bash
# 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.gif

Collapse Options

bash
# 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

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 :confirmation

Generated 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:

@order · NarrativeBoardscenario: successful checkoutPASSgiven:@customer is logged incart contains: Laptop ($1200), Mouse ($25)$total is 1225@customer@order@payment@inventory:checkoutAPI?cart not empty?[true] ✓#awaiting_payment:payment_requestexpect:✓ order is in #awaiting_payment ✓ :payment_request emitted:payment_success#paid:reserve_stock:stock_reserved#confirmed:confirmationexpect:order is in #confirmed@customer received :confirmationscenario: checkout with empty cartPASSscenario: payment failurePASS◀ Prev▶ Next▶▶ PlayCoverage: 94%Expand AllCollapse All◆ = Guard█ = State→ = Event✓ = Pass

Migration from Current Diagrams

Compatibility

NarrativeBoard is designed as a replacement, not an addition:

CurrentNarrativeBoardNotes
--type=laneDefault viewActor lanes are always shown
--type=stateState badges inlineStates shown within the flow
--type=combinedFull NarrativeBoardEverything in one view

Deprecation Plan

  1. Phase 1: Introduce NarrativeBoard as --type=narrative
  2. Phase 2: Make NarrativeBoard the default (--type defaults to narrative)
  3. Phase 3: Deprecate --type=lane, --type=state, --type=combined with warnings
  4. Phase 4: Remove deprecated types (major version)

Configuration

yaml
# eventflow.yaml
diagram:
  default_type: narrative  # or lane/state/combined for backward compat

  narrative:
    default_collapsed: false
    show_coverage: true
    show_context_panel: true


Open Questions

  1. Performance: How to handle very large systems (50+ actors, 100+ events)?

    • Proposed: Virtual scrolling, progressive loading, focus mode
  2. Print Output: How should NarrativeBoard look when printed to PDF?

    • Proposed: Auto-expand all, hide controls, optimize for A3 landscape
  3. Dark Mode: Should NarrativeBoard support dark mode?

    • Proposed: Yes, with CSS variables for theming
  4. Accessibility: How to make NarrativeBoard accessible?

    • Proposed: ARIA labels, keyboard navigation, screen reader support
  5. Embedding: How to embed NarrativeBoard in external docs?

    • Proposed: <iframe> embed code, exported HTML, web components

Changelog

VersionDateChanges
v1.02025-12-16Initial proposal

Appendix: Visual Reference

Color Palette

ColorUsageHex
BlueEvents, arrows#228be6
GreenSuccess states, passing tests#40c057
RedFailure states, failing tests#fa5252
YellowWarning, pending#fab005
GrayNeutral, disabled#868e96
WhiteBackground#ffffff
DarkText#212529

Icon Reference

IconMeaning
Collapsed region
Expanded region
Decision/guard point
Passed assertion
Failed assertion
Not executed
Wait point
Breakpoint/pause

Typography

ElementFontSize
Actor nameSystem UI, Bold12px
Event nameMonospace11px
State nameMonospace10px
Guard textSystem UI, Italic10px
AssertionSystem UI10px

Released under the MIT License.