@formicoidea/labre-framework-ddd-event-storming 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ import type { GfxController } from '@formicoidea/labre-core/std/gfx';
2
+ /** Create the board at the viewport centre, select it, return to the default tool. */
3
+ export declare function createEventStormingBoard(gfx: GfxController): void;
4
+ /**
5
+ * Activate the native connector tool, pre-styled and TYPED as a flow. The user
6
+ * then drags from what happens first to what follows, and the endpoints attach.
7
+ *
8
+ * ## Why this replaces the old palette entry
9
+ *
10
+ * Until WS5 the Flow entry dropped a 220-unit arrow at the viewport centre: a
11
+ * line between two points in mid-air, attached to nothing. It looked like the
12
+ * notation and said nothing — no rule could read its ends, and the user still
13
+ * had to drag both endpoints onto the stickies by hand.
14
+ *
15
+ * The gesture now IS the statement (`docs/adr/0010`): the tool announces which
16
+ * way to drag (the role's `gestureHint` — "drag from what happens first to what
17
+ * follows"), the drawn connector carries `es:flow`, and its endpoints are real
18
+ * element references. That is what makes both `es.against-timeline` and
19
+ * `es.forbidden-arc` possible at all.
20
+ *
21
+ * ## What the style says, and what the role says
22
+ *
23
+ * Style is presentation: a plain straight line with a rear arrowhead, which is
24
+ * exactly what the old drawing looked like, so a board mixing arcs drawn before
25
+ * and after WS5 still reads as one board. Meaning is the role, and only the
26
+ * role: restyling an arc never changes what it means, and an arc drawn before
27
+ * WS5 keeps its look and stays neutral.
28
+ */
29
+ export declare function activateEventStormingFlow(gfx: GfxController): void;
@@ -0,0 +1,78 @@
1
+ import { backgroundSize, DefaultTool } from '@formicoidea/labre-core/blocks/surface';
2
+ import { ConnectorTool } from '@formicoidea/labre-core/gfx/connector';
3
+ import { LABEL_COLOR } from '@formicoidea/labre-ddd-shared';
4
+ import { ConnectorMode, PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
5
+ import { Bound } from '@formicoidea/labre-core/global/gfx';
6
+ import { EVENT_STORMING_BACKGROUND } from './background.js';
7
+ import { ES_ROLE } from './roles.js';
8
+ /**
9
+ * Creation / activation actions for the Event Storming toolbox — the BEHAVIOUR
10
+ * layer, depending on nothing but the {@link GfxController}.
11
+ *
12
+ * They emit no telemetry: since PF3 the single emission point is the command
13
+ * registry's `runCommand` (`docs/adr/0008`).
14
+ */
15
+ const FLOW_STROKE_WIDTH = 2;
16
+ /** Create the board at the viewport centre, select it, return to the default tool. */
17
+ export function createEventStormingBoard(gfx) {
18
+ if (!gfx.surface)
19
+ return;
20
+ const { width, height } = backgroundSize(EVENT_STORMING_BACKGROUND);
21
+ const { centerX, centerY } = gfx.viewport;
22
+ const id = gfx.surface.addElement({
23
+ type: EVENT_STORMING_BACKGROUND.type,
24
+ // The board is a first-class role: rules frame stickies against `es:board`,
25
+ // never against the `eventStorming` element type. The declaration owns it,
26
+ // so a templated board and a hand-drawn one agree.
27
+ role: EVENT_STORMING_BACKGROUND.role,
28
+ resizeEnabled: EVENT_STORMING_BACKGROUND.geometry.resizable,
29
+ xywh: new Bound(centerX - width / 2, centerY - height / 2, width, height).serialize(),
30
+ });
31
+ gfx.doc.captureSync();
32
+ gfx.tool.setTool(DefaultTool);
33
+ gfx.selection.set({ elements: [id], editing: false });
34
+ }
35
+ /**
36
+ * Activate the native connector tool, pre-styled and TYPED as a flow. The user
37
+ * then drags from what happens first to what follows, and the endpoints attach.
38
+ *
39
+ * ## Why this replaces the old palette entry
40
+ *
41
+ * Until WS5 the Flow entry dropped a 220-unit arrow at the viewport centre: a
42
+ * line between two points in mid-air, attached to nothing. It looked like the
43
+ * notation and said nothing — no rule could read its ends, and the user still
44
+ * had to drag both endpoints onto the stickies by hand.
45
+ *
46
+ * The gesture now IS the statement (`docs/adr/0010`): the tool announces which
47
+ * way to drag (the role's `gestureHint` — "drag from what happens first to what
48
+ * follows"), the drawn connector carries `es:flow`, and its endpoints are real
49
+ * element references. That is what makes both `es.against-timeline` and
50
+ * `es.forbidden-arc` possible at all.
51
+ *
52
+ * ## What the style says, and what the role says
53
+ *
54
+ * Style is presentation: a plain straight line with a rear arrowhead, which is
55
+ * exactly what the old drawing looked like, so a board mixing arcs drawn before
56
+ * and after WS5 still reads as one board. Meaning is the role, and only the
57
+ * role: restyling an arc never changes what it means, and an arc drawn before
58
+ * WS5 keeps its look and stays neutral.
59
+ */
60
+ export function activateEventStormingFlow(gfx) {
61
+ gfx.tool.setTool(ConnectorTool, {
62
+ mode: ConnectorMode.Straight,
63
+ role: ES_ROLE.flow,
64
+ // The look rides on the activation, never through the last-props store:
65
+ // the plain connector tool must keep the user's own style (#144 M1).
66
+ style: {
67
+ stroke: LABEL_COLOR,
68
+ strokeStyle: StrokeStyle.Solid,
69
+ strokeWidth: FLOW_STROKE_WIDTH,
70
+ frontEndpointStyle: PointStyle.None,
71
+ // The arrow points at what FOLLOWS, which is the target: the role's
72
+ // verb is "leads to", so the source is what happens first.
73
+ rearEndpointStyle: PointStyle.Arrow,
74
+ },
75
+ });
76
+ // The Event Storming palette stays open (native sub-menu behaviour): it only
77
+ // closes on re-click of the senior button, another senior tool, or Escape.
78
+ }
@@ -0,0 +1,2 @@
1
+ import type { FrameworkBackgroundDef } from '@formicoidea/labre-core/blocks/surface';
2
+ export declare const EVENT_STORMING_BACKGROUND: FrameworkBackgroundDef;
@@ -0,0 +1,138 @@
1
+ import { ES_STICKIES, FONT_FAMILY } from '@formicoidea/labre-ddd-shared';
2
+ import { ES_ROLE } from './roles.js';
3
+ /**
4
+ * The Event Storming board, DECLARED (the `FrameworkBackgroundDef` primitive).
5
+ *
6
+ * ## One axis, and only one
7
+ *
8
+ * Time, running left to right along the bottom. That is the entire frame of
9
+ * reference Event Storming has, and declaring exactly it — no second axis, no
10
+ * zones, no graduations — is what makes `es.against-timeline` a real rule
11
+ * rather than a guess: a flow whose target sits to the LEFT of its source runs
12
+ * against the only direction this board means anything in.
13
+ *
14
+ * The vertical is deliberately unnamed. On a real wall it is where a workshop
15
+ * parks what it cannot place yet — a stack of hotspots above the frieze, a row
16
+ * of read models below it — and a tool that quietly turned "higher" into a
17
+ * scale would be inventing a semantic the framework does not have and then
18
+ * judging people against it.
19
+ *
20
+ * ## Swimlanes: cut from v1
21
+ *
22
+ * The v2 shape is written down in `EventStormingBoardElementModel`: lanes are a
23
+ * variant declaration plus a rule family that measures membership per band.
24
+ * Painting the bands without the rule would be the vertical semantic above,
25
+ * arrived at by accident.
26
+ *
27
+ * ## The palette
28
+ *
29
+ * The eight sticky colours, named. Nothing here paints them — the board is a
30
+ * white card with an axis on it — and that is what a declared REFERENCE looks
31
+ * like: the same precedent as the Wardley tone convention, so the day a
32
+ * `tone-convention` rule asks "is this sticky drawn in one of the notation's
33
+ * own colours" the answer is already written down, in one place, beside the
34
+ * card it belongs to.
35
+ */
36
+ /** Ink for the frame itself: the axis line and the word beside it. */
37
+ const AXIS_COLOR = '#6d6e71';
38
+ const CARD_BORDER = '#d5d9e0';
39
+ /**
40
+ * The one word this board writes on itself, and it is written BIG: 64 units
41
+ * (PO recette, 26/08/2026).
42
+ *
43
+ * Sixteen was chart-label size — right for a graduation, wrong for the only
44
+ * thing a 3200-wide roll declares. At the zoom where a whole Big Picture fits on
45
+ * screen the word vanished exactly like the hairline trait did before it was
46
+ * drawn at six; the title now reads at the same distance as the axis it names.
47
+ * Sized WITH the trait rather than beside it, and everything that has to make
48
+ * room for it — the bottom margin, the title's own offset — is derived from this
49
+ * number below.
50
+ */
51
+ const AXIS_TEXT = { size: 64, color: '@axis' };
52
+ /** The eight sticky fills, keyed by the kind the palette creates them under. */
53
+ const STICKY_PALETTE = Object.fromEntries(ES_STICKIES.map(preset => [preset.kind, preset.fill]));
54
+ export const EVENT_STORMING_BACKGROUND = {
55
+ type: 'eventStorming',
56
+ // The board is a first-class role: rules frame stickies against `es:board`,
57
+ // never against the `eventStorming` element type.
58
+ role: ES_ROLE.board,
59
+ geometry: {
60
+ // A Big Picture is WIDE — the timeline is the point — and it grows sideways
61
+ // all morning as events are remembered. Neither dimension is locked to the
62
+ // other and the handles are offered from the start, the opposite call from
63
+ // the Wardley map, which is a frame you place things on rather than a roll
64
+ // you unspool.
65
+ width: 3200,
66
+ height: 1400,
67
+ lockAspectRatio: false,
68
+ resizable: true,
69
+ // Room under the plot for the axis line and its word; the same inset
70
+ // elsewhere, so the roll reads as paper rather than as a chart.
71
+ //
72
+ // The bottom is the exception, and it is the WORD that sets it: a 64-unit
73
+ // title cannot be hung under a six-unit trait inside 56 units of paper —
74
+ // its cap height alone eats some 47 of them and its descender wants a dozen
75
+ // more. 104 is the title's offset below the trait plus a descender's worth
76
+ // of air, so the word sits between the trait and the card edge touching
77
+ // neither. Nothing else reads this number: the board declares no zones, and
78
+ // the stickies are placed by hand.
79
+ margin: { top: 32, right: 32, bottom: 104, left: 32 },
80
+ },
81
+ chrome: {
82
+ fontFamily: FONT_FAMILY,
83
+ palette: {
84
+ card: '#ffffff',
85
+ cardBorder: CARD_BORDER,
86
+ axis: AXIS_COLOR,
87
+ ...STICKY_PALETTE,
88
+ },
89
+ surface: {
90
+ fill: '@card',
91
+ border: { color: '@cardBorder', width: 1.5, radius: 12 },
92
+ },
93
+ },
94
+ axes: [
95
+ {
96
+ id: 'time',
97
+ orientation: 'horizontal',
98
+ // Along the bottom of the plot, under the frieze rather than through it.
99
+ at: 1,
100
+ // Forward is RIGHT: later. The one fact `es.against-timeline` reads.
101
+ arrow: 'forward',
102
+ // Drawn HEAVY, and deliberately heavier than any other axis in the
103
+ // library (PO recette, 26/08/2026). On a 3200-wide roll the timeline is
104
+ // not decoration beside the plot, it IS the frame of reference — the one
105
+ // thing the board declares and the one thing a rule measures against —
106
+ // and at the zoom where a whole Big Picture fits on screen a hairline
107
+ // simply disappears under the frieze. Six model units survive that.
108
+ //
109
+ // The head is sized WITH the line rather than left at its default: the
110
+ // renderer takes `arrowSize` as the head's LENGTH and spreads the base
111
+ // half that either side, so head width tracks head length. At 6× the
112
+ // stroke the triangle still reads as the end of this line and not as a
113
+ // separate mark — the same register as Wardley's 11-on-2, given room to
114
+ // scale up with the stroke.
115
+ arrowSize: 36,
116
+ stroke: { color: '@axis', width: 6 },
117
+ title: {
118
+ id: 'timeAxisTitle',
119
+ labelKey: 'com.labre.event-storming.background.axis.time',
120
+ fallback: 'Time',
121
+ // Pushed down with the SIZE, not just with the stroke.
122
+ //
123
+ // The renderer draws every background text on an `alphabetic`
124
+ // baseline, so `dy` positions the foot of the word and everything
125
+ // above it has to fit between the trait and that baseline: the trait
126
+ // grows three units below its centre (half of six) and the cap height
127
+ // of a 64-unit Inter is about 47. 72 clears both and leaves roughly the
128
+ // 23 units of air the 16-unit title used to have — the gap reads the
129
+ // same, it is simply no longer proportional to a word four times
130
+ // bigger. Below the baseline, the descender (~16) stops 16 units short
131
+ // of the 104-unit bottom margin, so the card edge is clear too.
132
+ anchor: { x: 1, y: 1, dx: -8, dy: 72 },
133
+ style: AXIS_TEXT,
134
+ align: 'right',
135
+ },
136
+ },
137
+ ],
138
+ };
package/dist/commands.js CHANGED
@@ -1,14 +1,43 @@
1
- import { addConnector, addSticky, ES_HOTSPOT, ES_STICKIES, placeDddElement, } from '@formicoidea/labre-ddd-shared';
1
+ import { addSticky, ES_HOTSPOT, ES_STICKIES, placeDddElement, STICKY_SIZE, } from '@formicoidea/labre-ddd-shared';
2
+ import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
2
3
  import { svg } from 'lit';
4
+ import { activateEventStormingFlow, createEventStormingBoard } from './actions.js';
5
+ import { ES_STICKY_ROLE } from './roles.js';
3
6
  /**
4
- * The Event Storming palette as commands: the seven colour-coded stickies, the
5
- * hotspot and a flow arrow. Declared once and read by the sub-menu, the keymap,
6
- * Settings › Shortcuts, the catalogue and the agent (`docs/adr/0008`).
7
+ * The Event Storming palette as commands: the board, the eight colour-coded
8
+ * stickies, the hotspot and the flow. Declared once and read by the sub-menu,
9
+ * the keymap, Settings › Shortcuts, the catalogue and the agent
10
+ * (`docs/adr/0008`).
11
+ *
12
+ * Three entries changed shape in WS5 and not one telemetry value moved: the
13
+ * stickies now carry their role, the flow arms the connector tool instead of
14
+ * dropping a drawing, and the board is a new entry with a new `element` value.
7
15
  */
8
16
  const squareSwatch = (color) => svg `<svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="3" fill="${color}"/></svg>`;
9
17
  const diamondSwatch = (color) => svg `<svg viewBox="0 0 24 24"><rect x="6" y="6" width="12" height="12" transform="rotate(45 12 12)" fill="${color}"/></svg>`;
10
18
  const flowSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><path d="M4 12 H18" stroke="currentColor" stroke-width="2"/><path d="M16 8 L20 12 L16 16" stroke="currentColor" stroke-width="2" fill="none"/></svg>`;
19
+ const boardSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><rect x="2.5" y="4" width="19" height="16" rx="2" fill="#ffffff" stroke="currentColor" stroke-width="1.6"/><rect x="5" y="7.5" width="4" height="4" rx="1" fill="#F5963B"/><rect x="10.5" y="7.5" width="4" height="4" rx="1" fill="#5BA3DB"/><rect x="16" y="7.5" width="4" height="4" rx="1" fill="#FAF2C9" stroke="#c9bd7f" stroke-width="0.6"/><path d="M4.5 16.5 H19.5" stroke="currentColor" stroke-width="1.2"/><path d="M17.5 14.8 L19.8 16.5 L17.5 18.2" stroke="currentColor" stroke-width="1.2"/></svg>`;
20
+ /**
21
+ * The aggregate is created BIG — 160 against the standard 120.
22
+ *
23
+ * Size is half of how the notation distinguishes it: on a real wall the
24
+ * aggregate is the large pale sticky a run of commands lands on, and the
25
+ * colour ladder in `ES_STICKIES` carries the other half. Declared here rather
26
+ * than in the shared palette because it is a FORMAT, not a colour: the palette
27
+ * says which yellow, the toolbox says how big.
28
+ */
29
+ const AGGREGATE_SIZE = 160;
11
30
  const SPECS = [
31
+ {
32
+ id: 'addBoard',
33
+ label: 'Event Storming board',
34
+ iconKey: 'ddd-event-storming.board',
35
+ // A NEW telemetry value: every other entry below keeps the `element` string
36
+ // it has emitted since ADR 0008.
37
+ element: 'board',
38
+ icon: boardSwatch,
39
+ run: std => createEventStormingBoard(std.get(GfxControllerIdentifier)),
40
+ },
12
41
  ...ES_STICKIES.map((preset) => ({
13
42
  id: `add${preset.kind[0].toUpperCase()}${preset.kind.slice(1)}`,
14
43
  label: preset.label,
@@ -19,6 +48,12 @@ const SPECS = [
19
48
  fill: preset.fill,
20
49
  text: preset.text,
21
50
  label: preset.label,
51
+ size: preset.kind === 'aggregate' ? AGGREGATE_SIZE : STICKY_SIZE,
52
+ // The role is what makes a sticky a domain EVENT rather than an
53
+ // orange square: every rule in `rules.ts` reads it, and a sticky
54
+ // placed before WS5 carries none and is never evaluated
55
+ // (promesse #71).
56
+ role: ES_STICKY_ROLE[preset.kind],
22
57
  })),
23
58
  })),
24
59
  {
@@ -32,6 +67,9 @@ const SPECS = [
32
67
  text: ES_HOTSPOT.text,
33
68
  label: ES_HOTSPOT.label,
34
69
  shapeType: 'diamond',
70
+ // Typed like the rest, and cited by no grammar triplet on purpose —
71
+ // an arc onto a hotspot is a question being parked. See `rules.ts`.
72
+ role: ES_STICKY_ROLE.hotspot,
35
73
  })),
36
74
  },
37
75
  {
@@ -40,7 +78,10 @@ const SPECS = [
40
78
  iconKey: 'ddd-event-storming.flow',
41
79
  element: 'flow',
42
80
  icon: flowSwatch,
43
- run: std => placeDddElement(std, (surface, cx, cy) => addConnector(surface, cx - 110, cy, cx + 110, cy, { rearArrow: true })),
81
+ // No longer a placement: the entry arms the connector tool and the user
82
+ // DRAWS the flow between two stickies. See `activateEventStormingFlow` for
83
+ // why the free-floating arrow had to go. The telemetry value is untouched.
84
+ run: std => activateEventStormingFlow(std.get(GfxControllerIdentifier)),
44
85
  },
45
86
  ];
46
87
  export const eventStormingCommands = SPECS.map((spec, order) => ({
@@ -1,7 +1,12 @@
1
- import { DddEventStormingViewExtension } from './view.js';
1
+ import { DddEventStormingRenderViewExtension, DddEventStormingViewExtension } from './view.js';
2
2
  /** Host wiring for the ddd-event-storming framework. */
3
3
  export declare const dddEventStormingFramework: {
4
4
  readonly flag: "ddd-event-storming";
5
5
  readonly telemetryKey: "event-storming";
6
- readonly viewExtension: typeof DddEventStormingViewExtension;
6
+ readonly extensions: readonly [{
7
+ readonly viewExtension: typeof DddEventStormingRenderViewExtension;
8
+ }, {
9
+ readonly flag: "ddd-event-storming";
10
+ readonly viewExtension: typeof DddEventStormingViewExtension;
11
+ }];
7
12
  };
@@ -1,7 +1,10 @@
1
- import { DddEventStormingViewExtension } from './view.js';
1
+ import { DddEventStormingRenderViewExtension, DddEventStormingViewExtension } from './view.js';
2
2
  /** Host wiring for the ddd-event-storming framework. */
3
3
  export const dddEventStormingFramework = {
4
4
  flag: 'ddd-event-storming',
5
5
  telemetryKey: 'event-storming',
6
- viewExtension: DddEventStormingViewExtension,
6
+ extensions: [
7
+ { viewExtension: DddEventStormingRenderViewExtension },
8
+ { flag: 'ddd-event-storming', viewExtension: DddEventStormingViewExtension },
9
+ ],
7
10
  };
@@ -0,0 +1,17 @@
1
+ import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
2
+ import type { EventStormingBoardElementModel } from '@formicoidea/labre-core/model';
3
+ /**
4
+ * Canvas renderer for the Event Storming board.
5
+ *
6
+ * There is no Event Storming drawing code: the board is an INSTANTIATION of the
7
+ * framework-background primitive, configured by the
8
+ * {@link EVENT_STORMING_BACKGROUND} declaration — a white card with one axis
9
+ * along the bottom.
10
+ *
11
+ * Exported as a function as well as an extension so a test can drive it with a
12
+ * canvas stub.
13
+ */
14
+ export declare const eventStorming: ElementRenderer<EventStormingBoardElementModel>;
15
+ export declare const EventStormingRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
16
+ identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<EventStormingBoardElementModel>>;
17
+ };
@@ -0,0 +1,15 @@
1
+ import { createFrameworkBackgroundRenderer, ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { EVENT_STORMING_BACKGROUND } from './background.js';
3
+ /**
4
+ * Canvas renderer for the Event Storming board.
5
+ *
6
+ * There is no Event Storming drawing code: the board is an INSTANTIATION of the
7
+ * framework-background primitive, configured by the
8
+ * {@link EVENT_STORMING_BACKGROUND} declaration — a white card with one axis
9
+ * along the bottom.
10
+ *
11
+ * Exported as a function as well as an extension so a test can drive it with a
12
+ * canvas stub.
13
+ */
14
+ export const eventStorming = createFrameworkBackgroundRenderer(EVENT_STORMING_BACKGROUND);
15
+ export const EventStormingRendererExtension = ElementRendererExtension(EVENT_STORMING_BACKGROUND.type, eventStorming);
@@ -0,0 +1,18 @@
1
+ import type { EventStormingBoardElementModel } from '@formicoidea/labre-core/model';
2
+ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
3
+ /**
4
+ * View for the Event Storming board. Registering it ensures `gfx.view.get(model)`
5
+ * returns a view (required so move / select interactions work).
6
+ *
7
+ * No double-click label editor, unlike the Wardley map: the only text on the
8
+ * card is the axis word, which the declaration owns and the model carries no
9
+ * prop for — there is nothing here the user edits in place.
10
+ */
11
+ export declare class EventStormingView extends GfxElementModelView<EventStormingBoardElementModel> {
12
+ static type: string;
13
+ }
14
+ /**
15
+ * Resize gating, from the primitive: the handles follow `resizeEnabled`, which
16
+ * the declaration seeds to `true` — the roll is unspooled as the morning goes.
17
+ */
18
+ export declare const EventStormingInteraction: import("@formicoidea/labre-core/store").ExtensionType;
@@ -0,0 +1,19 @@
1
+ import { FrameworkBackgroundInteractionExtension } from '@formicoidea/labre-core/blocks/surface';
2
+ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
3
+ import { EVENT_STORMING_BACKGROUND } from './background.js';
4
+ /**
5
+ * View for the Event Storming board. Registering it ensures `gfx.view.get(model)`
6
+ * returns a view (required so move / select interactions work).
7
+ *
8
+ * No double-click label editor, unlike the Wardley map: the only text on the
9
+ * card is the axis word, which the declaration owns and the model carries no
10
+ * prop for — there is nothing here the user edits in place.
11
+ */
12
+ export class EventStormingView extends GfxElementModelView {
13
+ static { this.type = 'eventStorming'; }
14
+ }
15
+ /**
16
+ * Resize gating, from the primitive: the handles follow `resizeEnabled`, which
17
+ * the declaration seeds to `true` — the roll is unspooled as the morning goes.
18
+ */
19
+ export const EventStormingInteraction = FrameworkBackgroundInteractionExtension(EVENT_STORMING_BACKGROUND);
package/dist/index.d.ts CHANGED
@@ -1,6 +1,11 @@
1
- export { eventStormingCommandIcons, eventStormingCommands } from './commands.js';
1
+ export { eventStormingCommandIcons, eventStormingCommands, } from './commands.js';
2
+ export { EVENT_STORMING_BACKGROUND } from './background.js';
3
+ export { EVENT_STORMING_NUDGES } from './nudges.js';
4
+ export { EVENT_STORMING_PROFILES } from './profiles.js';
5
+ export { ES_ROLE, ES_STICKY_ROLE, EVENT_STORMING_ROLES, type EventStormingRoleId, type EventStormingStickyKind, } from './roles.js';
6
+ export { ES_FLOW_MATRIX, EVENT_STORMING_RULES } from './rules.js';
2
7
  export { eventStormingTranslationEntries } from './translations.js';
3
8
  export { eventStormingTemplateCategory } from './templates.js';
4
9
  export { eventStormingSeniorTool } from './toolbar/senior-tool.js';
5
10
  export { EdgelessDddEventStormingSeniorButton } from './toolbar/senior-button.js';
6
- export { DddEventStormingViewExtension } from './view.js';
11
+ export { DddEventStormingRenderViewExtension, DddEventStormingViewExtension, } from './view.js';
package/dist/index.js CHANGED
@@ -1,6 +1,11 @@
1
- export { eventStormingCommandIcons, eventStormingCommands } from './commands.js';
1
+ export { eventStormingCommandIcons, eventStormingCommands, } from './commands.js';
2
+ export { EVENT_STORMING_BACKGROUND } from './background.js';
3
+ export { EVENT_STORMING_NUDGES } from './nudges.js';
4
+ export { EVENT_STORMING_PROFILES } from './profiles.js';
5
+ export { ES_ROLE, ES_STICKY_ROLE, EVENT_STORMING_ROLES, } from './roles.js';
6
+ export { ES_FLOW_MATRIX, EVENT_STORMING_RULES } from './rules.js';
2
7
  export { eventStormingTranslationEntries } from './translations.js';
3
8
  export { eventStormingTemplateCategory } from './templates.js';
4
9
  export { eventStormingSeniorTool } from './toolbar/senior-tool.js';
5
10
  export { EdgelessDddEventStormingSeniorButton } from './toolbar/senior-button.js';
6
- export { DddEventStormingViewExtension } from './view.js';
11
+ export { DddEventStormingRenderViewExtension, DddEventStormingViewExtension, } from './view.js';
@@ -0,0 +1,16 @@
1
+ import { type AutoLegendSpec } from '@formicoidea/labre-ddd-shared';
2
+ /**
3
+ * What the Event Storming board's automatic legend can say — a TABLE, and
4
+ * nothing else: the scan, the placement and the box are `createAutoLegend`'s
5
+ * job.
6
+ *
7
+ * Every row is DERIVED from the palette the stickies are drawn with
8
+ * ({@link ES_STICKIES}, {@link ES_HOTSPOT}) and from the role vocabulary's own
9
+ * labels, never restated — so the colour ladder the legend shows is by
10
+ * construction the colour ladder on the wall, and a tenth sticky kind added to
11
+ * `ES_STICKIES` gets its legend row with no edit.
12
+ *
13
+ * The hotspot is appended for the same reason `roles.ts` appends it: it lives in
14
+ * its own preset (a diamond, not a square) rather than in the table.
15
+ */
16
+ export declare const EVENT_STORMING_AUTO_LEGEND: AutoLegendSpec;
package/dist/legend.js ADDED
@@ -0,0 +1,58 @@
1
+ import { ES_HOTSPOT, ES_STICKIES, LABEL_COLOR, roleLabel, } from '@formicoidea/labre-ddd-shared';
2
+ import { ES_ROLE, ES_STICKY_ROLE, EVENT_STORMING_ROLES } from './roles.js';
3
+ /**
4
+ * What the Event Storming board's automatic legend can say — a TABLE, and
5
+ * nothing else: the scan, the placement and the box are `createAutoLegend`'s
6
+ * job.
7
+ *
8
+ * Every row is DERIVED from the palette the stickies are drawn with
9
+ * ({@link ES_STICKIES}, {@link ES_HOTSPOT}) and from the role vocabulary's own
10
+ * labels, never restated — so the colour ladder the legend shows is by
11
+ * construction the colour ladder on the wall, and a tenth sticky kind added to
12
+ * `ES_STICKIES` gets its legend row with no edit.
13
+ *
14
+ * The hotspot is appended for the same reason `roles.ts` appends it: it lives in
15
+ * its own preset (a diamond, not a square) rather than in the table.
16
+ */
17
+ export const EVENT_STORMING_AUTO_LEGEND = {
18
+ title: 'Legend',
19
+ roles: EVENT_STORMING_ROLES,
20
+ sections: [
21
+ {
22
+ title: 'Stickies',
23
+ entries: [
24
+ ...ES_STICKIES.map(preset => ({
25
+ role: ES_STICKY_ROLE[preset.kind],
26
+ row: {
27
+ swatch: 'square',
28
+ color: preset.fill,
29
+ label: preset.label,
30
+ },
31
+ })),
32
+ {
33
+ role: ES_STICKY_ROLE.hotspot,
34
+ row: {
35
+ swatch: 'square',
36
+ color: ES_HOTSPOT.fill,
37
+ label: ES_HOTSPOT.label,
38
+ },
39
+ },
40
+ ],
41
+ },
42
+ {
43
+ title: 'Flow',
44
+ entries: [
45
+ {
46
+ role: ES_ROLE.flow,
47
+ row: {
48
+ swatch: 'line',
49
+ // The style `activateEventStormingFlow` arms the connector tool
50
+ // with: a solid line in the label colour.
51
+ color: LABEL_COLOR,
52
+ label: roleLabel(EVENT_STORMING_ROLES, ES_ROLE.flow),
53
+ },
54
+ },
55
+ ],
56
+ },
57
+ ],
58
+ };
@@ -0,0 +1,26 @@
1
+ import type { QualityNudge } from '@formicoidea/labre-core/blocks/surface';
2
+ /**
3
+ * Event Storming **board quality** — the checklist (WS5, level 2).
4
+ *
5
+ * `./rules.ts` is level 1: deterministic, decidable, real time. This file is
6
+ * everything a board needs that no algorithm can decide. The split is the
7
+ * taxonomy's whole point — ticking is assuming, never verifying.
8
+ *
9
+ * ## The past tense lives HERE, and that was an arbitration
10
+ *
11
+ * "Order placed" is a domain event; "Place order" is a command. It is the first
12
+ * thing a facilitator corrects and the most tempting rule in the whole plan —
13
+ * and it is a nudge, by PO arbitration of 26/08/2026, because deciding it means
14
+ * parsing a human sentence. In whatever language the room speaks. Written in
15
+ * marker pen. By somebody who abbreviates. A regular expression over `Y.Text`
16
+ * would be wrong every fifth sticky, and a validation platform gets exactly one
17
+ * chance to be wrong about something the user can see is right.
18
+ *
19
+ * So it is a tick, and the tick is honest: it says the room LOOKED, which is
20
+ * what the facilitator wanted anyway.
21
+ *
22
+ * Registered from the flag-gated `DddEventStormingViewExtension`: a checklist
23
+ * is tooling. Switching the flag off takes it away and leaves the ticks written
24
+ * on the board, unread, until it comes back.
25
+ */
26
+ export declare const EVENT_STORMING_NUDGES: readonly QualityNudge[];
package/dist/nudges.js ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Event Storming **board quality** — the checklist (WS5, level 2).
3
+ *
4
+ * `./rules.ts` is level 1: deterministic, decidable, real time. This file is
5
+ * everything a board needs that no algorithm can decide. The split is the
6
+ * taxonomy's whole point — ticking is assuming, never verifying.
7
+ *
8
+ * ## The past tense lives HERE, and that was an arbitration
9
+ *
10
+ * "Order placed" is a domain event; "Place order" is a command. It is the first
11
+ * thing a facilitator corrects and the most tempting rule in the whole plan —
12
+ * and it is a nudge, by PO arbitration of 26/08/2026, because deciding it means
13
+ * parsing a human sentence. In whatever language the room speaks. Written in
14
+ * marker pen. By somebody who abbreviates. A regular expression over `Y.Text`
15
+ * would be wrong every fifth sticky, and a validation platform gets exactly one
16
+ * chance to be wrong about something the user can see is right.
17
+ *
18
+ * So it is a tick, and the tick is honest: it says the room LOOKED, which is
19
+ * what the facilitator wanted anyway.
20
+ *
21
+ * Registered from the flag-gated `DddEventStormingViewExtension`: a checklist
22
+ * is tooling. Switching the flag off takes it away and leaves the ticks written
23
+ * on the board, unread, until it comes back.
24
+ */
25
+ export const EVENT_STORMING_NUDGES = [
26
+ {
27
+ /** See the header: the rule that is deliberately not a rule. */
28
+ id: 'es.q1-events-past-tense',
29
+ framework: 'ddd-event-storming',
30
+ labelKey: 'com.labre.event-storming.quality.events-past-tense',
31
+ fallback: 'Domain events are named in the past tense — something that happened, not something to do.',
32
+ order: 1,
33
+ },
34
+ {
35
+ /**
36
+ * `es.against-timeline` judges each arc against the axis; nothing can judge
37
+ * whether the frieze as a whole tells the story the room means. Reading it
38
+ * out loud, left to right, is the move that finds the missing half of it.
39
+ */
40
+ id: 'es.q2-timeline-read',
41
+ framework: 'ddd-event-storming',
42
+ labelKey: 'com.labre.event-storming.quality.timeline-read',
43
+ fallback: 'The timeline has been read out loud left to right, and reordered where it did not hold.',
44
+ order: 2,
45
+ },
46
+ {
47
+ id: 'es.q3-hotspots-discussed',
48
+ framework: 'ddd-event-storming',
49
+ labelKey: 'com.labre.event-storming.quality.hotspots-discussed',
50
+ fallback: 'Every hotspot has been discussed — resolved, or assumed on purpose with a name against it.',
51
+ order: 3,
52
+ },
53
+ {
54
+ id: 'es.q4-actors-and-systems',
55
+ framework: 'ddd-event-storming',
56
+ labelKey: 'com.labre.event-storming.quality.actors-and-systems',
57
+ fallback: 'The actors and the external systems are identified: every command has someone who issues it.',
58
+ order: 4,
59
+ },
60
+ {
61
+ /**
62
+ * A pivotal event is a marking CONVENTION — a vertical bar, a bigger
63
+ * sticky, a line drawn on the paper — and the canvas cannot tell one from a
64
+ * sticky somebody happened to enlarge. What matters is that the room agreed
65
+ * which moments split the story, which is a conversation and not a shape.
66
+ */
67
+ id: 'es.q5-pivotal-events',
68
+ framework: 'ddd-event-storming',
69
+ labelKey: 'com.labre.event-storming.quality.pivotal-events',
70
+ fallback: 'The pivotal events are marked: the board says where the story changes phase.',
71
+ order: 5,
72
+ },
73
+ ];
@@ -0,0 +1,2 @@
1
+ import type { ValidationProfile } from '@formicoidea/labre-core/blocks/surface';
2
+ export declare const EVENT_STORMING_PROFILES: readonly ValidationProfile[];