@magicborn/dialogue-forge 0.1.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.
Files changed (241) hide show
  1. package/README.md +233 -0
  2. package/bin/dialogue-forge.js +78 -0
  3. package/demo/app/layout.tsx +36 -0
  4. package/demo/app/page.tsx +440 -0
  5. package/demo/components/ThemeSwitcher.tsx +611 -0
  6. package/demo/next.config.mjs +7 -0
  7. package/demo/package.json +29 -0
  8. package/demo/postcss.config.mjs +7 -0
  9. package/demo/public/logo.svg +1 -0
  10. package/demo/styles/globals.css +19 -0
  11. package/demo/tailwind.config.ts +90 -0
  12. package/demo/tsconfig.json +42 -0
  13. package/dist/components/ChoiceEdgeV2.d.ts +3 -0
  14. package/dist/components/ChoiceEdgeV2.js +103 -0
  15. package/dist/components/CodeBlock.d.ts +8 -0
  16. package/dist/components/CodeBlock.js +24 -0
  17. package/dist/components/ConditionAutocomplete.d.ts +14 -0
  18. package/dist/components/ConditionAutocomplete.js +284 -0
  19. package/dist/components/ConditionalNodeV2.d.ts +16 -0
  20. package/dist/components/ConditionalNodeV2.js +147 -0
  21. package/dist/components/DialogueEditorV2.d.ts +22 -0
  22. package/dist/components/DialogueEditorV2.js +1170 -0
  23. package/dist/components/EdgeIcon.d.ts +8 -0
  24. package/dist/components/EdgeIcon.js +13 -0
  25. package/dist/components/ExampleLoader.d.ts +11 -0
  26. package/dist/components/ExampleLoader.js +52 -0
  27. package/dist/components/ExampleLoaderButton.d.ts +15 -0
  28. package/dist/components/ExampleLoaderButton.js +102 -0
  29. package/dist/components/FlagManager.d.ts +11 -0
  30. package/dist/components/FlagManager.js +282 -0
  31. package/dist/components/FlagSelector.d.ts +11 -0
  32. package/dist/components/FlagSelector.js +235 -0
  33. package/dist/components/GuidePanel.d.ts +7 -0
  34. package/dist/components/GuidePanel.js +1176 -0
  35. package/dist/components/Minimap.d.ts +16 -0
  36. package/dist/components/Minimap.js +93 -0
  37. package/dist/components/NPCEdgeV2.d.ts +3 -0
  38. package/dist/components/NPCEdgeV2.js +104 -0
  39. package/dist/components/NPCNodeV2.d.ts +26 -0
  40. package/dist/components/NPCNodeV2.js +86 -0
  41. package/dist/components/NodeEditor.d.ts +18 -0
  42. package/dist/components/NodeEditor.js +1025 -0
  43. package/dist/components/PlayView.d.ts +12 -0
  44. package/dist/components/PlayView.js +307 -0
  45. package/dist/components/PlayerNodeV2.d.ts +16 -0
  46. package/dist/components/PlayerNodeV2.js +139 -0
  47. package/dist/components/ReactFlowPOC.d.ts +61 -0
  48. package/dist/components/ReactFlowPOC.js +312 -0
  49. package/dist/components/ScenePlayer.d.ts +18 -0
  50. package/dist/components/ScenePlayer.js +196 -0
  51. package/dist/components/YarnView.d.ts +9 -0
  52. package/dist/components/YarnView.js +45 -0
  53. package/dist/components/ZoomControls.d.ts +11 -0
  54. package/dist/components/ZoomControls.js +34 -0
  55. package/dist/esm/components/ChoiceEdgeV2.d.ts +3 -0
  56. package/dist/esm/components/ChoiceEdgeV2.js +67 -0
  57. package/dist/esm/components/CodeBlock.d.ts +8 -0
  58. package/dist/esm/components/CodeBlock.js +18 -0
  59. package/dist/esm/components/ConditionAutocomplete.d.ts +14 -0
  60. package/dist/esm/components/ConditionAutocomplete.js +248 -0
  61. package/dist/esm/components/ConditionalNodeV2.d.ts +16 -0
  62. package/dist/esm/components/ConditionalNodeV2.js +111 -0
  63. package/dist/esm/components/DialogueEditorV2.d.ts +22 -0
  64. package/dist/esm/components/DialogueEditorV2.js +1134 -0
  65. package/dist/esm/components/EdgeIcon.d.ts +8 -0
  66. package/dist/esm/components/EdgeIcon.js +7 -0
  67. package/dist/esm/components/ExampleLoader.d.ts +11 -0
  68. package/dist/esm/components/ExampleLoader.js +46 -0
  69. package/dist/esm/components/ExampleLoaderButton.d.ts +15 -0
  70. package/dist/esm/components/ExampleLoaderButton.js +66 -0
  71. package/dist/esm/components/FlagManager.d.ts +11 -0
  72. package/dist/esm/components/FlagManager.js +246 -0
  73. package/dist/esm/components/FlagSelector.d.ts +11 -0
  74. package/dist/esm/components/FlagSelector.js +199 -0
  75. package/dist/esm/components/GuidePanel.d.ts +7 -0
  76. package/dist/esm/components/GuidePanel.js +1140 -0
  77. package/dist/esm/components/Minimap.d.ts +16 -0
  78. package/dist/esm/components/Minimap.js +57 -0
  79. package/dist/esm/components/NPCEdgeV2.d.ts +3 -0
  80. package/dist/esm/components/NPCEdgeV2.js +68 -0
  81. package/dist/esm/components/NPCNodeV2.d.ts +26 -0
  82. package/dist/esm/components/NPCNodeV2.js +80 -0
  83. package/dist/esm/components/NodeEditor.d.ts +18 -0
  84. package/dist/esm/components/NodeEditor.js +989 -0
  85. package/dist/esm/components/PlayView.d.ts +12 -0
  86. package/dist/esm/components/PlayView.js +271 -0
  87. package/dist/esm/components/PlayerNodeV2.d.ts +16 -0
  88. package/dist/esm/components/PlayerNodeV2.js +103 -0
  89. package/dist/esm/components/ReactFlowPOC.d.ts +61 -0
  90. package/dist/esm/components/ReactFlowPOC.js +275 -0
  91. package/dist/esm/components/ScenePlayer.d.ts +18 -0
  92. package/dist/esm/components/ScenePlayer.js +160 -0
  93. package/dist/esm/components/YarnView.d.ts +9 -0
  94. package/dist/esm/components/YarnView.js +39 -0
  95. package/dist/esm/components/ZoomControls.d.ts +11 -0
  96. package/dist/esm/components/ZoomControls.js +28 -0
  97. package/dist/esm/examples/example-loader.d.ts +29 -0
  98. package/dist/esm/examples/example-loader.js +103 -0
  99. package/dist/esm/examples/examples-registry.d.ts +38 -0
  100. package/dist/esm/examples/examples-registry.js +153 -0
  101. package/dist/esm/examples/index.d.ts +26 -0
  102. package/dist/esm/examples/index.js +50 -0
  103. package/dist/esm/examples/legacy-examples.d.ts +9 -0
  104. package/dist/esm/examples/legacy-examples.js +814 -0
  105. package/dist/esm/examples/yarn-examples.d.ts +35 -0
  106. package/dist/esm/examples/yarn-examples.js +181 -0
  107. package/dist/esm/index.d.ts +21 -0
  108. package/dist/esm/index.js +26 -0
  109. package/dist/esm/lib/flag-manager.d.ts +21 -0
  110. package/dist/esm/lib/flag-manager.js +93 -0
  111. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  112. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.js +169 -0
  113. package/dist/esm/lib/yarn-converter.d.ts +17 -0
  114. package/dist/esm/lib/yarn-converter.js +521 -0
  115. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  116. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.js +171 -0
  117. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  118. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.js +237 -0
  119. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  120. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.js +106 -0
  121. package/dist/esm/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  122. package/dist/esm/lib/yarn-runner/condition-evaluator.js +56 -0
  123. package/dist/esm/lib/yarn-runner/index.d.ts +12 -0
  124. package/dist/esm/lib/yarn-runner/index.js +11 -0
  125. package/dist/esm/lib/yarn-runner/node-processor.d.ts +18 -0
  126. package/dist/esm/lib/yarn-runner/node-processor.js +129 -0
  127. package/dist/esm/lib/yarn-runner/variable-manager.d.ts +51 -0
  128. package/dist/esm/lib/yarn-runner/variable-manager.js +120 -0
  129. package/dist/esm/lib/yarn-runner/variable-operations.d.ts +16 -0
  130. package/dist/esm/lib/yarn-runner/variable-operations.js +88 -0
  131. package/dist/esm/types/conditionals.d.ts +29 -0
  132. package/dist/esm/types/conditionals.js +1 -0
  133. package/dist/esm/types/constants.d.ts +59 -0
  134. package/dist/esm/types/constants.js +55 -0
  135. package/dist/esm/types/flags.d.ts +49 -0
  136. package/dist/esm/types/flags.js +49 -0
  137. package/dist/esm/types/game-state.d.ts +62 -0
  138. package/dist/esm/types/game-state.js +6 -0
  139. package/dist/esm/types/index.d.ts +77 -0
  140. package/dist/esm/types/index.js +1 -0
  141. package/dist/esm/utils/constants.d.ts +5 -0
  142. package/dist/esm/utils/constants.js +5 -0
  143. package/dist/esm/utils/feature-flags.d.ts +11 -0
  144. package/dist/esm/utils/feature-flags.js +11 -0
  145. package/dist/esm/utils/game-state-flattener.d.ts +41 -0
  146. package/dist/esm/utils/game-state-flattener.js +135 -0
  147. package/dist/esm/utils/layout/collision.d.ts +27 -0
  148. package/dist/esm/utils/layout/collision.js +74 -0
  149. package/dist/esm/utils/layout/index.d.ts +82 -0
  150. package/dist/esm/utils/layout/index.js +98 -0
  151. package/dist/esm/utils/layout/registry.d.ts +91 -0
  152. package/dist/esm/utils/layout/registry.js +148 -0
  153. package/dist/esm/utils/layout/strategies/dagre.d.ts +19 -0
  154. package/dist/esm/utils/layout/strategies/dagre.js +182 -0
  155. package/dist/esm/utils/layout/strategies/force.d.ts +21 -0
  156. package/dist/esm/utils/layout/strategies/force.js +178 -0
  157. package/dist/esm/utils/layout/strategies/grid.d.ts +17 -0
  158. package/dist/esm/utils/layout/strategies/grid.js +91 -0
  159. package/dist/esm/utils/layout/strategies/index.d.ts +8 -0
  160. package/dist/esm/utils/layout/strategies/index.js +8 -0
  161. package/dist/esm/utils/layout/types.d.ts +100 -0
  162. package/dist/esm/utils/layout/types.js +7 -0
  163. package/dist/esm/utils/layout.d.ts +9 -0
  164. package/dist/esm/utils/layout.js +17 -0
  165. package/dist/esm/utils/node-helpers.d.ts +7 -0
  166. package/dist/esm/utils/node-helpers.js +94 -0
  167. package/dist/esm/utils/reactflow-converter.d.ts +42 -0
  168. package/dist/esm/utils/reactflow-converter.js +217 -0
  169. package/dist/examples/example-loader.d.ts +29 -0
  170. package/dist/examples/example-loader.js +109 -0
  171. package/dist/examples/examples-registry.d.ts +38 -0
  172. package/dist/examples/examples-registry.js +160 -0
  173. package/dist/examples/index.d.ts +26 -0
  174. package/dist/examples/index.js +63 -0
  175. package/dist/examples/legacy-examples.d.ts +9 -0
  176. package/dist/examples/legacy-examples.js +817 -0
  177. package/dist/examples/yarn-examples.d.ts +35 -0
  178. package/dist/examples/yarn-examples.js +189 -0
  179. package/dist/index.d.ts +21 -0
  180. package/dist/index.js +66 -0
  181. package/dist/lib/flag-manager.d.ts +21 -0
  182. package/dist/lib/flag-manager.js +99 -0
  183. package/dist/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  184. package/dist/lib/yarn-converter/__tests__/round-trip.test.js +171 -0
  185. package/dist/lib/yarn-converter.d.ts +17 -0
  186. package/dist/lib/yarn-converter.js +525 -0
  187. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  188. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.js +173 -0
  189. package/dist/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  190. package/dist/lib/yarn-runner/__tests__/node-processor.test.js +239 -0
  191. package/dist/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  192. package/dist/lib/yarn-runner/__tests__/variable-manager.test.js +108 -0
  193. package/dist/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  194. package/dist/lib/yarn-runner/condition-evaluator.js +60 -0
  195. package/dist/lib/yarn-runner/index.d.ts +12 -0
  196. package/dist/lib/yarn-runner/index.js +21 -0
  197. package/dist/lib/yarn-runner/node-processor.d.ts +18 -0
  198. package/dist/lib/yarn-runner/node-processor.js +133 -0
  199. package/dist/lib/yarn-runner/variable-manager.d.ts +51 -0
  200. package/dist/lib/yarn-runner/variable-manager.js +124 -0
  201. package/dist/lib/yarn-runner/variable-operations.d.ts +16 -0
  202. package/dist/lib/yarn-runner/variable-operations.js +92 -0
  203. package/dist/types/conditionals.d.ts +29 -0
  204. package/dist/types/conditionals.js +2 -0
  205. package/dist/types/constants.d.ts +59 -0
  206. package/dist/types/constants.js +58 -0
  207. package/dist/types/flags.d.ts +49 -0
  208. package/dist/types/flags.js +52 -0
  209. package/dist/types/game-state.d.ts +62 -0
  210. package/dist/types/game-state.js +7 -0
  211. package/dist/types/index.d.ts +77 -0
  212. package/dist/types/index.js +2 -0
  213. package/dist/utils/constants.d.ts +5 -0
  214. package/dist/utils/constants.js +8 -0
  215. package/dist/utils/feature-flags.d.ts +11 -0
  216. package/dist/utils/feature-flags.js +14 -0
  217. package/dist/utils/game-state-flattener.d.ts +41 -0
  218. package/dist/utils/game-state-flattener.js +140 -0
  219. package/dist/utils/layout/collision.d.ts +27 -0
  220. package/dist/utils/layout/collision.js +77 -0
  221. package/dist/utils/layout/index.d.ts +82 -0
  222. package/dist/utils/layout/index.js +109 -0
  223. package/dist/utils/layout/registry.d.ts +91 -0
  224. package/dist/utils/layout/registry.js +151 -0
  225. package/dist/utils/layout/strategies/dagre.d.ts +19 -0
  226. package/dist/utils/layout/strategies/dagre.js +189 -0
  227. package/dist/utils/layout/strategies/force.d.ts +21 -0
  228. package/dist/utils/layout/strategies/force.js +182 -0
  229. package/dist/utils/layout/strategies/grid.d.ts +17 -0
  230. package/dist/utils/layout/strategies/grid.js +95 -0
  231. package/dist/utils/layout/strategies/index.d.ts +8 -0
  232. package/dist/utils/layout/strategies/index.js +14 -0
  233. package/dist/utils/layout/types.d.ts +100 -0
  234. package/dist/utils/layout/types.js +8 -0
  235. package/dist/utils/layout.d.ts +9 -0
  236. package/dist/utils/layout.js +25 -0
  237. package/dist/utils/node-helpers.d.ts +7 -0
  238. package/dist/utils/node-helpers.js +101 -0
  239. package/dist/utils/reactflow-converter.d.ts +42 -0
  240. package/dist/utils/reactflow-converter.js +223 -0
  241. package/package.json +70 -0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Game State Integration Types
3
+ *
4
+ * These types define how Dialogue Forge integrates with your game's state system.
5
+ */
6
+ import type { DialogueTree } from './index';
7
+ import type { FlagSchema } from './flags';
8
+ /**
9
+ * Flag value types - must be Yarn Spinner-compatible
10
+ */
11
+ export type FlagValue = boolean | number | string;
12
+ /**
13
+ * Current game state - flags and their values (flat, Yarn-compatible)
14
+ */
15
+ export interface FlagState {
16
+ [flagId: string]: FlagValue;
17
+ }
18
+ /**
19
+ * Legacy alias for backward compatibility
20
+ */
21
+ export type GameFlagState = FlagState;
22
+ /**
23
+ * Base game state structure that users can extend
24
+ * Must have a 'flags' property, but can have any other structure
25
+ */
26
+ export interface BaseGameState {
27
+ flags?: FlagState;
28
+ }
29
+ /**
30
+ * Convenience type for extending game state
31
+ */
32
+ export type GameState<T extends Record<string, any> = {}> = BaseGameState & T;
33
+ /**
34
+ * Updated flags after dialogue completes
35
+ */
36
+ export interface DialogueResult {
37
+ updatedFlags: FlagState;
38
+ dialogueTree: DialogueTree;
39
+ completedNodeIds: string[];
40
+ }
41
+ /**
42
+ * Props for running a dialogue (simulation/play mode)
43
+ */
44
+ export interface DialogueRunProps {
45
+ dialogue: DialogueTree;
46
+ gameState: Record<string, any>;
47
+ startNodeId?: string;
48
+ onComplete?: (result: DialogueResult) => void;
49
+ onFlagUpdate?: (flags: FlagState) => void;
50
+ }
51
+ /**
52
+ * Props for editing a dialogue
53
+ */
54
+ export interface DialogueEditProps {
55
+ dialogue: DialogueTree | null;
56
+ flagSchema?: FlagSchema;
57
+ onChange: (dialogue: DialogueTree) => void;
58
+ onExportYarn?: (yarn: string) => void;
59
+ onExportJSON?: (json: string) => void;
60
+ className?: string;
61
+ showTitleEditor?: boolean;
62
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * Game State Integration Types
4
+ *
5
+ * These types define how Dialogue Forge integrates with your game's state system.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,77 @@
1
+ import { ConditionOperator, NodeType } from './constants';
2
+ export interface Choice {
3
+ id: string;
4
+ text: string;
5
+ nextNodeId?: string;
6
+ conditions?: Condition[];
7
+ setFlags?: string[];
8
+ }
9
+ export interface Condition {
10
+ flag: string;
11
+ operator: ConditionOperator;
12
+ value?: boolean | number | string;
13
+ }
14
+ /**
15
+ * Conditional content block for if/elseif/else statements
16
+ */
17
+ export interface ConditionalBlock {
18
+ id: string;
19
+ type: 'if' | 'elseif' | 'else';
20
+ condition?: Condition[];
21
+ content: string;
22
+ speaker?: string;
23
+ nextNodeId?: string;
24
+ }
25
+ export interface DialogueNode {
26
+ id: string;
27
+ type: NodeType;
28
+ speaker?: string;
29
+ content: string;
30
+ choices?: Choice[];
31
+ nextNodeId?: string;
32
+ setFlags?: string[];
33
+ conditionalBlocks?: ConditionalBlock[];
34
+ x: number;
35
+ y: number;
36
+ }
37
+ export interface DialogueTree {
38
+ id: string;
39
+ title: string;
40
+ startNodeId: string;
41
+ nodes: Record<string, DialogueNode>;
42
+ }
43
+ import { FlagSchema } from './flags';
44
+ export interface DialogueEditorProps {
45
+ dialogue: DialogueTree | null;
46
+ onChange: (dialogue: DialogueTree) => void;
47
+ onExportYarn?: (yarn: string) => void;
48
+ onExportJSON?: (json: string) => void;
49
+ flagSchema?: FlagSchema;
50
+ className?: string;
51
+ showTitleEditor?: boolean;
52
+ onNodeAdd?: (node: DialogueNode) => void;
53
+ onNodeDelete?: (nodeId: string) => void;
54
+ onNodeUpdate?: (nodeId: string, updates: Partial<DialogueNode>) => void;
55
+ onConnect?: (sourceId: string, targetId: string, sourceHandle?: string) => void;
56
+ onDisconnect?: (edgeId: string, sourceId: string, targetId: string) => void;
57
+ onNodeSelect?: (nodeId: string | null) => void;
58
+ onNodeDoubleClick?: (nodeId: string) => void;
59
+ }
60
+ export interface ContextMenu {
61
+ x: number;
62
+ y: number;
63
+ graphX: number;
64
+ graphY: number;
65
+ }
66
+ export interface EdgeDropMenu extends ContextMenu {
67
+ fromNodeId: string;
68
+ fromChoiceIdx?: number;
69
+ }
70
+ export interface DraggingEdge {
71
+ fromNodeId: string;
72
+ fromChoiceIdx?: number;
73
+ startX: number;
74
+ startY: number;
75
+ endX: number;
76
+ endY: number;
77
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ export declare const NODE_WIDTH = 200;
2
+ export declare const NODE_HEIGHT = 100;
3
+ export declare const DEFAULT_GRAPH_SCALE = 0.85;
4
+ export declare const MIN_SCALE = 0.3;
5
+ export declare const MAX_SCALE = 2;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_SCALE = exports.MIN_SCALE = exports.DEFAULT_GRAPH_SCALE = exports.NODE_HEIGHT = exports.NODE_WIDTH = void 0;
4
+ exports.NODE_WIDTH = 200;
5
+ exports.NODE_HEIGHT = 100;
6
+ exports.DEFAULT_GRAPH_SCALE = 0.85;
7
+ exports.MIN_SCALE = 0.3;
8
+ exports.MAX_SCALE = 2;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Feature Flags
3
+ *
4
+ * Control optional features that are only for development/debugging.
5
+ * When users install the package, these can be disabled.
6
+ */
7
+ /**
8
+ * Enable debug tools (ExampleLoader, etc.)
9
+ * Set to false in production builds or when distributing the package.
10
+ */
11
+ export declare const ENABLE_DEBUG_TOOLS = true;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * Feature Flags
4
+ *
5
+ * Control optional features that are only for development/debugging.
6
+ * When users install the package, these can be disabled.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ENABLE_DEBUG_TOOLS = void 0;
10
+ /**
11
+ * Enable debug tools (ExampleLoader, etc.)
12
+ * Set to false in production builds or when distributing the package.
13
+ */
14
+ exports.ENABLE_DEBUG_TOOLS = true;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Game State Flattening Utility
3
+ *
4
+ * Flattens nested game state structures into Yarn Spinner-compatible flat variables.
5
+ * Supports: flags, player, characters (as object), and any other nested structures.
6
+ *
7
+ * Rules:
8
+ * - Only includes truthy values (skips 0, false, null, undefined, empty strings)
9
+ * - Flattens nested objects using underscore separator
10
+ * - Characters are objects, not arrays (uses object keys as part of path)
11
+ * - All values must be boolean | number | string (Yarn-compatible)
12
+ */
13
+ import type { FlagState } from '../types/game-state';
14
+ export interface FlattenConfig {
15
+ /** Skip null/undefined values (default: true) */
16
+ excludeNull?: boolean;
17
+ /** Separator for nested keys (default: '_') */
18
+ separator?: string;
19
+ /** Maximum depth to flatten (default: 5, prevents infinite recursion) */
20
+ maxDepth?: number;
21
+ }
22
+ export interface FlattenedState {
23
+ flags: FlagState;
24
+ metadata: {
25
+ sourcePaths: Record<string, string>;
26
+ };
27
+ }
28
+ /**
29
+ * Flattens a game state object into Yarn Spinner-compatible flat variables
30
+ */
31
+ export declare function flattenGameState(gameState: any, config?: FlattenConfig): FlattenedState;
32
+ /**
33
+ * Validates that gameState has a valid structure
34
+ * Throws descriptive errors if validation fails
35
+ */
36
+ export declare function validateGameState(gameState: any): asserts gameState is Record<string, any>;
37
+ /**
38
+ * Extracts flags from gameState, flattening if necessary
39
+ * This is the main entry point for ScenePlayer
40
+ */
41
+ export declare function extractFlagsFromGameState(gameState: any, config?: FlattenConfig): FlagState;
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ /**
3
+ * Game State Flattening Utility
4
+ *
5
+ * Flattens nested game state structures into Yarn Spinner-compatible flat variables.
6
+ * Supports: flags, player, characters (as object), and any other nested structures.
7
+ *
8
+ * Rules:
9
+ * - Only includes truthy values (skips 0, false, null, undefined, empty strings)
10
+ * - Flattens nested objects using underscore separator
11
+ * - Characters are objects, not arrays (uses object keys as part of path)
12
+ * - All values must be boolean | number | string (Yarn-compatible)
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.flattenGameState = flattenGameState;
16
+ exports.validateGameState = validateGameState;
17
+ exports.extractFlagsFromGameState = extractFlagsFromGameState;
18
+ /**
19
+ * Validates that a value is Yarn Spinner-compatible
20
+ */
21
+ function isYarnCompatible(value) {
22
+ return typeof value === 'boolean' ||
23
+ typeof value === 'number' ||
24
+ typeof value === 'string';
25
+ }
26
+ /**
27
+ * Checks if a value is "truthy" for our purposes
28
+ * - Numbers: only include if !== 0
29
+ * - Booleans: only include if true
30
+ * - Strings: only include if non-empty
31
+ * - null/undefined: excluded if excludeNull is true
32
+ */
33
+ function isTruthyValue(value, excludeNull) {
34
+ if (value == null) {
35
+ return !excludeNull; // Include null only if excludeNull is false
36
+ }
37
+ if (typeof value === 'number') {
38
+ return value !== 0; // Exclude zero
39
+ }
40
+ if (typeof value === 'boolean') {
41
+ return value === true; // Only include true
42
+ }
43
+ if (typeof value === 'string') {
44
+ return value.length > 0; // Exclude empty strings
45
+ }
46
+ return true; // Objects/arrays will be flattened further
47
+ }
48
+ /**
49
+ * Flattens a game state object into Yarn Spinner-compatible flat variables
50
+ */
51
+ function flattenGameState(gameState, config = {}) {
52
+ if (!gameState || typeof gameState !== 'object') {
53
+ throw new Error('GameState must be an object');
54
+ }
55
+ const { excludeNull = true, separator = '_', maxDepth = 5, } = config;
56
+ const flags = {};
57
+ const sourcePaths = {};
58
+ /**
59
+ * Recursively flatten a value
60
+ */
61
+ function flattenValue(value, path, depth = 0) {
62
+ // Prevent infinite recursion
63
+ if (depth > maxDepth) {
64
+ console.warn(`Max depth (${maxDepth}) reached at path: ${path}`);
65
+ return;
66
+ }
67
+ // Handle primitives (Yarn-compatible types)
68
+ if (isYarnCompatible(value)) {
69
+ // Only include truthy values
70
+ if (isTruthyValue(value, excludeNull)) {
71
+ const key = path.replace(/\./g, separator);
72
+ flags[key] = value;
73
+ sourcePaths[key] = path;
74
+ }
75
+ return;
76
+ }
77
+ // Handle null/undefined
78
+ if (value == null) {
79
+ if (!excludeNull) {
80
+ // Could store as string representation, but Yarn doesn't support null
81
+ // Skip for now - Yarn only supports boolean | number | string
82
+ }
83
+ return;
84
+ }
85
+ // Handle arrays - flatten all items
86
+ if (Array.isArray(value)) {
87
+ value.forEach((item, index) => {
88
+ const arrayPath = `${path}[${index}]`;
89
+ flattenValue(item, arrayPath, depth + 1);
90
+ });
91
+ return;
92
+ }
93
+ // Handle objects - flatten all properties
94
+ if (typeof value === 'object') {
95
+ Object.entries(value).forEach(([key, val]) => {
96
+ // Skip if value is not truthy (for nested objects, we still traverse)
97
+ // but we'll check truthiness when we hit primitives
98
+ const newPath = path ? `${path}.${key}` : key;
99
+ flattenValue(val, newPath, depth + 1);
100
+ });
101
+ return;
102
+ }
103
+ // Unknown type - skip
104
+ console.warn(`Skipping unsupported type at path: ${path} (type: ${typeof value})`);
105
+ }
106
+ // Flatten all top-level keys
107
+ Object.entries(gameState).forEach(([key, value]) => {
108
+ flattenValue(value, key, 0);
109
+ });
110
+ return {
111
+ flags,
112
+ metadata: {
113
+ sourcePaths,
114
+ },
115
+ };
116
+ }
117
+ /**
118
+ * Validates that gameState has a valid structure
119
+ * Throws descriptive errors if validation fails
120
+ */
121
+ function validateGameState(gameState) {
122
+ if (gameState == null) {
123
+ throw new Error('GameState cannot be null or undefined');
124
+ }
125
+ if (typeof gameState !== 'object') {
126
+ throw new Error(`GameState must be an object, got: ${typeof gameState}`);
127
+ }
128
+ if (Array.isArray(gameState)) {
129
+ throw new Error('GameState cannot be an array. Use an object with keys like { flags: {...}, player: {...} }');
130
+ }
131
+ }
132
+ /**
133
+ * Extracts flags from gameState, flattening if necessary
134
+ * This is the main entry point for ScenePlayer
135
+ */
136
+ function extractFlagsFromGameState(gameState, config) {
137
+ validateGameState(gameState);
138
+ const flattened = flattenGameState(gameState, config);
139
+ return flattened.flags;
140
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Node Collision Resolution
3
+ *
4
+ * Utility for resolving overlapping nodes in freeform layout.
5
+ * Iteratively pushes overlapping nodes apart until stable.
6
+ *
7
+ * @see https://reactflow.dev/examples/layout/node-collisions
8
+ */
9
+ import { DialogueTree } from '../../types';
10
+ interface CollisionOptions {
11
+ /** Maximum iterations before giving up */
12
+ maxIterations?: number;
13
+ /** Overlap ratio threshold to trigger resolution (0-1) */
14
+ overlapThreshold?: number;
15
+ /** Extra margin to add when pushing nodes apart */
16
+ margin?: number;
17
+ }
18
+ /**
19
+ * Resolve node collisions for freeform layout.
20
+ * Iteratively pushes overlapping nodes apart until no collisions remain.
21
+ *
22
+ * @param dialogue - The dialogue tree with potentially overlapping nodes
23
+ * @param options - Configuration options
24
+ * @returns Updated dialogue tree with resolved positions
25
+ */
26
+ export declare function resolveNodeCollisions(dialogue: DialogueTree, options?: CollisionOptions): DialogueTree;
27
+ export {};
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Node Collision Resolution
4
+ *
5
+ * Utility for resolving overlapping nodes in freeform layout.
6
+ * Iteratively pushes overlapping nodes apart until stable.
7
+ *
8
+ * @see https://reactflow.dev/examples/layout/node-collisions
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.resolveNodeCollisions = resolveNodeCollisions;
12
+ // ============================================================================
13
+ // Constants
14
+ // ============================================================================
15
+ const NODE_WIDTH = 220;
16
+ const NODE_HEIGHT = 120;
17
+ // ============================================================================
18
+ // Implementation
19
+ // ============================================================================
20
+ /**
21
+ * Resolve node collisions for freeform layout.
22
+ * Iteratively pushes overlapping nodes apart until no collisions remain.
23
+ *
24
+ * @param dialogue - The dialogue tree with potentially overlapping nodes
25
+ * @param options - Configuration options
26
+ * @returns Updated dialogue tree with resolved positions
27
+ */
28
+ function resolveNodeCollisions(dialogue, options = {}) {
29
+ const { maxIterations = 50, overlapThreshold = 0.3, margin = 20 } = options;
30
+ // Create mutable position array
31
+ const nodePositions = Object.values(dialogue.nodes).map(node => ({
32
+ id: node.id,
33
+ x: node.x,
34
+ y: node.y,
35
+ width: NODE_WIDTH,
36
+ height: NODE_HEIGHT,
37
+ }));
38
+ // Iteratively resolve collisions
39
+ for (let iter = 0; iter < maxIterations; iter++) {
40
+ let hasCollision = false;
41
+ for (let i = 0; i < nodePositions.length; i++) {
42
+ for (let j = i + 1; j < nodePositions.length; j++) {
43
+ const a = nodePositions[i];
44
+ const b = nodePositions[j];
45
+ // Calculate overlap
46
+ const overlapX = Math.max(0, Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x));
47
+ const overlapY = Math.max(0, Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y));
48
+ if (overlapX > 0 && overlapY > 0) {
49
+ const overlapRatio = (overlapX * overlapY) / Math.min(a.width * a.height, b.width * b.height);
50
+ if (overlapRatio > overlapThreshold) {
51
+ hasCollision = true;
52
+ // Calculate push direction (center to center)
53
+ const dx = (b.x + b.width / 2) - (a.x + a.width / 2);
54
+ const dy = (b.y + b.height / 2) - (a.y + a.height / 2);
55
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
56
+ // Push apart
57
+ const pushX = (dx / dist) * (overlapX / 2 + margin);
58
+ const pushY = (dy / dist) * (overlapY / 2 + margin);
59
+ a.x -= pushX / 2;
60
+ a.y -= pushY / 2;
61
+ b.x += pushX / 2;
62
+ b.y += pushY / 2;
63
+ }
64
+ }
65
+ }
66
+ }
67
+ // Exit early if no collisions found
68
+ if (!hasCollision)
69
+ break;
70
+ }
71
+ // Build updated dialogue with new positions
72
+ const updatedNodes = {};
73
+ for (const pos of nodePositions) {
74
+ updatedNodes[pos.id] = { ...dialogue.nodes[pos.id], x: pos.x, y: pos.y };
75
+ }
76
+ return { ...dialogue, nodes: updatedNodes };
77
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Layout Module
3
+ *
4
+ * Provides automatic graph layout algorithms for dialogue trees.
5
+ * Uses the Strategy pattern to allow swappable layout algorithms.
6
+ *
7
+ * ## Quick Start
8
+ *
9
+ * ```typescript
10
+ * import { layoutRegistry, applyLayout } from './layout';
11
+ *
12
+ * // Apply default layout (dagre)
13
+ * const result = applyLayout(dialogue);
14
+ *
15
+ * // Apply specific layout
16
+ * const result = applyLayout(dialogue, 'force');
17
+ *
18
+ * // With options
19
+ * const result = applyLayout(dialogue, 'dagre', { direction: 'LR' });
20
+ *
21
+ * // List available layouts
22
+ * console.log(layoutRegistry.list());
23
+ * ```
24
+ *
25
+ * ## Adding Custom Layouts
26
+ *
27
+ * See LAYOUT_STRATEGIES.md for documentation on creating custom layouts.
28
+ *
29
+ * @module layout
30
+ */
31
+ import { DialogueTree } from '../../types';
32
+ import { LayoutOptions, LayoutResult, LayoutDirection } from './types';
33
+ /**
34
+ * Apply a layout algorithm to a dialogue tree
35
+ *
36
+ * @param dialogue - The dialogue tree to layout
37
+ * @param strategyId - Optional strategy ID (defaults to 'dagre')
38
+ * @param options - Optional layout configuration
39
+ * @returns Layout result with updated dialogue and metadata
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // Default dagre layout
44
+ * const result = applyLayout(dialogue);
45
+ *
46
+ * // Horizontal dagre layout
47
+ * const result = applyLayout(dialogue, 'dagre', { direction: 'LR' });
48
+ *
49
+ * // Force-directed layout
50
+ * const result = applyLayout(dialogue, 'force');
51
+ *
52
+ * // Grid layout
53
+ * const result = applyLayout(dialogue, 'grid');
54
+ * ```
55
+ */
56
+ export declare function applyLayout(dialogue: DialogueTree, strategyId?: string, options?: LayoutOptions): LayoutResult;
57
+ /**
58
+ * Get the list of available layout strategies
59
+ */
60
+ export declare function listLayouts(): Array<{
61
+ id: string;
62
+ name: string;
63
+ description: string;
64
+ isDefault: boolean;
65
+ }>;
66
+ /**
67
+ * Apply dagre layout (backward compatible function)
68
+ * @deprecated Use applyLayout(dialogue, 'dagre', options) instead
69
+ */
70
+ export declare function applyDagreLayout(dialogue: DialogueTree, direction?: LayoutDirection): DialogueTree;
71
+ /**
72
+ * Apply hierarchical layout (backward compatible alias)
73
+ * @deprecated Use applyLayout(dialogue, 'dagre', options) instead
74
+ */
75
+ export declare const applyHierarchicalLayout: typeof applyDagreLayout;
76
+ /**
77
+ * Resolve node collisions (kept for backward compatibility)
78
+ */
79
+ export { resolveNodeCollisions } from './collision';
80
+ export type { LayoutStrategy, LayoutOptions, LayoutResult, LayoutDirection } from './types';
81
+ export { layoutRegistry } from './registry';
82
+ export { DagreLayoutStrategy, ForceLayoutStrategy, GridLayoutStrategy } from './strategies';
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ /**
3
+ * Layout Module
4
+ *
5
+ * Provides automatic graph layout algorithms for dialogue trees.
6
+ * Uses the Strategy pattern to allow swappable layout algorithms.
7
+ *
8
+ * ## Quick Start
9
+ *
10
+ * ```typescript
11
+ * import { layoutRegistry, applyLayout } from './layout';
12
+ *
13
+ * // Apply default layout (dagre)
14
+ * const result = applyLayout(dialogue);
15
+ *
16
+ * // Apply specific layout
17
+ * const result = applyLayout(dialogue, 'force');
18
+ *
19
+ * // With options
20
+ * const result = applyLayout(dialogue, 'dagre', { direction: 'LR' });
21
+ *
22
+ * // List available layouts
23
+ * console.log(layoutRegistry.list());
24
+ * ```
25
+ *
26
+ * ## Adding Custom Layouts
27
+ *
28
+ * See LAYOUT_STRATEGIES.md for documentation on creating custom layouts.
29
+ *
30
+ * @module layout
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.GridLayoutStrategy = exports.ForceLayoutStrategy = exports.DagreLayoutStrategy = exports.layoutRegistry = exports.resolveNodeCollisions = exports.applyHierarchicalLayout = void 0;
34
+ exports.applyLayout = applyLayout;
35
+ exports.listLayouts = listLayouts;
36
+ exports.applyDagreLayout = applyDagreLayout;
37
+ const registry_1 = require("./registry");
38
+ const strategies_1 = require("./strategies");
39
+ // ============================================================================
40
+ // Register Built-in Strategies
41
+ // ============================================================================
42
+ // Register all built-in strategies
43
+ registry_1.layoutRegistry.register(new strategies_1.DagreLayoutStrategy(), true); // Default
44
+ registry_1.layoutRegistry.register(new strategies_1.ForceLayoutStrategy());
45
+ registry_1.layoutRegistry.register(new strategies_1.GridLayoutStrategy());
46
+ // ============================================================================
47
+ // Convenience Functions
48
+ // ============================================================================
49
+ /**
50
+ * Apply a layout algorithm to a dialogue tree
51
+ *
52
+ * @param dialogue - The dialogue tree to layout
53
+ * @param strategyId - Optional strategy ID (defaults to 'dagre')
54
+ * @param options - Optional layout configuration
55
+ * @returns Layout result with updated dialogue and metadata
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // Default dagre layout
60
+ * const result = applyLayout(dialogue);
61
+ *
62
+ * // Horizontal dagre layout
63
+ * const result = applyLayout(dialogue, 'dagre', { direction: 'LR' });
64
+ *
65
+ * // Force-directed layout
66
+ * const result = applyLayout(dialogue, 'force');
67
+ *
68
+ * // Grid layout
69
+ * const result = applyLayout(dialogue, 'grid');
70
+ * ```
71
+ */
72
+ function applyLayout(dialogue, strategyId, options) {
73
+ return registry_1.layoutRegistry.apply(strategyId, dialogue, options);
74
+ }
75
+ /**
76
+ * Get the list of available layout strategies
77
+ */
78
+ function listLayouts() {
79
+ return registry_1.layoutRegistry.list();
80
+ }
81
+ // ============================================================================
82
+ // Backward Compatibility
83
+ // ============================================================================
84
+ /**
85
+ * Apply dagre layout (backward compatible function)
86
+ * @deprecated Use applyLayout(dialogue, 'dagre', options) instead
87
+ */
88
+ function applyDagreLayout(dialogue, direction = 'TB') {
89
+ const result = applyLayout(dialogue, 'dagre', { direction });
90
+ return result.dialogue;
91
+ }
92
+ /**
93
+ * Apply hierarchical layout (backward compatible alias)
94
+ * @deprecated Use applyLayout(dialogue, 'dagre', options) instead
95
+ */
96
+ exports.applyHierarchicalLayout = applyDagreLayout;
97
+ /**
98
+ * Resolve node collisions (kept for backward compatibility)
99
+ */
100
+ var collision_1 = require("./collision");
101
+ Object.defineProperty(exports, "resolveNodeCollisions", { enumerable: true, get: function () { return collision_1.resolveNodeCollisions; } });
102
+ // Registry
103
+ var registry_2 = require("./registry");
104
+ Object.defineProperty(exports, "layoutRegistry", { enumerable: true, get: function () { return registry_2.layoutRegistry; } });
105
+ // Strategies (for direct use or extension)
106
+ var strategies_2 = require("./strategies");
107
+ Object.defineProperty(exports, "DagreLayoutStrategy", { enumerable: true, get: function () { return strategies_2.DagreLayoutStrategy; } });
108
+ Object.defineProperty(exports, "ForceLayoutStrategy", { enumerable: true, get: function () { return strategies_2.ForceLayoutStrategy; } });
109
+ Object.defineProperty(exports, "GridLayoutStrategy", { enumerable: true, get: function () { return strategies_2.GridLayoutStrategy; } });