@nice2dev/game-engine 0.1.0 → 1.0.3

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 (294) hide show
  1. package/CHANGELOG.md +193 -1
  2. package/dist/cjs/ai/BehaviorTree.js +1215 -0
  3. package/dist/cjs/ai/BehaviorTree.js.map +1 -0
  4. package/dist/cjs/ai/StateMachine.js +783 -0
  5. package/dist/cjs/ai/StateMachine.js.map +1 -0
  6. package/dist/cjs/audio/AudioBridge.js +454 -0
  7. package/dist/cjs/audio/AudioBridge.js.map +1 -0
  8. package/dist/cjs/devtools/GameplayAnalytics.js +651 -0
  9. package/dist/cjs/devtools/GameplayAnalytics.js.map +1 -0
  10. package/dist/cjs/dialogue/DialogueSystem.js +1023 -0
  11. package/dist/cjs/dialogue/DialogueSystem.js.map +1 -0
  12. package/dist/cjs/editor/NiceGameEditor.js +569 -71
  13. package/dist/cjs/editor/NiceGameEditor.js.map +1 -1
  14. package/dist/cjs/editor/ShaderGraph.js +1616 -0
  15. package/dist/cjs/editor/ShaderGraph.js.map +1 -0
  16. package/dist/cjs/editor/TimelineEditor.js +819 -0
  17. package/dist/cjs/editor/TimelineEditor.js.map +1 -0
  18. package/dist/cjs/engine/SaveSystemV2.js +494 -0
  19. package/dist/cjs/engine/SaveSystemV2.js.map +1 -0
  20. package/dist/cjs/export/GodotExporter.js +1102 -0
  21. package/dist/cjs/export/GodotExporter.js.map +1 -0
  22. package/dist/cjs/export/PlatformExporter.js +236 -0
  23. package/dist/cjs/export/PlatformExporter.js.map +1 -0
  24. package/dist/cjs/export/ThreeJSExporter.js +1116 -0
  25. package/dist/cjs/export/ThreeJSExporter.js.map +1 -0
  26. package/dist/cjs/export/UnityExporter.js +1193 -0
  27. package/dist/cjs/export/UnityExporter.js.map +1 -0
  28. package/dist/cjs/export/WebExporter.js +1036 -0
  29. package/dist/cjs/export/WebExporter.js.map +1 -0
  30. package/dist/cjs/export/index.js +58 -0
  31. package/dist/cjs/export/index.js.map +1 -0
  32. package/dist/cjs/i18n/useTranslation.js +11 -11
  33. package/dist/cjs/import/AsepriteImporter.js +761 -0
  34. package/dist/cjs/import/AsepriteImporter.js.map +1 -0
  35. package/dist/cjs/import/DragonBonesImporter.js +499 -0
  36. package/dist/cjs/import/DragonBonesImporter.js.map +1 -0
  37. package/dist/cjs/import/GameMakerImporter.js +559 -0
  38. package/dist/cjs/import/GameMakerImporter.js.map +1 -0
  39. package/dist/cjs/import/GodotSceneImporter.js +824 -0
  40. package/dist/cjs/import/GodotSceneImporter.js.map +1 -0
  41. package/dist/cjs/import/LDtkImporter.js +481 -0
  42. package/dist/cjs/import/LDtkImporter.js.map +1 -0
  43. package/dist/cjs/import/Live2DImporter.js +553 -0
  44. package/dist/cjs/import/Live2DImporter.js.map +1 -0
  45. package/dist/cjs/import/NdgFormat.js +499 -0
  46. package/dist/cjs/import/NdgFormat.js.map +1 -0
  47. package/dist/cjs/import/OgmoImporter.js +529 -0
  48. package/dist/cjs/import/OgmoImporter.js.map +1 -0
  49. package/dist/cjs/import/RPGMakerImporter.js +520 -0
  50. package/dist/cjs/import/RPGMakerImporter.js.map +1 -0
  51. package/dist/cjs/import/SceneImporter.js +449 -0
  52. package/dist/cjs/import/SceneImporter.js.map +1 -0
  53. package/dist/cjs/import/SpineImporter.js +583 -0
  54. package/dist/cjs/import/SpineImporter.js.map +1 -0
  55. package/dist/cjs/import/SpriterImporter.js +652 -0
  56. package/dist/cjs/import/SpriterImporter.js.map +1 -0
  57. package/dist/cjs/import/TiledMapImporter.js +859 -0
  58. package/dist/cjs/import/TiledMapImporter.js.map +1 -0
  59. package/dist/cjs/import/UnitySceneImporter.js +732 -0
  60. package/dist/cjs/import/UnitySceneImporter.js.map +1 -0
  61. package/dist/cjs/import/index.js +305 -0
  62. package/dist/cjs/import/index.js.map +1 -0
  63. package/dist/cjs/index.js +291 -1
  64. package/dist/cjs/index.js.map +1 -1
  65. package/dist/cjs/input/GamepadNavigation.js +21 -21
  66. package/dist/cjs/input/useGamepads.js +6 -6
  67. package/dist/cjs/integration/IconSprite.js +281 -0
  68. package/dist/cjs/integration/IconSprite.js.map +1 -0
  69. package/dist/cjs/inventory/InventorySystem.js +930 -0
  70. package/dist/cjs/inventory/InventorySystem.js.map +1 -0
  71. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/AbortController.js.map +1 -1
  72. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/AccessTokenHttpClient.js.map +1 -1
  73. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/DefaultHttpClient.js.map +1 -1
  74. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/DefaultReconnectPolicy.js.map +1 -1
  75. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Errors.js.map +1 -1
  76. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/FetchHttpClient.js.map +1 -1
  77. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HandshakeProtocol.js.map +1 -1
  78. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HeaderNames.js.map +1 -1
  79. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HttpClient.js.map +1 -1
  80. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HttpConnection.js.map +1 -1
  81. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HubConnection.js.map +1 -1
  82. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/HubConnectionBuilder.js.map +1 -1
  83. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/IHubProtocol.js.map +1 -1
  84. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/ILogger.js.map +1 -1
  85. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/ITransport.js.map +1 -1
  86. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/JsonHubProtocol.js.map +1 -1
  87. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Loggers.js.map +1 -1
  88. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/LongPollingTransport.js.map +1 -1
  89. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/MessageBuffer.js.map +1 -1
  90. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/ServerSentEventsTransport.js.map +1 -1
  91. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Subject.js.map +1 -1
  92. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/TextMessageFormat.js.map +1 -1
  93. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/Utils.js.map +1 -1
  94. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/WebSocketTransport.js.map +1 -1
  95. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/XhrHttpClient.js.map +1 -1
  96. package/dist/cjs/node_modules/@microsoft/signalr/dist/esm/pkg-version.js.map +1 -1
  97. package/dist/cjs/quest/QuestSystem.js +924 -0
  98. package/dist/cjs/quest/QuestSystem.js.map +1 -0
  99. package/dist/cjs/rendering/WebGPURenderPipeline.js +658 -0
  100. package/dist/cjs/rendering/WebGPURenderPipeline.js.map +1 -0
  101. package/dist/cjs/scripting/GraphToAST.js +567 -0
  102. package/dist/cjs/scripting/GraphToAST.js.map +1 -0
  103. package/dist/cjs/scripting/LanguageExporter.js +321 -0
  104. package/dist/cjs/scripting/LanguageExporter.js.map +1 -0
  105. package/dist/cjs/scripting/ScriptAST.js +67 -0
  106. package/dist/cjs/scripting/ScriptAST.js.map +1 -0
  107. package/dist/cjs/scripting/VisualScripting2.js +1140 -0
  108. package/dist/cjs/scripting/VisualScripting2.js.map +1 -0
  109. package/dist/cjs/scripting/exporters/CSharpExporter.js +503 -0
  110. package/dist/cjs/scripting/exporters/CSharpExporter.js.map +1 -0
  111. package/dist/cjs/scripting/exporters/GDScriptExporter.js +452 -0
  112. package/dist/cjs/scripting/exporters/GDScriptExporter.js.map +1 -0
  113. package/dist/cjs/scripting/exporters/LuaExporter.js +457 -0
  114. package/dist/cjs/scripting/exporters/LuaExporter.js.map +1 -0
  115. package/dist/cjs/scripting/exporters/PythonExporter.js +565 -0
  116. package/dist/cjs/scripting/exporters/PythonExporter.js.map +1 -0
  117. package/dist/cjs/scripting/exporters/RustExporter.js +525 -0
  118. package/dist/cjs/scripting/exporters/RustExporter.js.map +1 -0
  119. package/dist/cjs/scripting/exporters/TypeScriptExporter.js +570 -0
  120. package/dist/cjs/scripting/exporters/TypeScriptExporter.js.map +1 -0
  121. package/dist/cjs/systems/ParticleSystem2.js +1478 -0
  122. package/dist/cjs/systems/ParticleSystem2.js.map +1 -0
  123. package/dist/cjs/xr/ARVR.js.map +1 -1
  124. package/dist/esm/ai/BehaviorTree.js +1186 -0
  125. package/dist/esm/ai/BehaviorTree.js.map +1 -0
  126. package/dist/esm/ai/StateMachine.js +767 -0
  127. package/dist/esm/ai/StateMachine.js.map +1 -0
  128. package/dist/esm/audio/AudioBridge.js +446 -0
  129. package/dist/esm/audio/AudioBridge.js.map +1 -0
  130. package/dist/esm/devtools/GameplayAnalytics.js +639 -0
  131. package/dist/esm/devtools/GameplayAnalytics.js.map +1 -0
  132. package/dist/esm/dialogue/DialogueSystem.js +1008 -0
  133. package/dist/esm/dialogue/DialogueSystem.js.map +1 -0
  134. package/dist/esm/editor/NiceGameEditor.js +556 -58
  135. package/dist/esm/editor/NiceGameEditor.js.map +1 -1
  136. package/dist/esm/editor/ShaderGraph.js +1606 -0
  137. package/dist/esm/editor/ShaderGraph.js.map +1 -0
  138. package/dist/esm/editor/TimelineEditor.js +800 -0
  139. package/dist/esm/editor/TimelineEditor.js.map +1 -0
  140. package/dist/esm/engine/SaveSystemV2.js +487 -0
  141. package/dist/esm/engine/SaveSystemV2.js.map +1 -0
  142. package/dist/esm/export/GodotExporter.js +1100 -0
  143. package/dist/esm/export/GodotExporter.js.map +1 -0
  144. package/dist/esm/export/PlatformExporter.js +230 -0
  145. package/dist/esm/export/PlatformExporter.js.map +1 -0
  146. package/dist/esm/export/ThreeJSExporter.js +1114 -0
  147. package/dist/esm/export/ThreeJSExporter.js.map +1 -0
  148. package/dist/esm/export/UnityExporter.js +1191 -0
  149. package/dist/esm/export/UnityExporter.js.map +1 -0
  150. package/dist/esm/export/WebExporter.js +1033 -0
  151. package/dist/esm/export/WebExporter.js.map +1 -0
  152. package/dist/esm/export/index.js +44 -0
  153. package/dist/esm/export/index.js.map +1 -0
  154. package/dist/esm/import/AsepriteImporter.js +759 -0
  155. package/dist/esm/import/AsepriteImporter.js.map +1 -0
  156. package/dist/esm/import/DragonBonesImporter.js +496 -0
  157. package/dist/esm/import/DragonBonesImporter.js.map +1 -0
  158. package/dist/esm/import/GameMakerImporter.js +556 -0
  159. package/dist/esm/import/GameMakerImporter.js.map +1 -0
  160. package/dist/esm/import/GodotSceneImporter.js +822 -0
  161. package/dist/esm/import/GodotSceneImporter.js.map +1 -0
  162. package/dist/esm/import/LDtkImporter.js +479 -0
  163. package/dist/esm/import/LDtkImporter.js.map +1 -0
  164. package/dist/esm/import/Live2DImporter.js +550 -0
  165. package/dist/esm/import/Live2DImporter.js.map +1 -0
  166. package/dist/esm/import/NdgFormat.js +490 -0
  167. package/dist/esm/import/NdgFormat.js.map +1 -0
  168. package/dist/esm/import/OgmoImporter.js +526 -0
  169. package/dist/esm/import/OgmoImporter.js.map +1 -0
  170. package/dist/esm/import/RPGMakerImporter.js +517 -0
  171. package/dist/esm/import/RPGMakerImporter.js.map +1 -0
  172. package/dist/esm/import/SceneImporter.js +441 -0
  173. package/dist/esm/import/SceneImporter.js.map +1 -0
  174. package/dist/esm/import/SpineImporter.js +580 -0
  175. package/dist/esm/import/SpineImporter.js.map +1 -0
  176. package/dist/esm/import/SpriterImporter.js +649 -0
  177. package/dist/esm/import/SpriterImporter.js.map +1 -0
  178. package/dist/esm/import/TiledMapImporter.js +857 -0
  179. package/dist/esm/import/TiledMapImporter.js.map +1 -0
  180. package/dist/esm/import/UnitySceneImporter.js +730 -0
  181. package/dist/esm/import/UnitySceneImporter.js.map +1 -0
  182. package/dist/esm/import/index.js +279 -0
  183. package/dist/esm/import/index.js.map +1 -0
  184. package/dist/esm/index.js +47 -3
  185. package/dist/esm/index.js.map +1 -1
  186. package/dist/esm/integration/IconSprite.js +266 -0
  187. package/dist/esm/integration/IconSprite.js.map +1 -0
  188. package/dist/esm/inventory/InventorySystem.js +924 -0
  189. package/dist/esm/inventory/InventorySystem.js.map +1 -0
  190. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/AbortController.js.map +1 -1
  191. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/AccessTokenHttpClient.js.map +1 -1
  192. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/DefaultHttpClient.js.map +1 -1
  193. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/DefaultReconnectPolicy.js.map +1 -1
  194. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Errors.js.map +1 -1
  195. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/FetchHttpClient.js.map +1 -1
  196. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HandshakeProtocol.js.map +1 -1
  197. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HeaderNames.js.map +1 -1
  198. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HttpClient.js.map +1 -1
  199. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HttpConnection.js.map +1 -1
  200. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HubConnection.js.map +1 -1
  201. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/HubConnectionBuilder.js.map +1 -1
  202. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/IHubProtocol.js.map +1 -1
  203. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/ILogger.js.map +1 -1
  204. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/ITransport.js.map +1 -1
  205. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/JsonHubProtocol.js.map +1 -1
  206. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Loggers.js.map +1 -1
  207. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/LongPollingTransport.js.map +1 -1
  208. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/MessageBuffer.js.map +1 -1
  209. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/ServerSentEventsTransport.js.map +1 -1
  210. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Subject.js.map +1 -1
  211. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/TextMessageFormat.js.map +1 -1
  212. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/Utils.js.map +1 -1
  213. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/WebSocketTransport.js.map +1 -1
  214. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/XhrHttpClient.js.map +1 -1
  215. package/dist/esm/node_modules/@microsoft/signalr/dist/esm/pkg-version.js.map +1 -1
  216. package/dist/esm/quest/QuestSystem.js +916 -0
  217. package/dist/esm/quest/QuestSystem.js.map +1 -0
  218. package/dist/esm/rendering/WebGPURenderPipeline.js +642 -0
  219. package/dist/esm/rendering/WebGPURenderPipeline.js.map +1 -0
  220. package/dist/esm/scripting/GraphToAST.js +564 -0
  221. package/dist/esm/scripting/GraphToAST.js.map +1 -0
  222. package/dist/esm/scripting/LanguageExporter.js +311 -0
  223. package/dist/esm/scripting/LanguageExporter.js.map +1 -0
  224. package/dist/esm/scripting/ScriptAST.js +52 -0
  225. package/dist/esm/scripting/ScriptAST.js.map +1 -0
  226. package/dist/esm/scripting/VisualScripting2.js +1130 -0
  227. package/dist/esm/scripting/VisualScripting2.js.map +1 -0
  228. package/dist/esm/scripting/exporters/CSharpExporter.js +501 -0
  229. package/dist/esm/scripting/exporters/CSharpExporter.js.map +1 -0
  230. package/dist/esm/scripting/exporters/GDScriptExporter.js +450 -0
  231. package/dist/esm/scripting/exporters/GDScriptExporter.js.map +1 -0
  232. package/dist/esm/scripting/exporters/LuaExporter.js +455 -0
  233. package/dist/esm/scripting/exporters/LuaExporter.js.map +1 -0
  234. package/dist/esm/scripting/exporters/PythonExporter.js +563 -0
  235. package/dist/esm/scripting/exporters/PythonExporter.js.map +1 -0
  236. package/dist/esm/scripting/exporters/RustExporter.js +523 -0
  237. package/dist/esm/scripting/exporters/RustExporter.js.map +1 -0
  238. package/dist/esm/scripting/exporters/TypeScriptExporter.js +568 -0
  239. package/dist/esm/scripting/exporters/TypeScriptExporter.js.map +1 -0
  240. package/dist/esm/systems/ParticleSystem2.js +1471 -0
  241. package/dist/esm/systems/ParticleSystem2.js.map +1 -0
  242. package/dist/esm/xr/ARVR.js.map +1 -1
  243. package/dist/types/__tests__/setup.d.ts +1 -1
  244. package/dist/types/ai/BehaviorTree.d.ts +375 -0
  245. package/dist/types/ai/StateMachine.d.ts +296 -0
  246. package/dist/types/audio/AudioBridge.d.ts +199 -0
  247. package/dist/types/devtools/GameplayAnalytics.d.ts +279 -0
  248. package/dist/types/dialogue/DialogueSystem.d.ts +326 -0
  249. package/dist/types/dialogue/index.d.ts +2 -0
  250. package/dist/types/editor/NiceGameEditor.d.ts +12 -1
  251. package/dist/types/editor/ShaderGraph.d.ts +207 -0
  252. package/dist/types/editor/TimelineEditor.d.ts +393 -0
  253. package/dist/types/engine/SaveSystemV2.d.ts +155 -0
  254. package/dist/types/export/GodotExporter.d.ts +56 -0
  255. package/dist/types/export/PlatformExporter.d.ts +201 -0
  256. package/dist/types/export/ThreeJSExporter.d.ts +40 -0
  257. package/dist/types/export/UnityExporter.d.ts +69 -0
  258. package/dist/types/export/WebExporter.d.ts +58 -0
  259. package/dist/types/export/index.d.ts +19 -0
  260. package/dist/types/import/AsepriteImporter.d.ts +46 -0
  261. package/dist/types/import/DragonBonesImporter.d.ts +331 -0
  262. package/dist/types/import/GameMakerImporter.d.ts +375 -0
  263. package/dist/types/import/GodotSceneImporter.d.ts +34 -0
  264. package/dist/types/import/LDtkImporter.d.ts +177 -0
  265. package/dist/types/import/Live2DImporter.d.ts +237 -0
  266. package/dist/types/import/NdgFormat.d.ts +387 -0
  267. package/dist/types/import/OgmoImporter.d.ts +237 -0
  268. package/dist/types/import/RPGMakerImporter.d.ts +186 -0
  269. package/dist/types/import/SceneImporter.d.ts +276 -0
  270. package/dist/types/import/SpineImporter.d.ts +372 -0
  271. package/dist/types/import/SpriterImporter.d.ts +230 -0
  272. package/dist/types/import/TiledMapImporter.d.ts +57 -0
  273. package/dist/types/import/UnitySceneImporter.d.ts +87 -0
  274. package/dist/types/import/index.d.ts +59 -0
  275. package/dist/types/index.d.ts +46 -18
  276. package/dist/types/integration/IconSprite.d.ts +196 -0
  277. package/dist/types/inventory/InventorySystem.d.ts +336 -0
  278. package/dist/types/performance/WebGPUCompute.d.ts +0 -10
  279. package/dist/types/quest/QuestSystem.d.ts +287 -0
  280. package/dist/types/rendering/WebGPURenderPipeline.d.ts +255 -0
  281. package/dist/types/scripting/GraphToAST.d.ts +55 -0
  282. package/dist/types/scripting/LanguageExporter.d.ts +136 -0
  283. package/dist/types/scripting/ScriptAST.d.ts +312 -0
  284. package/dist/types/scripting/VisualScripting2.d.ts +353 -0
  285. package/dist/types/scripting/exporters/CSharpExporter.d.ts +44 -0
  286. package/dist/types/scripting/exporters/GDScriptExporter.d.ts +46 -0
  287. package/dist/types/scripting/exporters/LuaExporter.d.ts +46 -0
  288. package/dist/types/scripting/exporters/PythonExporter.d.ts +49 -0
  289. package/dist/types/scripting/exporters/RustExporter.d.ts +46 -0
  290. package/dist/types/scripting/exporters/TypeScriptExporter.d.ts +48 -0
  291. package/dist/types/scripting/exporters/index.d.ts +8 -0
  292. package/dist/types/scripting/index.d.ts +11 -0
  293. package/dist/types/systems/ParticleSystem2.d.ts +646 -0
  294. package/package.json +7 -1
@@ -0,0 +1,1023 @@
1
+ 'use strict';
2
+
3
+ var EventBus = require('../core/EventBus.js');
4
+ var React = require('react');
5
+
6
+ /* ────────────────────────────────────────────────────────────────
7
+ Dialogue System — Visual Dialogue Tree Editor
8
+
9
+ A comprehensive dialogue system with:
10
+ - Visual node-based dialogue tree editor
11
+ - Variables and conditions support
12
+ - Character portraits and emotions
13
+ - Branching conversations
14
+ - Localization support
15
+ ──────────────────────────────────────────────────────────────── */
16
+ /* ═══════════════════════════════════════════════════════════════
17
+ DIALOGUE ENGINE
18
+ ══════════════════════════════════════════════════════════════════ */
19
+ class DialogueEngine {
20
+ constructor(events) {
21
+ this.trees = new Map();
22
+ this.globalVariables = new Map();
23
+ this.currentState = null;
24
+ this.events = events !== null && events !== void 0 ? events : new EventBus.EventBus();
25
+ }
26
+ /* ── Tree Management ──────────────────────────────────────────── */
27
+ registerTree(tree) {
28
+ this.trees.set(tree.id, tree);
29
+ }
30
+ unregisterTree(treeId) {
31
+ this.trees.delete(treeId);
32
+ }
33
+ getTree(treeId) {
34
+ return this.trees.get(treeId);
35
+ }
36
+ getAllTrees() {
37
+ return Array.from(this.trees.values());
38
+ }
39
+ /* ── Variable Management ──────────────────────────────────────── */
40
+ setGlobalVariable(name, value) {
41
+ this.globalVariables.set(name, value);
42
+ this.emitEvent('dialogue:variable-changed', { name, value, scope: 'global' });
43
+ }
44
+ getGlobalVariable(name) {
45
+ return this.globalVariables.get(name);
46
+ }
47
+ getVariable(variableId) {
48
+ var _a;
49
+ if (!this.currentState)
50
+ return this.globalVariables.get(variableId);
51
+ return (_a = this.currentState.variables[variableId]) !== null && _a !== void 0 ? _a : this.globalVariables.get(variableId);
52
+ }
53
+ setVariable(variableId, value, scope) {
54
+ if (scope === 'global') {
55
+ this.globalVariables.set(variableId, value);
56
+ }
57
+ else if (this.currentState) {
58
+ this.currentState.variables[variableId] = value;
59
+ }
60
+ this.emitEvent('dialogue:variable-changed', { variableId, value, scope });
61
+ }
62
+ /* ── Dialogue Flow ────────────────────────────────────────────── */
63
+ startDialogue(treeId, startLabel) {
64
+ const tree = this.trees.get(treeId);
65
+ if (!tree)
66
+ return false;
67
+ // Find start node
68
+ let startNode;
69
+ if (startLabel) {
70
+ startNode = tree.nodes.find((n) => n.type === 'start' && n.label === startLabel);
71
+ }
72
+ if (!startNode) {
73
+ startNode = tree.nodes.find((n) => n.id === tree.startNodeId);
74
+ }
75
+ if (!startNode)
76
+ return false;
77
+ // Initialize state
78
+ const variables = {};
79
+ for (const v of tree.variables) {
80
+ if (v.scope === 'conversation') {
81
+ variables[v.id] = v.defaultValue;
82
+ }
83
+ }
84
+ this.currentState = {
85
+ treeId,
86
+ currentNodeId: startNode.id,
87
+ variables,
88
+ history: [startNode.id],
89
+ choicesMade: [],
90
+ startTime: Date.now(),
91
+ isActive: true,
92
+ isPaused: false,
93
+ };
94
+ this.emitEvent('dialogue:started', { treeId, startNodeId: startNode.id });
95
+ // Advance to first content node
96
+ if (startNode.nextNode) {
97
+ this.goToNode(startNode.nextNode);
98
+ }
99
+ return true;
100
+ }
101
+ endDialogue() {
102
+ if (!this.currentState)
103
+ return;
104
+ const treeId = this.currentState.treeId;
105
+ this.currentState.isActive = false;
106
+ this.emitEvent('dialogue:ended', { treeId, state: { ...this.currentState } });
107
+ this.currentState = null;
108
+ }
109
+ pauseDialogue() {
110
+ if (!this.currentState || !this.currentState.isActive)
111
+ return;
112
+ this.currentState.isPaused = true;
113
+ this.emitEvent('dialogue:paused', {});
114
+ }
115
+ resumeDialogue() {
116
+ if (!this.currentState || !this.currentState.isActive)
117
+ return;
118
+ this.currentState.isPaused = false;
119
+ this.emitEvent('dialogue:resumed', {});
120
+ }
121
+ getState() {
122
+ return this.currentState ? { ...this.currentState } : null;
123
+ }
124
+ isActive() {
125
+ var _a, _b;
126
+ return (_b = (_a = this.currentState) === null || _a === void 0 ? void 0 : _a.isActive) !== null && _b !== void 0 ? _b : false;
127
+ }
128
+ /* ── Node Navigation ──────────────────────────────────────────── */
129
+ goToNode(nodeId) {
130
+ if (!this.currentState)
131
+ return;
132
+ const tree = this.trees.get(this.currentState.treeId);
133
+ if (!tree)
134
+ return;
135
+ const node = tree.nodes.find(n => n.id === nodeId);
136
+ if (!node)
137
+ return;
138
+ this.currentState.currentNodeId = nodeId;
139
+ this.currentState.history.push(nodeId);
140
+ this.emitEvent('dialogue:node-entered', { nodeId, nodeType: node.type });
141
+ this.processNode(node, tree);
142
+ }
143
+ processNode(node, tree) {
144
+ switch (node.type) {
145
+ case 'start':
146
+ if (node.nextNode)
147
+ this.goToNode(node.nextNode);
148
+ break;
149
+ case 'text':
150
+ this.processTextNode(node, tree);
151
+ break;
152
+ case 'choice':
153
+ this.processChoiceNode(node, tree);
154
+ break;
155
+ case 'branch':
156
+ case 'check_variable':
157
+ this.processBranchNode(node);
158
+ break;
159
+ case 'set_variable':
160
+ this.processSetVariableNode(node, tree);
161
+ break;
162
+ case 'event':
163
+ this.processEventNode(node);
164
+ break;
165
+ case 'random':
166
+ this.processRandomNode(node);
167
+ break;
168
+ case 'end':
169
+ this.processEndNode(node);
170
+ break;
171
+ }
172
+ }
173
+ processTextNode(node, tree) {
174
+ const character = tree.characters.find(c => c.id === node.characterId);
175
+ if (character && this.onTextCallback) {
176
+ this.onTextCallback(node, character);
177
+ }
178
+ this.emitEvent('dialogue:text-displayed', {
179
+ nodeId: node.id,
180
+ characterId: node.characterId,
181
+ text: node.text,
182
+ emotion: node.emotion,
183
+ });
184
+ }
185
+ processChoiceNode(node, tree) {
186
+ // Filter valid options based on conditions
187
+ const validOptions = node.options.filter(opt => {
188
+ if (opt.disabled)
189
+ return false;
190
+ if (!opt.conditions || opt.conditions.length === 0)
191
+ return true;
192
+ return opt.conditions.every(c => this.evaluateCondition(c));
193
+ });
194
+ if (this.onChoiceCallback) {
195
+ this.onChoiceCallback(node, validOptions);
196
+ }
197
+ }
198
+ processBranchNode(node) {
199
+ const result = this.evaluateConditions(node.conditions, node.logic);
200
+ const nextNode = result ? node.trueNode : node.falseNode;
201
+ if (nextNode)
202
+ this.goToNode(nextNode);
203
+ }
204
+ processSetVariableNode(node, tree) {
205
+ var _a;
206
+ const variable = tree.variables.find(v => v.id === node.variableId);
207
+ if (!variable) {
208
+ if (node.nextNode)
209
+ this.goToNode(node.nextNode);
210
+ return;
211
+ }
212
+ const currentValue = (_a = this.getVariable(node.variableId)) !== null && _a !== void 0 ? _a : variable.defaultValue;
213
+ let newValue;
214
+ switch (node.operation) {
215
+ case 'set':
216
+ newValue = node.value;
217
+ break;
218
+ case 'add':
219
+ newValue = currentValue + node.value;
220
+ break;
221
+ case 'subtract':
222
+ newValue = currentValue - node.value;
223
+ break;
224
+ case 'multiply':
225
+ newValue = currentValue * node.value;
226
+ break;
227
+ case 'toggle':
228
+ newValue = !currentValue;
229
+ break;
230
+ case 'append':
231
+ newValue = currentValue + node.value;
232
+ break;
233
+ default:
234
+ newValue = node.value;
235
+ }
236
+ this.setVariable(node.variableId, newValue, variable.scope);
237
+ if (node.nextNode)
238
+ this.goToNode(node.nextNode);
239
+ }
240
+ processEventNode(node) {
241
+ this.events.emit(node.eventType, node.eventData);
242
+ this.emitEvent('dialogue:event-triggered', {
243
+ eventType: node.eventType,
244
+ eventData: node.eventData,
245
+ });
246
+ if (node.nextNode)
247
+ this.goToNode(node.nextNode);
248
+ }
249
+ processRandomNode(node) {
250
+ const totalWeight = node.outputs.reduce((sum, out) => sum + out.weight, 0);
251
+ let random = Math.random() * totalWeight;
252
+ for (const output of node.outputs) {
253
+ random -= output.weight;
254
+ if (random <= 0 && output.nextNode) {
255
+ this.goToNode(output.nextNode);
256
+ return;
257
+ }
258
+ }
259
+ // Fallback to first output
260
+ const first = node.outputs[0];
261
+ if (first === null || first === void 0 ? void 0 : first.nextNode)
262
+ this.goToNode(first.nextNode);
263
+ }
264
+ processEndNode(node) {
265
+ // Apply final variable changes
266
+ if (node.setVariables && this.currentState) {
267
+ const tree = this.trees.get(this.currentState.treeId);
268
+ if (tree) {
269
+ for (const sv of node.setVariables) {
270
+ const variable = tree.variables.find(v => v.id === sv.variableId);
271
+ if (variable) {
272
+ this.setVariable(sv.variableId, sv.value, variable.scope);
273
+ }
274
+ }
275
+ }
276
+ }
277
+ if (this.onEndCallback && this.currentState) {
278
+ this.onEndCallback(node, this.currentState);
279
+ }
280
+ this.endDialogue();
281
+ }
282
+ /* ── Choice Selection ─────────────────────────────────────────── */
283
+ selectChoice(optionId) {
284
+ if (!this.currentState || !this.currentState.isActive)
285
+ return false;
286
+ const tree = this.trees.get(this.currentState.treeId);
287
+ if (!tree)
288
+ return false;
289
+ const node = tree.nodes.find(n => n.id === this.currentState.currentNodeId);
290
+ if (!node || node.type !== 'choice')
291
+ return false;
292
+ const choice = node.options.find(o => o.id === optionId);
293
+ if (!choice)
294
+ return false;
295
+ // Apply variables from choice
296
+ if (choice.setVariables) {
297
+ for (const sv of choice.setVariables) {
298
+ const variable = tree.variables.find(v => v.id === sv.variableId);
299
+ if (variable) {
300
+ this.setVariable(sv.variableId, sv.value, variable.scope);
301
+ }
302
+ }
303
+ }
304
+ this.currentState.choicesMade.push({
305
+ nodeId: node.id,
306
+ optionId,
307
+ timestamp: Date.now(),
308
+ });
309
+ this.emitEvent('dialogue:choice-selected', {
310
+ nodeId: node.id,
311
+ optionId,
312
+ text: choice.text,
313
+ });
314
+ if (choice.nextNode) {
315
+ this.goToNode(choice.nextNode);
316
+ }
317
+ return true;
318
+ }
319
+ /** Advance to next node (for text nodes) */
320
+ advance() {
321
+ if (!this.currentState || !this.currentState.isActive)
322
+ return false;
323
+ const tree = this.trees.get(this.currentState.treeId);
324
+ if (!tree)
325
+ return false;
326
+ const node = tree.nodes.find(n => n.id === this.currentState.currentNodeId);
327
+ if (!node)
328
+ return false;
329
+ if (node.type === 'text' && node.nextNode) {
330
+ this.goToNode(node.nextNode);
331
+ return true;
332
+ }
333
+ return false;
334
+ }
335
+ /* ── Condition Evaluation ─────────────────────────────────────── */
336
+ evaluateConditions(conditions, logic) {
337
+ if (conditions.length === 0)
338
+ return true;
339
+ if (logic === 'and') {
340
+ return conditions.every(c => this.evaluateCondition(c));
341
+ }
342
+ else {
343
+ return conditions.some(c => this.evaluateCondition(c));
344
+ }
345
+ }
346
+ evaluateCondition(condition) {
347
+ const varValue = this.getVariable(condition.variableId);
348
+ if (varValue === undefined)
349
+ return false;
350
+ const { operator, value } = condition;
351
+ switch (operator) {
352
+ case 'eq':
353
+ return varValue === value;
354
+ case 'neq':
355
+ return varValue !== value;
356
+ case 'gt':
357
+ return varValue > value;
358
+ case 'lt':
359
+ return varValue < value;
360
+ case 'gte':
361
+ return varValue >= value;
362
+ case 'lte':
363
+ return varValue <= value;
364
+ case 'contains':
365
+ return String(varValue).includes(String(value));
366
+ case 'startsWith':
367
+ return String(varValue).startsWith(String(value));
368
+ case 'endsWith':
369
+ return String(varValue).endsWith(String(value));
370
+ default:
371
+ return false;
372
+ }
373
+ }
374
+ /* ── Callbacks ────────────────────────────────────────────────── */
375
+ onText(callback) {
376
+ this.onTextCallback = callback;
377
+ }
378
+ onChoice(callback) {
379
+ this.onChoiceCallback = callback;
380
+ }
381
+ onEnd(callback) {
382
+ this.onEndCallback = callback;
383
+ }
384
+ /* ── Events ───────────────────────────────────────────────────── */
385
+ emitEvent(type, data) {
386
+ var _a, _b, _c, _d;
387
+ this.events.emit(type, {
388
+ type,
389
+ treeId: (_b = (_a = this.currentState) === null || _a === void 0 ? void 0 : _a.treeId) !== null && _b !== void 0 ? _b : '',
390
+ nodeId: (_d = (_c = this.currentState) === null || _c === void 0 ? void 0 : _c.currentNodeId) !== null && _d !== void 0 ? _d : undefined,
391
+ data,
392
+ timestamp: Date.now(),
393
+ });
394
+ }
395
+ subscribe(eventType, handler) {
396
+ return this.events.on(eventType, handler);
397
+ }
398
+ }
399
+ /* ═══════════════════════════════════════════════════════════════
400
+ DIALOGUE TREE BUILDER (Fluent API)
401
+ ══════════════════════════════════════════════════════════════════ */
402
+ class DialogueTreeBuilder {
403
+ constructor(id, name) {
404
+ this.nodeCounter = 0;
405
+ this.tree = {
406
+ id,
407
+ name,
408
+ version: '1.0.0',
409
+ characters: [],
410
+ variables: [],
411
+ nodes: [],
412
+ startNodeId: '',
413
+ metadata: {
414
+ created: new Date().toISOString(),
415
+ modified: new Date().toISOString(),
416
+ locale: 'en',
417
+ },
418
+ };
419
+ }
420
+ generateId() {
421
+ return `node_${++this.nodeCounter}`;
422
+ }
423
+ /* ── Metadata ─────────────────────────────────────────────────── */
424
+ description(desc) {
425
+ this.tree.description = desc;
426
+ return this;
427
+ }
428
+ author(author) {
429
+ this.tree.metadata.author = author;
430
+ return this;
431
+ }
432
+ locale(locale) {
433
+ this.tree.metadata.locale = locale;
434
+ return this;
435
+ }
436
+ tags(tags) {
437
+ this.tree.metadata.tags = tags;
438
+ return this;
439
+ }
440
+ /* ── Characters ───────────────────────────────────────────────── */
441
+ addCharacter(character) {
442
+ this.tree.characters.push(character);
443
+ return this;
444
+ }
445
+ /* ── Variables ────────────────────────────────────────────────── */
446
+ addVariable(variable) {
447
+ this.tree.variables.push(variable);
448
+ return this;
449
+ }
450
+ boolVar(id, name, defaultValue = false, scope = 'conversation') {
451
+ return this.addVariable({ id, name, type: 'boolean', defaultValue, scope });
452
+ }
453
+ numVar(id, name, defaultValue = 0, scope = 'conversation') {
454
+ return this.addVariable({ id, name, type: 'number', defaultValue, scope });
455
+ }
456
+ strVar(id, name, defaultValue = '', scope = 'conversation') {
457
+ return this.addVariable({ id, name, type: 'string', defaultValue, scope });
458
+ }
459
+ /* ── Nodes ────────────────────────────────────────────────────── */
460
+ addStart(label, nextNode = null, position = { x: 0, y: 0 }) {
461
+ const id = this.generateId();
462
+ const node = { id, type: 'start', label, nextNode, position };
463
+ this.tree.nodes.push(node);
464
+ if (!this.tree.startNodeId)
465
+ this.tree.startNodeId = id;
466
+ return this;
467
+ }
468
+ addText(characterId, text, nextNode = null, options = {}) {
469
+ var _a;
470
+ const id = this.generateId();
471
+ const node = {
472
+ id,
473
+ type: 'text',
474
+ characterId,
475
+ text,
476
+ nextNode,
477
+ position: (_a = options.position) !== null && _a !== void 0 ? _a : { x: 100, y: 0 },
478
+ ...options,
479
+ };
480
+ this.tree.nodes.push(node);
481
+ return this;
482
+ }
483
+ addChoice(options, settings = {}) {
484
+ var _a;
485
+ const id = this.generateId();
486
+ const node = {
487
+ id,
488
+ type: 'choice',
489
+ options,
490
+ position: (_a = settings.position) !== null && _a !== void 0 ? _a : { x: 200, y: 0 },
491
+ ...settings,
492
+ };
493
+ this.tree.nodes.push(node);
494
+ return this;
495
+ }
496
+ addBranch(conditions, trueNode, falseNode, logic = 'and', position = { x: 150, y: 0 }) {
497
+ const id = this.generateId();
498
+ const node = {
499
+ id,
500
+ type: 'branch',
501
+ conditions,
502
+ logic,
503
+ trueNode,
504
+ falseNode,
505
+ position,
506
+ };
507
+ this.tree.nodes.push(node);
508
+ return this;
509
+ }
510
+ addSetVariable(variableId, operation, value, nextNode = null, position = { x: 150, y: 0 }) {
511
+ const id = this.generateId();
512
+ const node = {
513
+ id,
514
+ type: 'set_variable',
515
+ variableId,
516
+ operation,
517
+ value,
518
+ nextNode,
519
+ position,
520
+ };
521
+ this.tree.nodes.push(node);
522
+ return this;
523
+ }
524
+ addEvent(eventType, eventData, nextNode = null, position = { x: 150, y: 0 }) {
525
+ const id = this.generateId();
526
+ const node = {
527
+ id,
528
+ type: 'event',
529
+ eventType,
530
+ eventData,
531
+ nextNode,
532
+ position,
533
+ };
534
+ this.tree.nodes.push(node);
535
+ return this;
536
+ }
537
+ addRandom(outputs, position = { x: 150, y: 0 }) {
538
+ const id = this.generateId();
539
+ const node = {
540
+ id,
541
+ type: 'random',
542
+ outputs: outputs.map((o, i) => ({ ...o, id: `out_${i}` })),
543
+ position,
544
+ };
545
+ this.tree.nodes.push(node);
546
+ return this;
547
+ }
548
+ addEnd(result = 'success', setVariables, position = { x: 300, y: 0 }) {
549
+ const id = this.generateId();
550
+ const node = {
551
+ id,
552
+ type: 'end',
553
+ result,
554
+ setVariables,
555
+ position,
556
+ };
557
+ this.tree.nodes.push(node);
558
+ return this;
559
+ }
560
+ /* ── Build ────────────────────────────────────────────────────── */
561
+ build() {
562
+ this.tree.metadata.modified = new Date().toISOString();
563
+ return { ...this.tree };
564
+ }
565
+ /** Get the ID of the last added node */
566
+ lastNodeId() {
567
+ var _a;
568
+ const lastNode = this.tree.nodes[this.tree.nodes.length - 1];
569
+ return (_a = lastNode === null || lastNode === void 0 ? void 0 : lastNode.id) !== null && _a !== void 0 ? _a : '';
570
+ }
571
+ /** Get node by index (1-based for readability) */
572
+ nodeId(index) {
573
+ return `node_${index}`;
574
+ }
575
+ }
576
+ /**
577
+ * React hook for typewriter text effect
578
+ */
579
+ function useTypewriter(text, speed = 50, enabled = true) {
580
+ const [displayedText, setDisplayedText] = React.useState('');
581
+ const [isComplete, setIsComplete] = React.useState(!enabled);
582
+ const indexRef = React.useRef(0);
583
+ React.useEffect(() => {
584
+ if (!enabled) {
585
+ setDisplayedText(text);
586
+ setIsComplete(true);
587
+ return;
588
+ }
589
+ setDisplayedText('');
590
+ setIsComplete(false);
591
+ indexRef.current = 0;
592
+ const interval = setInterval(() => {
593
+ if (indexRef.current >= text.length) {
594
+ setIsComplete(true);
595
+ clearInterval(interval);
596
+ return;
597
+ }
598
+ indexRef.current++;
599
+ setDisplayedText(text.slice(0, indexRef.current));
600
+ }, 1000 / speed);
601
+ return () => clearInterval(interval);
602
+ }, [text, speed, enabled]);
603
+ const skip = React.useCallback(() => {
604
+ setDisplayedText(text);
605
+ setIsComplete(true);
606
+ }, [text]);
607
+ return { displayedText, isComplete, skip };
608
+ }
609
+ /**
610
+ * DialogueBox component for displaying dialogue text
611
+ */
612
+ const DialogueBox = ({ text, characterName, portrait, emotion = 'neutral', textEffect = 'typewriter', textSpeed = 50, onComplete, onAdvance, className = '', style, }) => {
613
+ const { displayedText, isComplete, skip } = useTypewriter(text, textSpeed, textEffect === 'typewriter');
614
+ React.useEffect(() => {
615
+ if (isComplete && onComplete) {
616
+ onComplete();
617
+ }
618
+ }, [isComplete, onComplete]);
619
+ const handleClick = () => {
620
+ if (!isComplete) {
621
+ skip();
622
+ }
623
+ else if (onAdvance) {
624
+ onAdvance();
625
+ }
626
+ };
627
+ return React.createElement('div', {
628
+ className: `nice-dialogue-box ${className}`,
629
+ style: {
630
+ display: 'flex',
631
+ gap: '16px',
632
+ padding: '16px',
633
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
634
+ borderRadius: '8px',
635
+ color: 'white',
636
+ cursor: 'pointer',
637
+ ...style,
638
+ },
639
+ onClick: handleClick,
640
+ 'data-emotion': emotion,
641
+ }, [
642
+ portrait && React.createElement('div', {
643
+ key: 'portrait',
644
+ className: 'nice-dialogue-portrait',
645
+ style: {
646
+ width: '80px',
647
+ height: '80px',
648
+ flexShrink: 0,
649
+ borderRadius: '8px',
650
+ overflow: 'hidden',
651
+ },
652
+ }, React.createElement('img', {
653
+ src: portrait,
654
+ alt: characterName !== null && characterName !== void 0 ? characterName : 'Character',
655
+ style: { width: '100%', height: '100%', objectFit: 'cover' },
656
+ })),
657
+ React.createElement('div', {
658
+ key: 'content',
659
+ className: 'nice-dialogue-content',
660
+ style: { flex: 1 },
661
+ }, [
662
+ characterName && React.createElement('div', {
663
+ key: 'name',
664
+ className: 'nice-dialogue-name',
665
+ style: {
666
+ fontWeight: 'bold',
667
+ marginBottom: '8px',
668
+ color: '#64b5f6',
669
+ },
670
+ }, characterName),
671
+ React.createElement('div', {
672
+ key: 'text',
673
+ className: 'nice-dialogue-text',
674
+ style: { lineHeight: 1.6 },
675
+ }, displayedText),
676
+ React.createElement('div', {
677
+ key: 'indicator',
678
+ className: 'nice-dialogue-indicator',
679
+ style: {
680
+ marginTop: '8px',
681
+ textAlign: 'right',
682
+ opacity: isComplete ? 1 : 0.5,
683
+ fontSize: '12px',
684
+ },
685
+ }, isComplete ? '▼ Click to continue' : '...'),
686
+ ]),
687
+ ]);
688
+ };
689
+ /**
690
+ * ChoiceList component for displaying dialogue choices
691
+ */
692
+ const ChoiceList = ({ options, prompt, onSelect, timeout, className = '', style, }) => {
693
+ const [timeLeft, setTimeLeft] = React.useState(timeout !== null && timeout !== void 0 ? timeout : 0);
694
+ const [selectedIndex, setSelectedIndex] = React.useState(0);
695
+ // Timeout countdown
696
+ React.useEffect(() => {
697
+ if (!timeout)
698
+ return;
699
+ setTimeLeft(timeout);
700
+ const interval = setInterval(() => {
701
+ setTimeLeft(prev => {
702
+ if (prev <= 100) {
703
+ // Auto-select first option
704
+ const firstValid = options.find(o => !o.disabled);
705
+ if (firstValid)
706
+ onSelect(firstValid.id);
707
+ return 0;
708
+ }
709
+ return prev - 100;
710
+ });
711
+ }, 100);
712
+ return () => clearInterval(interval);
713
+ }, [timeout, options, onSelect]);
714
+ // Keyboard navigation
715
+ React.useEffect(() => {
716
+ const handleKeyDown = (e) => {
717
+ const validOptions = options.filter(o => !o.disabled);
718
+ switch (e.key) {
719
+ case 'ArrowUp':
720
+ e.preventDefault();
721
+ setSelectedIndex(prev => (prev - 1 + validOptions.length) % validOptions.length);
722
+ break;
723
+ case 'ArrowDown':
724
+ e.preventDefault();
725
+ setSelectedIndex(prev => (prev + 1) % validOptions.length);
726
+ break;
727
+ case 'Enter':
728
+ case ' ':
729
+ e.preventDefault();
730
+ if (validOptions[selectedIndex]) {
731
+ onSelect(validOptions[selectedIndex].id);
732
+ }
733
+ break;
734
+ }
735
+ };
736
+ window.addEventListener('keydown', handleKeyDown);
737
+ return () => window.removeEventListener('keydown', handleKeyDown);
738
+ }, [options, selectedIndex, onSelect]);
739
+ const validOptions = options.filter(o => !o.disabled);
740
+ return React.createElement('div', {
741
+ className: `nice-choice-list ${className}`,
742
+ style: {
743
+ padding: '16px',
744
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
745
+ borderRadius: '8px',
746
+ color: 'white',
747
+ ...style,
748
+ },
749
+ }, [
750
+ prompt && React.createElement('div', {
751
+ key: 'prompt',
752
+ className: 'nice-choice-prompt',
753
+ style: {
754
+ marginBottom: '16px',
755
+ fontStyle: 'italic',
756
+ opacity: 0.9,
757
+ },
758
+ }, prompt),
759
+ timeout && timeLeft > 0 && React.createElement('div', {
760
+ key: 'timer',
761
+ className: 'nice-choice-timer',
762
+ style: {
763
+ marginBottom: '8px',
764
+ height: '4px',
765
+ backgroundColor: 'rgba(255, 255, 255, 0.2)',
766
+ borderRadius: '2px',
767
+ overflow: 'hidden',
768
+ },
769
+ }, React.createElement('div', {
770
+ style: {
771
+ width: `${(timeLeft / timeout) * 100}%`,
772
+ height: '100%',
773
+ backgroundColor: timeLeft < 3000 ? '#f44336' : '#4caf50',
774
+ transition: 'width 0.1s linear',
775
+ },
776
+ })),
777
+ React.createElement('div', {
778
+ key: 'options',
779
+ className: 'nice-choice-options',
780
+ style: { display: 'flex', flexDirection: 'column', gap: '8px' },
781
+ }, validOptions.map((option, index) => React.createElement('button', {
782
+ key: option.id,
783
+ className: `nice-choice-option ${index === selectedIndex ? 'selected' : ''}`,
784
+ onClick: () => onSelect(option.id),
785
+ title: option.tooltip,
786
+ style: {
787
+ padding: '12px 16px',
788
+ backgroundColor: index === selectedIndex ? 'rgba(100, 181, 246, 0.3)' : 'rgba(255, 255, 255, 0.1)',
789
+ border: index === selectedIndex ? '2px solid #64b5f6' : '2px solid transparent',
790
+ borderRadius: '4px',
791
+ color: 'white',
792
+ cursor: 'pointer',
793
+ textAlign: 'left',
794
+ transition: 'all 0.2s ease',
795
+ },
796
+ }, option.text))),
797
+ ]);
798
+ };
799
+ /* ═══════════════════════════════════════════════════════════════
800
+ SERIALIZATION & VALIDATION
801
+ ══════════════════════════════════════════════════════════════════ */
802
+ /**
803
+ * Serialize dialogue tree to JSON string
804
+ */
805
+ function serializeDialogueTree(tree) {
806
+ return JSON.stringify(tree, null, 2);
807
+ }
808
+ /**
809
+ * Deserialize dialogue tree from JSON string
810
+ */
811
+ function deserializeDialogueTree(json) {
812
+ const parsed = JSON.parse(json);
813
+ return validateDialogueTree(parsed);
814
+ }
815
+ /**
816
+ * Validate dialogue tree structure
817
+ */
818
+ function validateDialogueTree(tree) {
819
+ if (!tree || typeof tree !== 'object') {
820
+ throw new Error('Invalid dialogue tree: must be an object');
821
+ }
822
+ const t = tree;
823
+ if (typeof t.id !== 'string' || !t.id) {
824
+ throw new Error('Invalid dialogue tree: missing id');
825
+ }
826
+ if (typeof t.name !== 'string' || !t.name) {
827
+ throw new Error('Invalid dialogue tree: missing name');
828
+ }
829
+ if (!Array.isArray(t.nodes)) {
830
+ throw new Error('Invalid dialogue tree: nodes must be an array');
831
+ }
832
+ if (!Array.isArray(t.characters)) {
833
+ throw new Error('Invalid dialogue tree: characters must be an array');
834
+ }
835
+ if (!Array.isArray(t.variables)) {
836
+ throw new Error('Invalid dialogue tree: variables must be an array');
837
+ }
838
+ if (typeof t.startNodeId !== 'string') {
839
+ throw new Error('Invalid dialogue tree: missing startNodeId');
840
+ }
841
+ // Validate all node connections
842
+ const nodeIds = new Set(t.nodes.map(n => n.id));
843
+ for (const node of t.nodes) {
844
+ validateNodeConnections(node, nodeIds);
845
+ }
846
+ return t;
847
+ }
848
+ function validateNodeConnections(node, validIds) {
849
+ const checkId = (id, context) => {
850
+ if (id !== null && !validIds.has(id)) {
851
+ throw new Error(`Invalid node reference "${id}" in ${context} of node "${node.id}"`);
852
+ }
853
+ };
854
+ switch (node.type) {
855
+ case 'start':
856
+ case 'text':
857
+ case 'set_variable':
858
+ case 'event':
859
+ checkId(node.nextNode, 'nextNode');
860
+ break;
861
+ case 'choice':
862
+ for (const opt of node.options) {
863
+ checkId(opt.nextNode, `option "${opt.id}"`);
864
+ }
865
+ break;
866
+ case 'branch':
867
+ case 'check_variable':
868
+ checkId(node.trueNode, 'trueNode');
869
+ checkId(node.falseNode, 'falseNode');
870
+ break;
871
+ case 'random':
872
+ for (const out of node.outputs) {
873
+ checkId(out.nextNode, `output "${out.id}"`);
874
+ }
875
+ break;
876
+ }
877
+ }
878
+ /**
879
+ * Find unreachable nodes in dialogue tree
880
+ */
881
+ function findUnreachableNodes(tree) {
882
+ const reachable = new Set();
883
+ const toVisit = [tree.startNodeId];
884
+ while (toVisit.length > 0) {
885
+ const nodeId = toVisit.pop();
886
+ if (reachable.has(nodeId))
887
+ continue;
888
+ reachable.add(nodeId);
889
+ const node = tree.nodes.find(n => n.id === nodeId);
890
+ if (!node)
891
+ continue;
892
+ const nextIds = getNextNodeIds(node);
893
+ for (const id of nextIds) {
894
+ if (id && !reachable.has(id)) {
895
+ toVisit.push(id);
896
+ }
897
+ }
898
+ }
899
+ return tree.nodes
900
+ .filter(n => !reachable.has(n.id) && n.type !== 'start')
901
+ .map(n => n.id);
902
+ }
903
+ function getNextNodeIds(node) {
904
+ switch (node.type) {
905
+ case 'start':
906
+ case 'text':
907
+ case 'set_variable':
908
+ case 'event':
909
+ return [node.nextNode];
910
+ case 'choice':
911
+ return node.options.map(o => o.nextNode);
912
+ case 'branch':
913
+ case 'check_variable':
914
+ return [node.trueNode, node.falseNode];
915
+ case 'random':
916
+ return node.outputs.map(o => o.nextNode);
917
+ case 'end':
918
+ return [];
919
+ default:
920
+ return [];
921
+ }
922
+ }
923
+ /**
924
+ * Extract all translatable strings from a dialogue tree
925
+ */
926
+ function extractTranslatableStrings(tree) {
927
+ const nodeTexts = {};
928
+ const characterNames = {};
929
+ for (const node of tree.nodes) {
930
+ if (node.type === 'text') {
931
+ nodeTexts[node.id] = node.text;
932
+ }
933
+ else if (node.type === 'choice') {
934
+ const choiceNode = node;
935
+ if (choiceNode.prompt) {
936
+ nodeTexts[`${node.id}_prompt`] = choiceNode.prompt;
937
+ }
938
+ for (const opt of choiceNode.options) {
939
+ nodeTexts[`${node.id}_${opt.id}`] = opt.text;
940
+ if (opt.tooltip) {
941
+ nodeTexts[`${node.id}_${opt.id}_tooltip`] = opt.tooltip;
942
+ }
943
+ }
944
+ }
945
+ }
946
+ for (const char of tree.characters) {
947
+ characterNames[char.id] = char.displayName;
948
+ }
949
+ return { nodeTexts, characterNames };
950
+ }
951
+ /**
952
+ * Apply localization to a dialogue tree (creates a copy)
953
+ */
954
+ function applyLocalization(tree, localization) {
955
+ const localized = JSON.parse(JSON.stringify(tree));
956
+ localized.metadata.locale = localization.locale;
957
+ for (const node of localized.nodes) {
958
+ if (node.type === 'text' && localization.texts[node.id]) {
959
+ node.text = localization.texts[node.id];
960
+ }
961
+ else if (node.type === 'choice') {
962
+ const choiceNode = node;
963
+ if (localization.texts[`${node.id}_prompt`]) {
964
+ choiceNode.prompt = localization.texts[`${node.id}_prompt`];
965
+ }
966
+ for (const opt of choiceNode.options) {
967
+ if (localization.texts[`${node.id}_${opt.id}`]) {
968
+ opt.text = localization.texts[`${node.id}_${opt.id}`];
969
+ }
970
+ if (localization.texts[`${node.id}_${opt.id}_tooltip`]) {
971
+ opt.tooltip = localization.texts[`${node.id}_${opt.id}_tooltip`];
972
+ }
973
+ }
974
+ }
975
+ }
976
+ for (const char of localized.characters) {
977
+ if (localization.characterNames[char.id]) {
978
+ char.displayName = localization.characterNames[char.id];
979
+ }
980
+ }
981
+ return localized;
982
+ }
983
+ /* ═══════════════════════════════════════════════════════════════
984
+ DEFAULT EXPORTS
985
+ ══════════════════════════════════════════════════════════════════ */
986
+ const DEFAULT_TEXT_SPEED = 50; // characters per second
987
+ const EMOTION_COLORS = {
988
+ neutral: '#9e9e9e',
989
+ happy: '#4caf50',
990
+ sad: '#2196f3',
991
+ angry: '#f44336',
992
+ surprised: '#ff9800',
993
+ scared: '#9c27b0',
994
+ disgusted: '#795548',
995
+ confused: '#607d8b',
996
+ thoughtful: '#3f51b5',
997
+ excited: '#ffeb3b',
998
+ tired: '#455a64',
999
+ love: '#e91e63',
1000
+ custom: '#ffffff',
1001
+ };
1002
+ function createEmptyDialogueTree(id, name) {
1003
+ return new DialogueTreeBuilder(id, name)
1004
+ .addStart('main', null)
1005
+ .addEnd('success')
1006
+ .build();
1007
+ }
1008
+
1009
+ exports.ChoiceList = ChoiceList;
1010
+ exports.DEFAULT_TEXT_SPEED = DEFAULT_TEXT_SPEED;
1011
+ exports.DialogueBox = DialogueBox;
1012
+ exports.DialogueEngine = DialogueEngine;
1013
+ exports.DialogueTreeBuilder = DialogueTreeBuilder;
1014
+ exports.EMOTION_COLORS = EMOTION_COLORS;
1015
+ exports.applyLocalization = applyLocalization;
1016
+ exports.createEmptyDialogueTree = createEmptyDialogueTree;
1017
+ exports.deserializeDialogueTree = deserializeDialogueTree;
1018
+ exports.extractTranslatableStrings = extractTranslatableStrings;
1019
+ exports.findUnreachableNodes = findUnreachableNodes;
1020
+ exports.serializeDialogueTree = serializeDialogueTree;
1021
+ exports.useTypewriter = useTypewriter;
1022
+ exports.validateDialogueTree = validateDialogueTree;
1023
+ //# sourceMappingURL=DialogueSystem.js.map