@magicborn/dialogue-forge 0.1.2 → 0.1.4
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.
- package/demo/app/page.tsx +2 -1
- package/demo/tsconfig.tsbuildinfo +1 -0
- package/dist/components/DialogueEditorV2.d.ts +1 -3
- package/dist/components/PlayView.js +32 -184
- package/dist/components/ScenePlayer.js +41 -6
- package/dist/esm/components/DialogueEditorV2.d.ts +1 -3
- package/dist/esm/components/PlayView.js +34 -186
- package/dist/esm/components/ScenePlayer.js +41 -6
- package/dist/esm/examples/examples-registry.js +8 -0
- package/dist/esm/examples/yarn-examples.js +71 -0
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/examples/examples-registry.js +8 -0
- package/dist/examples/yarn-examples.js +71 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -64,11 +64,9 @@ export function ScenePlayer({ dialogue, gameState, startNodeId, onComplete, onFl
|
|
|
64
64
|
setIsTyping(false);
|
|
65
65
|
// Call onNodeExit before moving to next
|
|
66
66
|
onNodeExit?.(currentNodeId, node);
|
|
67
|
-
//
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
67
|
+
// For NPC-only linear stories: don't auto-advance, wait for user input (Enter key or Continue button)
|
|
68
|
+
// Only auto-advance if there's no next node (dialogue complete)
|
|
69
|
+
if (!node.nextNodeId) {
|
|
72
70
|
// Dialogue complete
|
|
73
71
|
onDialogueEnd?.();
|
|
74
72
|
onComplete({
|
|
@@ -77,6 +75,7 @@ export function ScenePlayer({ dialogue, gameState, startNodeId, onComplete, onFl
|
|
|
77
75
|
completedNodeIds: Array.from(visitedNodes)
|
|
78
76
|
});
|
|
79
77
|
}
|
|
78
|
+
// If there's a nextNodeId, we'll wait for user to press Enter or click Continue
|
|
80
79
|
}, 500);
|
|
81
80
|
return () => clearTimeout(timer);
|
|
82
81
|
}
|
|
@@ -95,6 +94,26 @@ export function ScenePlayer({ dialogue, gameState, startNodeId, onComplete, onFl
|
|
|
95
94
|
return cond.operator === 'is_set' ? hasFlag : !hasFlag;
|
|
96
95
|
});
|
|
97
96
|
}) || [];
|
|
97
|
+
// Handle Enter key for advancing NPC-only dialogues
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
const handleKeyDown = (e) => {
|
|
100
|
+
// Only handle Enter key when:
|
|
101
|
+
// 1. Not typing
|
|
102
|
+
// 2. Current node is NPC
|
|
103
|
+
// 3. There's a next node to advance to
|
|
104
|
+
// 4. Not waiting for player choice
|
|
105
|
+
if (e.key === 'Enter' &&
|
|
106
|
+
!isTyping &&
|
|
107
|
+
currentNode?.type === 'npc' &&
|
|
108
|
+
currentNode.nextNodeId &&
|
|
109
|
+
availableChoices.length === 0) {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
setCurrentNodeId(currentNode.nextNodeId);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
115
|
+
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
116
|
+
}, [isTyping, currentNode, availableChoices, setCurrentNodeId]);
|
|
98
117
|
const handleChoice = (choice) => {
|
|
99
118
|
const currentNode = dialogue.nodes[currentNodeId];
|
|
100
119
|
// Call onChoiceSelect hook
|
|
@@ -128,6 +147,15 @@ export function ScenePlayer({ dialogue, gameState, startNodeId, onComplete, onFl
|
|
|
128
147
|
});
|
|
129
148
|
}
|
|
130
149
|
};
|
|
150
|
+
console.log("isnpc", currentNode?.type === 'npc');
|
|
151
|
+
console.log("isplayer", currentNode?.type === 'player');
|
|
152
|
+
console.log("isTyping", isTyping);
|
|
153
|
+
console.log("availableChoices", availableChoices);
|
|
154
|
+
console.log("visitedNodes", visitedNodes);
|
|
155
|
+
console.log("flags", flags);
|
|
156
|
+
console.log("history", history);
|
|
157
|
+
console.log("currentNodeId", currentNodeId);
|
|
158
|
+
console.log("dialogue", dialogue);
|
|
131
159
|
return (React.createElement("div", { className: "flex-1 flex flex-col" },
|
|
132
160
|
React.createElement("div", { className: "flex-1 overflow-y-auto p-4" },
|
|
133
161
|
React.createElement("div", { className: "max-w-2xl mx-auto space-y-4" },
|
|
@@ -156,5 +184,12 @@ export function ScenePlayer({ dialogue, gameState, startNodeId, onComplete, onFl
|
|
|
156
184
|
updatedFlags: flags,
|
|
157
185
|
dialogueTree: dialogue,
|
|
158
186
|
completedNodeIds: Array.from(visitedNodes)
|
|
159
|
-
}), className: "px-4 py-2 bg-[#e94560] hover:bg-[#d63850] text-white rounded-lg transition-colors" }, "Close"))))
|
|
187
|
+
}), className: "px-4 py-2 bg-[#e94560] hover:bg-[#d63850] text-white rounded-lg transition-colors" }, "Close")))),
|
|
188
|
+
currentNode?.type === 'npc' && currentNode.nextNodeId && !isTyping && (React.createElement("div", { className: "border-t border-[#1a1a2e] bg-[#0d0d14]/80 backdrop-blur-sm p-4 sticky bottom-0 z-10" },
|
|
189
|
+
React.createElement("div", { className: "max-w-2xl mx-auto text-center" },
|
|
190
|
+
React.createElement("p", { className: "text-xs text-gray-400 mb-3" },
|
|
191
|
+
"Press ",
|
|
192
|
+
React.createElement("kbd", { className: "px-2 py-1 bg-[#1a1a2e] border border-[#2a2a3e] rounded text-xs" }, "Enter"),
|
|
193
|
+
" to continue"),
|
|
194
|
+
React.createElement("button", { onClick: () => setCurrentNodeId(currentNode.nextNodeId), className: "px-6 py-3 bg-[#e94560] hover:bg-[#d63850] text-white rounded-lg transition-colors font-medium shadow-lg hover:shadow-xl transform hover:scale-105 active:scale-95", autoFocus: true }, "Continue \u2192"))))));
|
|
160
195
|
}
|
|
@@ -43,6 +43,14 @@ export const examplesRegistry = [
|
|
|
43
43
|
filename: 'variable-operations-example.yarn',
|
|
44
44
|
flagSchemaId: 'rpg',
|
|
45
45
|
features: ['variable-operations', 'variable-interpolation', 'numeric-calculations', 'string-variables']
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'linear-story',
|
|
49
|
+
title: 'Linear Story Example',
|
|
50
|
+
description: 'A linear narrative with no branching—just NPCs telling a story. Press Enter to continue.',
|
|
51
|
+
filename: 'linear-story.yarn',
|
|
52
|
+
flagSchemaId: 'basic',
|
|
53
|
+
features: ['linear-narrative', 'npc-only', 'story-driven']
|
|
46
54
|
}
|
|
47
55
|
];
|
|
48
56
|
/**
|
|
@@ -103,6 +103,77 @@ NPC: I've greeted you {$greeting_count} times now.
|
|
|
103
103
|
title: end
|
|
104
104
|
---
|
|
105
105
|
===
|
|
106
|
+
`,
|
|
107
|
+
'linear-story': `title: opening
|
|
108
|
+
---
|
|
109
|
+
Narrator: The old lighthouse stood silent against the storm, its beacon long extinguished.
|
|
110
|
+
Narrator: You've been searching for three days, following the map your grandfather left behind.
|
|
111
|
+
Narrator: The key to the lighthouse door feels cold in your hand, heavy with purpose.
|
|
112
|
+
<<jump lighthouse_entrance>>
|
|
113
|
+
===
|
|
114
|
+
|
|
115
|
+
title: lighthouse_entrance
|
|
116
|
+
---
|
|
117
|
+
Narrator: The door creaks open with a sound that echoes through the empty tower.
|
|
118
|
+
Narrator: Dust motes dance in the beam of your flashlight as you step inside.
|
|
119
|
+
Narrator: The air is still, thick with the scent of salt and old wood.
|
|
120
|
+
<<jump climbing_stairs>>
|
|
121
|
+
===
|
|
122
|
+
|
|
123
|
+
title: climbing_stairs
|
|
124
|
+
---
|
|
125
|
+
Narrator: Your footsteps echo on the spiral staircase as you climb.
|
|
126
|
+
Narrator: Each step feels like a journey through time, the wood groaning under your weight.
|
|
127
|
+
Narrator: You count the steps: twenty, thirty, forty... the tower seems endless.
|
|
128
|
+
<<jump lantern_room>>
|
|
129
|
+
===
|
|
130
|
+
|
|
131
|
+
title: lantern_room
|
|
132
|
+
---
|
|
133
|
+
Narrator: At the top, you find the lantern room—the heart of the lighthouse.
|
|
134
|
+
Narrator: The great lens sits dark and still, its glass covered in years of grime.
|
|
135
|
+
Narrator: But something catches your eye: a small wooden box on the windowsill.
|
|
136
|
+
<<jump finding_box>>
|
|
137
|
+
===
|
|
138
|
+
|
|
139
|
+
title: finding_box
|
|
140
|
+
---
|
|
141
|
+
Narrator: You approach the box carefully, your heart racing.
|
|
142
|
+
Narrator: Carved into its lid are words you recognize: "For when the light returns."
|
|
143
|
+
Narrator: Inside, you find a letter, yellowed with age, and a single match.
|
|
144
|
+
<<jump reading_letter>>
|
|
145
|
+
===
|
|
146
|
+
|
|
147
|
+
title: reading_letter
|
|
148
|
+
---
|
|
149
|
+
Narrator: The letter is in your grandfather's handwriting, dated fifty years ago.
|
|
150
|
+
Narrator: "If you're reading this, you've found your way home. Light the beacon."
|
|
151
|
+
Narrator: "The world needs its light again. Trust in what you know to be true."
|
|
152
|
+
<<jump lighting_beacon>>
|
|
153
|
+
===
|
|
154
|
+
|
|
155
|
+
title: lighting_beacon
|
|
156
|
+
---
|
|
157
|
+
Narrator: You strike the match, its flame dancing in the darkness.
|
|
158
|
+
Narrator: As you light the old lantern, the lens begins to turn, slowly at first.
|
|
159
|
+
Narrator: Light spills across the sea, cutting through the storm like a blade.
|
|
160
|
+
<<jump beacon_awakened>>
|
|
161
|
+
===
|
|
162
|
+
|
|
163
|
+
title: beacon_awakened
|
|
164
|
+
---
|
|
165
|
+
Narrator: The lighthouse awakens, its beam reaching far across the waters.
|
|
166
|
+
Narrator: In the distance, you see something impossible: ships, long thought lost, returning home.
|
|
167
|
+
Narrator: Your grandfather's promise fulfilled, the light guides them safely to shore.
|
|
168
|
+
<<jump epilogue>>
|
|
169
|
+
===
|
|
170
|
+
|
|
171
|
+
title: epilogue
|
|
172
|
+
---
|
|
173
|
+
Narrator: The storm breaks, and dawn paints the sky in shades of gold and rose.
|
|
174
|
+
Narrator: You stand at the top of the lighthouse, watching the ships come home.
|
|
175
|
+
Narrator: The beacon burns bright once more, and you know—this is where you belong.
|
|
176
|
+
===
|
|
106
177
|
`,
|
|
107
178
|
// Add more examples here as they're converted to Yarn format
|
|
108
179
|
};
|
|
@@ -43,6 +43,7 @@ export interface DialogueTree {
|
|
|
43
43
|
nodes: Record<string, DialogueNode>;
|
|
44
44
|
}
|
|
45
45
|
import { FlagSchema } from './flags';
|
|
46
|
+
export type ViewMode = 'graph' | 'yarn' | 'play';
|
|
46
47
|
export interface DialogueEditorProps {
|
|
47
48
|
dialogue: DialogueTree | null;
|
|
48
49
|
onChange: (dialogue: DialogueTree) => void;
|
|
@@ -50,6 +50,14 @@ exports.examplesRegistry = [
|
|
|
50
50
|
filename: 'variable-operations-example.yarn',
|
|
51
51
|
flagSchemaId: 'rpg',
|
|
52
52
|
features: ['variable-operations', 'variable-interpolation', 'numeric-calculations', 'string-variables']
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'linear-story',
|
|
56
|
+
title: 'Linear Story Example',
|
|
57
|
+
description: 'A linear narrative with no branching—just NPCs telling a story. Press Enter to continue.',
|
|
58
|
+
filename: 'linear-story.yarn',
|
|
59
|
+
flagSchemaId: 'basic',
|
|
60
|
+
features: ['linear-narrative', 'npc-only', 'story-driven']
|
|
53
61
|
}
|
|
54
62
|
];
|
|
55
63
|
/**
|
|
@@ -111,6 +111,77 @@ NPC: I've greeted you {$greeting_count} times now.
|
|
|
111
111
|
title: end
|
|
112
112
|
---
|
|
113
113
|
===
|
|
114
|
+
`,
|
|
115
|
+
'linear-story': `title: opening
|
|
116
|
+
---
|
|
117
|
+
Narrator: The old lighthouse stood silent against the storm, its beacon long extinguished.
|
|
118
|
+
Narrator: You've been searching for three days, following the map your grandfather left behind.
|
|
119
|
+
Narrator: The key to the lighthouse door feels cold in your hand, heavy with purpose.
|
|
120
|
+
<<jump lighthouse_entrance>>
|
|
121
|
+
===
|
|
122
|
+
|
|
123
|
+
title: lighthouse_entrance
|
|
124
|
+
---
|
|
125
|
+
Narrator: The door creaks open with a sound that echoes through the empty tower.
|
|
126
|
+
Narrator: Dust motes dance in the beam of your flashlight as you step inside.
|
|
127
|
+
Narrator: The air is still, thick with the scent of salt and old wood.
|
|
128
|
+
<<jump climbing_stairs>>
|
|
129
|
+
===
|
|
130
|
+
|
|
131
|
+
title: climbing_stairs
|
|
132
|
+
---
|
|
133
|
+
Narrator: Your footsteps echo on the spiral staircase as you climb.
|
|
134
|
+
Narrator: Each step feels like a journey through time, the wood groaning under your weight.
|
|
135
|
+
Narrator: You count the steps: twenty, thirty, forty... the tower seems endless.
|
|
136
|
+
<<jump lantern_room>>
|
|
137
|
+
===
|
|
138
|
+
|
|
139
|
+
title: lantern_room
|
|
140
|
+
---
|
|
141
|
+
Narrator: At the top, you find the lantern room—the heart of the lighthouse.
|
|
142
|
+
Narrator: The great lens sits dark and still, its glass covered in years of grime.
|
|
143
|
+
Narrator: But something catches your eye: a small wooden box on the windowsill.
|
|
144
|
+
<<jump finding_box>>
|
|
145
|
+
===
|
|
146
|
+
|
|
147
|
+
title: finding_box
|
|
148
|
+
---
|
|
149
|
+
Narrator: You approach the box carefully, your heart racing.
|
|
150
|
+
Narrator: Carved into its lid are words you recognize: "For when the light returns."
|
|
151
|
+
Narrator: Inside, you find a letter, yellowed with age, and a single match.
|
|
152
|
+
<<jump reading_letter>>
|
|
153
|
+
===
|
|
154
|
+
|
|
155
|
+
title: reading_letter
|
|
156
|
+
---
|
|
157
|
+
Narrator: The letter is in your grandfather's handwriting, dated fifty years ago.
|
|
158
|
+
Narrator: "If you're reading this, you've found your way home. Light the beacon."
|
|
159
|
+
Narrator: "The world needs its light again. Trust in what you know to be true."
|
|
160
|
+
<<jump lighting_beacon>>
|
|
161
|
+
===
|
|
162
|
+
|
|
163
|
+
title: lighting_beacon
|
|
164
|
+
---
|
|
165
|
+
Narrator: You strike the match, its flame dancing in the darkness.
|
|
166
|
+
Narrator: As you light the old lantern, the lens begins to turn, slowly at first.
|
|
167
|
+
Narrator: Light spills across the sea, cutting through the storm like a blade.
|
|
168
|
+
<<jump beacon_awakened>>
|
|
169
|
+
===
|
|
170
|
+
|
|
171
|
+
title: beacon_awakened
|
|
172
|
+
---
|
|
173
|
+
Narrator: The lighthouse awakens, its beam reaching far across the waters.
|
|
174
|
+
Narrator: In the distance, you see something impossible: ships, long thought lost, returning home.
|
|
175
|
+
Narrator: Your grandfather's promise fulfilled, the light guides them safely to shore.
|
|
176
|
+
<<jump epilogue>>
|
|
177
|
+
===
|
|
178
|
+
|
|
179
|
+
title: epilogue
|
|
180
|
+
---
|
|
181
|
+
Narrator: The storm breaks, and dawn paints the sky in shades of gold and rose.
|
|
182
|
+
Narrator: You stand at the top of the lighthouse, watching the ships come home.
|
|
183
|
+
Narrator: The beacon burns bright once more, and you know—this is where you belong.
|
|
184
|
+
===
|
|
114
185
|
`,
|
|
115
186
|
// Add more examples here as they're converted to Yarn format
|
|
116
187
|
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export interface DialogueTree {
|
|
|
43
43
|
nodes: Record<string, DialogueNode>;
|
|
44
44
|
}
|
|
45
45
|
import { FlagSchema } from './flags';
|
|
46
|
+
export type ViewMode = 'graph' | 'yarn' | 'play';
|
|
46
47
|
export interface DialogueEditorProps {
|
|
47
48
|
dialogue: DialogueTree | null;
|
|
48
49
|
onChange: (dialogue: DialogueTree) => void;
|