charon-conversation-editor 0.0.19
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/README.md +251 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Charon Conversation Editor Extension
|
|
2
|
+
|
|
3
|
+
A visual node-based conversation/dialog editor extension for [Charon](https://gamedevware.com/) game data editor, built with React and React Flow.
|
|
4
|
+
|
|
5
|
+
<img width="1065" alt="dashboard" src="./screenshot.png"/>
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
This extension demonstrates how to create a custom document editor for Charon using Web Components and React.
|
|
10
|
+
It provides a visual, node-based interface for designing branching conversations and dialogs, making it easy for
|
|
11
|
+
game designers to create complex narrative structures without writing code.
|
|
12
|
+
|
|
13
|
+
## What is This Example?
|
|
14
|
+
|
|
15
|
+
The Conversation Editor is a fully functional Charon extension that:
|
|
16
|
+
- Provides a visual graph-based editor for dialog trees
|
|
17
|
+
- Allows drag-and-drop node creation and connection
|
|
18
|
+
- Supports different dialog node types (conversations, response choices)
|
|
19
|
+
- Automatically saves changes back to your Charon game data
|
|
20
|
+
- Demonstrates best practices for building custom Charon editors
|
|
21
|
+
|
|
22
|
+
## Architecture: Web Components + React
|
|
23
|
+
|
|
24
|
+
This extension uses **Web Components** as a wrapper around a **React application**. This architecture allows:
|
|
25
|
+
|
|
26
|
+
1. **Framework Agnostic Integration**: Charon can load the extension without knowing it's built with React
|
|
27
|
+
2. **Encapsulation**: Logic is isolated from the main Charon application
|
|
28
|
+
3. **Reusability**: The component can be distributed via NPM and used across projects
|
|
29
|
+
|
|
30
|
+
### How It Works
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Charon Application
|
|
34
|
+
↓
|
|
35
|
+
Custom Element (<ext-conversation-editor>)
|
|
36
|
+
↓
|
|
37
|
+
React Application (with React Flow)
|
|
38
|
+
↓
|
|
39
|
+
Your Game Data
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The Web Component acts as a bridge, implementing the `CharonSchemaEditorElement` interface to receive data from Charon and sending updates back when the user makes changes.
|
|
43
|
+
|
|
44
|
+
## Key Files for Customization
|
|
45
|
+
|
|
46
|
+
### Core Extension Files
|
|
47
|
+
|
|
48
|
+
#### `src/main.tsx`
|
|
49
|
+
**Purpose**: Entry point that registers the Web Component with the browser.
|
|
50
|
+
- Defines the custom element tag name (e.g., `ext-conversation-editor`)
|
|
51
|
+
- Bootstraps the React application
|
|
52
|
+
- **Customize**: Change the element name or registration logic here, don't forget to update `src/package.json` to reflect new element name
|
|
53
|
+
|
|
54
|
+
#### `src/schema.validation/validate.schema.ts`
|
|
55
|
+
**Purpose**: Logic for validating the schema for compliance with the structure required by the editor
|
|
56
|
+
- Checks that the `Schema` contains the required properties.
|
|
57
|
+
- **Customize**: Change if you require additional required schema properties
|
|
58
|
+
|
|
59
|
+
#### `src/conversation.editor.element.tsx`
|
|
60
|
+
**Purpose**: The Web Component wrapper that interfaces with Charon.
|
|
61
|
+
- Implements `CharonSchemaEditorElement` interface
|
|
62
|
+
- Manages subscriptions to `documentControl` from Charon
|
|
63
|
+
- **Customize**: Modify how data is passed between Charon and React, add validation logic
|
|
64
|
+
|
|
65
|
+
#### `src/dev/
|
|
66
|
+
A folder containing a set of mocks simulating the extension's harness during development
|
|
67
|
+
|
|
68
|
+
#### `src/reactive/
|
|
69
|
+
A folder containing a set of **React** state system adapters for **Rx.js**
|
|
70
|
+
|
|
71
|
+
#### `package.json`
|
|
72
|
+
**Purpose**: Defines the extension metadata and Charon integration.
|
|
73
|
+
- Contains the `config.customEditors` section that tells Charon about your extension
|
|
74
|
+
- Specifies which data types and contexts the editor supports
|
|
75
|
+
- **Customize**: Update editor name, Web Component name, styles, and other metadata
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
"config": {
|
|
79
|
+
"customEditors": [
|
|
80
|
+
{
|
|
81
|
+
"id": "ext-conversation-editor",
|
|
82
|
+
"selector": "ext-conversation-editor",
|
|
83
|
+
"name": "Conversation Editor",
|
|
84
|
+
"type": [
|
|
85
|
+
"Schema"
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### UI Components
|
|
93
|
+
|
|
94
|
+
#### `src/conversation.editor.tsx`
|
|
95
|
+
**Purpose**: Main React component that renders the React Flow editor.
|
|
96
|
+
- Sets up the React Flow instance
|
|
97
|
+
- Manages node and edge state
|
|
98
|
+
- Handles user interactions (add node, delete, connect)
|
|
99
|
+
- **Customize**: Modify editor layout, add toolbar buttons, change default behaviors
|
|
100
|
+
|
|
101
|
+
#### `src/components/nodes/`
|
|
102
|
+
**Purpose**: Custom node components for different dialog node types.
|
|
103
|
+
- `dialog.tree.node.tsx`: Standard conversation node
|
|
104
|
+
- `root.node.tsx`: Conversation start node (start marker)
|
|
105
|
+
- **Customize**: Create new node types, modify appearance, add custom fields
|
|
106
|
+
|
|
107
|
+
#### `src/components/property.drawer/property.drawer.tsx`
|
|
108
|
+
**Purpose**: A panel for displaying the properties of the selected dialog node.
|
|
109
|
+
- **Customize**: Add new controls, modify layout, create custom tools for dialog nodes.
|
|
110
|
+
|
|
111
|
+
### Data & State Management
|
|
112
|
+
|
|
113
|
+
#### `src/state/use.control.to.flow.sync.ts`
|
|
114
|
+
**Purpose**: Custom React hook for managing conversation data.
|
|
115
|
+
- Converts between Charon's data format and React Flow's node/edge format (see `src/state/conversation.state.ts`)
|
|
116
|
+
- Handles data transformations
|
|
117
|
+
- **Customize**: Modify data structure, add new fields, change serialization
|
|
118
|
+
|
|
119
|
+
#### `src/models/conversation.tree .ts`
|
|
120
|
+
**Purpose**: TypeScript type definitions for expected conversation data model
|
|
121
|
+
- Defines the shape of conversation data
|
|
122
|
+
- Node types, edge types, and editor state
|
|
123
|
+
- **Customize**: Extend types for new features, don't forget to check for new properties in `src/schema.validation/validate.schema.ts`
|
|
124
|
+
|
|
125
|
+
## React Flow Integration
|
|
126
|
+
|
|
127
|
+
### What is React Flow?
|
|
128
|
+
|
|
129
|
+
[React Flow](https://reactflow.dev/) is a library for building node-based editors and interactive diagrams. It handles:
|
|
130
|
+
- Node rendering and positioning
|
|
131
|
+
- Edge (connection) drawing and routing
|
|
132
|
+
- Drag-and-drop interactions
|
|
133
|
+
- Zoom and pan controls
|
|
134
|
+
- Selection and multi-selection
|
|
135
|
+
|
|
136
|
+
### How It's Used in This Editor
|
|
137
|
+
|
|
138
|
+
#### 1. **Node Layout**
|
|
139
|
+
```tsx
|
|
140
|
+
<ReactFlow
|
|
141
|
+
nodes={nodes} // Array of conversation nodes
|
|
142
|
+
edges={edges} // Connections between nodes
|
|
143
|
+
onNodesChange={onNodesChange}
|
|
144
|
+
onEdgesChange={onEdgesChange}
|
|
145
|
+
onConnect={onConnect}
|
|
146
|
+
nodeTypes={nodeTypes} // Your custom node components
|
|
147
|
+
/>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### 2. **Custom Node Types**
|
|
151
|
+
Each node type is a React component:
|
|
152
|
+
```tsx
|
|
153
|
+
const nodeTypes = {
|
|
154
|
+
dialogue: DialogueNode, // Character speech
|
|
155
|
+
choice: ChoiceNode, // Player options (not implemented)
|
|
156
|
+
condition: ConditionNode // Logic branches (not implemented)
|
|
157
|
+
};
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### 3. **Node Structure**
|
|
161
|
+
Each node in React Flow contains:
|
|
162
|
+
```typescript
|
|
163
|
+
{
|
|
164
|
+
id: string, // Unique identifier
|
|
165
|
+
type: 'dialogue' | 'choice' | 'condition',
|
|
166
|
+
position: { x: number, y: number },
|
|
167
|
+
data: { // Your custom data
|
|
168
|
+
valueControl: ValueControl<DialogueNode> | ValueControl<ChoiceNode> | ValueControl<ConditionNode>,
|
|
169
|
+
// ... other fields
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### 4. **Edges (Connections)**
|
|
175
|
+
Edges connect nodes:
|
|
176
|
+
```typescript
|
|
177
|
+
{
|
|
178
|
+
id: string,
|
|
179
|
+
source: string, // Source node ID
|
|
180
|
+
target: string, // Target node ID
|
|
181
|
+
label?: string // Optional label on connection
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Getting Started
|
|
186
|
+
|
|
187
|
+
### Prerequisites
|
|
188
|
+
- Node.js 21+
|
|
189
|
+
- npm or yarn
|
|
190
|
+
- Basic knowledge of React and TypeScript
|
|
191
|
+
|
|
192
|
+
### Installation
|
|
193
|
+
```bash
|
|
194
|
+
npm install
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Development
|
|
198
|
+
```bash
|
|
199
|
+
npm start
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Building
|
|
203
|
+
```bash
|
|
204
|
+
npm run build
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
This generates a `.tgz` file that can be installed in Charon.
|
|
208
|
+
|
|
209
|
+
### Testing in Charon
|
|
210
|
+
|
|
211
|
+
1. Build the extension: `npm run build`
|
|
212
|
+
2. In Charon's **Project Settings → Extensions** use **Upload NPM Package...** button to upload newly build package from `src\charon-conversation-editor\dist\` folder
|
|
213
|
+
3. Add your extension to the project's extension list
|
|
214
|
+
4. Create or edit a document schema and select "Conversation Editor" as the custom editor
|
|
215
|
+
|
|
216
|
+
## Customization Ideas
|
|
217
|
+
|
|
218
|
+
### Add New Node Types
|
|
219
|
+
1. Create a new component in `src/nodes/NewNodeType.tsx`
|
|
220
|
+
2. Register it in `nodeTypes: NodeTypes` in `src\nodes\node.types.ts`
|
|
221
|
+
3. Add the new node type to your sidebar drawer or to some toolbar
|
|
222
|
+
|
|
223
|
+
### Integrate with AI
|
|
224
|
+
- Add a button to generate dialogue using GPT API
|
|
225
|
+
- Auto-suggest character responses
|
|
226
|
+
- Validate grammar and style
|
|
227
|
+
|
|
228
|
+
### Implement Version Control
|
|
229
|
+
- Save conversation snapshots
|
|
230
|
+
- Add diff view to compare versions
|
|
231
|
+
- Allow branching and merging of conversation trees
|
|
232
|
+
|
|
233
|
+
## Resources
|
|
234
|
+
|
|
235
|
+
- [Charon Documentation](https://gamedevware.github.io/charon/)
|
|
236
|
+
- [Creating Charon Extensions Guide](https://gamedevware.github.io/charon/advanced/extensions/creating_react_extension.html)
|
|
237
|
+
- [React Flow Documentation](https://reactflow.dev/)
|
|
238
|
+
- [Web Components Specification](https://developer.mozilla.org/en-US/docs/Web/Web_Components)
|
|
239
|
+
- [Conversation Tree Schema for Import into Charon](conversation_schemas_to_import.json)
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
MIT
|
|
244
|
+
|
|
245
|
+
## Contributing
|
|
246
|
+
|
|
247
|
+
Contributions are welcome! This example serves as a template for building custom Charon editors. Feel free to fork and modify for your own game's needs.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
**Need Help?** Check the [Charon Discord](https://discord.gg/gamedevware) or [GitHub Issues](https://github.com/gamedevware/charon-extensions/issues).
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/gamedevware/charon-extensions/refs/heads/main/package.json.schema.json",
|
|
3
|
+
"name": "charon-conversation-editor",
|
|
4
|
+
"version": "0.0.19",
|
|
5
|
+
"description": "",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"charon",
|
|
8
|
+
"extensions",
|
|
9
|
+
"conversation editor"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/gamedevware/charon-extensions",
|
|
12
|
+
"bugs": "https://github.com/gamedevware/charon-extensions/issues",
|
|
13
|
+
"author": "GameDevWare, Denis Zykov",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"config": {
|
|
16
|
+
"customEditors": [
|
|
17
|
+
{
|
|
18
|
+
"id": "ext-conversation-editor",
|
|
19
|
+
"selector": "ext-conversation-editor",
|
|
20
|
+
"name": "Conversation Editor",
|
|
21
|
+
"type": [
|
|
22
|
+
"Schema"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"main": "index.js",
|
|
28
|
+
"files": [
|
|
29
|
+
"assets/index.css"
|
|
30
|
+
],
|
|
31
|
+
"type": "module",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"start": "vite",
|
|
34
|
+
"dev": "vite",
|
|
35
|
+
"build": "tsc -b && vite build && copy package.json dist\\package.json && cd dist && npm pack",
|
|
36
|
+
"lint": "eslint .",
|
|
37
|
+
"preview": "vite preview"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@xyflow/react": "^12.8.6",
|
|
41
|
+
"charon-extensions": "2.314.388",
|
|
42
|
+
"dagre": "^0.8.5",
|
|
43
|
+
"react": "^19.2.0",
|
|
44
|
+
"react-dom": "^19.2.0",
|
|
45
|
+
"react-hotkeys-hook": "^5.2.1",
|
|
46
|
+
"rxjs": "^7.8.2",
|
|
47
|
+
"sass": "^1.86.3"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@eslint/js": "^9.21.0",
|
|
51
|
+
"@types/dagre": "^0.7.53",
|
|
52
|
+
"@types/react": "^19.2.2",
|
|
53
|
+
"@types/react-dom": "^19.2.2",
|
|
54
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
55
|
+
"eslint": "^9.21.0",
|
|
56
|
+
"eslint-plugin-react-hooks": "^5.1.0",
|
|
57
|
+
"eslint-plugin-react-refresh": "^0.4.19",
|
|
58
|
+
"globals": "^15.15.0",
|
|
59
|
+
"ts-essentials": "^10.1.1",
|
|
60
|
+
"typescript": "~5.7.2",
|
|
61
|
+
"typescript-eslint": "^8.24.1",
|
|
62
|
+
"vite": "^6.2.0"
|
|
63
|
+
}
|
|
64
|
+
}
|