@luna-editor/engine 0.1.0 → 0.3.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 (65) hide show
  1. package/dist/Player.d.ts +1 -1
  2. package/dist/Player.js +527 -85
  3. package/dist/api/conversationBranch.d.ts +4 -0
  4. package/dist/api/conversationBranch.js +83 -0
  5. package/dist/components/BackgroundLayer.d.ts +19 -0
  6. package/dist/components/BackgroundLayer.js +218 -0
  7. package/dist/components/ClickWaitIndicator.d.ts +10 -0
  8. package/dist/components/ClickWaitIndicator.js +31 -0
  9. package/dist/components/ConversationBranchBox.d.ts +2 -0
  10. package/dist/components/ConversationBranchBox.js +29 -0
  11. package/dist/components/DialogueBox.js +16 -1
  12. package/dist/components/FontSettingsPanel.d.ts +10 -0
  13. package/dist/components/FontSettingsPanel.js +30 -0
  14. package/dist/components/FullscreenTextBox.d.ts +6 -0
  15. package/dist/components/FullscreenTextBox.js +70 -0
  16. package/dist/components/GameScreen.d.ts +1 -0
  17. package/dist/components/GameScreen.js +363 -81
  18. package/dist/components/PluginComponentProvider.d.ts +2 -2
  19. package/dist/components/PluginComponentProvider.js +3 -3
  20. package/dist/components/TimeWaitIndicator.d.ts +15 -0
  21. package/dist/components/TimeWaitIndicator.js +17 -0
  22. package/dist/contexts/AudioContext.d.ts +14 -0
  23. package/dist/contexts/AudioContext.js +14 -0
  24. package/dist/contexts/DataContext.d.ts +4 -1
  25. package/dist/contexts/DataContext.js +82 -13
  26. package/dist/hooks/useBacklog.js +3 -0
  27. package/dist/hooks/useConversationBranch.d.ts +16 -0
  28. package/dist/hooks/useConversationBranch.js +125 -0
  29. package/dist/hooks/useFontLoader.d.ts +23 -0
  30. package/dist/hooks/useFontLoader.js +153 -0
  31. package/dist/hooks/useFullscreenText.d.ts +17 -0
  32. package/dist/hooks/useFullscreenText.js +120 -0
  33. package/dist/hooks/usePlayerLogic.d.ts +10 -3
  34. package/dist/hooks/usePlayerLogic.js +115 -18
  35. package/dist/hooks/usePluginEvents.d.ts +4 -1
  36. package/dist/hooks/usePluginEvents.js +16 -11
  37. package/dist/hooks/usePreloadImages.js +27 -7
  38. package/dist/hooks/useSoundPlayer.d.ts +15 -0
  39. package/dist/hooks/useSoundPlayer.js +209 -0
  40. package/dist/hooks/useTypewriter.d.ts +6 -2
  41. package/dist/hooks/useTypewriter.js +42 -6
  42. package/dist/hooks/useVoice.js +7 -1
  43. package/dist/index.d.ts +6 -3
  44. package/dist/index.js +3 -1
  45. package/dist/plugin/PluginManager.d.ts +66 -2
  46. package/dist/plugin/PluginManager.js +352 -79
  47. package/dist/sdk.d.ts +184 -22
  48. package/dist/sdk.js +27 -2
  49. package/dist/types.d.ts +303 -4
  50. package/dist/utils/branchBlockConverter.d.ts +2 -0
  51. package/dist/utils/branchBlockConverter.js +21 -0
  52. package/dist/utils/branchNavigator.d.ts +14 -0
  53. package/dist/utils/branchNavigator.js +55 -0
  54. package/dist/utils/facePositionCalculator.js +0 -1
  55. package/dist/utils/variableManager.d.ts +18 -0
  56. package/dist/utils/variableManager.js +159 -0
  57. package/package.json +1 -1
  58. package/dist/components/ConversationLogUI.d.ts +0 -2
  59. package/dist/components/ConversationLogUI.js +0 -115
  60. package/dist/hooks/useConversationLog.d.ts +0 -14
  61. package/dist/hooks/useConversationLog.js +0 -82
  62. package/dist/hooks/useUIVisibility.d.ts +0 -9
  63. package/dist/hooks/useUIVisibility.js +0 -19
  64. package/dist/plugin/luna-react.d.ts +0 -41
  65. package/dist/plugin/luna-react.js +0 -99
package/dist/sdk.d.ts CHANGED
@@ -1,9 +1,38 @@
1
1
  import React from "react";
2
- import type { ActionNode, BacklogEntry, Character, EntityState, ScenarioBlock } from "./types";
2
+ import type { BackgroundData, BacklogEntry, BranchChoiceHistory, Character, ConversationBranchState, DisplayedCharacter, EntityState, ScenarioBlock, ScenarioBlockType, WorkFont } from "./types";
3
+ /**
4
+ * ブロックオプションの定義
5
+ * プラグインがシナリオブロックに追加できるカスタムオプションを定義
6
+ */
7
+ export interface BlockOptionDefinition {
8
+ /** オプションのキー(プラグイン固有のプレフィックス推奨: "myplugin_option_name") */
9
+ key: string;
10
+ /** 表示名 */
11
+ name: string;
12
+ /** 対象のブロックタイプ(nullまたは未指定で全タイプ対象) */
13
+ targetBlockTypes?: ScenarioBlockType[] | null;
14
+ /** オプションの入力タイプ */
15
+ type: "select" | "text" | "number" | "boolean";
16
+ /** select型の場合の選択肢 */
17
+ options?: BlockOptionChoice[];
18
+ /** select以外の場合のデフォルト値 */
19
+ default?: string | number | boolean;
20
+ }
21
+ /**
22
+ * select型オプションの選択肢
23
+ */
24
+ export interface BlockOptionChoice {
25
+ value: string;
26
+ label: string;
27
+ /** デフォルト選択かどうか */
28
+ isDefault?: boolean;
29
+ }
3
30
  export interface LunaPlugin {
4
31
  name: string;
5
32
  version: string;
6
33
  description: string;
34
+ /** プラグインが定義するブロックオプション */
35
+ blockOptions?: BlockOptionDefinition[];
7
36
  /** プラグインインストール時の処理(オプション) */
8
37
  onInstall?(api: PluginInstallAPI): Promise<void>;
9
38
  /** プラグインアンインストール時の処理(オプション) */
@@ -24,12 +53,12 @@ export interface ScenarioPlaybackData {
24
53
  scenarioName: string;
25
54
  /** 現在のブロック */
26
55
  currentBlock: ScenarioBlock | null;
27
- /** 表示中のテキスト */
28
- displayText?: string;
56
+ /** 表示中のテキスト(改行は自動的に<br />に変換されます) */
57
+ displayText?: string | React.ReactNode;
29
58
  /** テキストアニメーション中かどうか */
30
59
  isTyping?: boolean;
31
60
  /** 表示中のキャラクター */
32
- displayedCharacters?: any[];
61
+ displayedCharacters?: DisplayedCharacter[];
33
62
  }
34
63
  /**
35
64
  * バックログデータ
@@ -48,7 +77,7 @@ export interface BacklogData {
48
77
  * プレイヤー設定データ
49
78
  */
50
79
  export interface PlayerSettingsData extends PlayerSettings {
51
- /** テキスト速度 (1-10) */
80
+ /** テキスト速度 (ミリ秒/文字) */
52
81
  textSpeed: number;
53
82
  /** 自動再生速度 (秒) */
54
83
  autoPlaySpeed: number;
@@ -73,6 +102,17 @@ export interface PluginAssetsData {
73
102
  */
74
103
  getAssetUrl: (pluginName: string, filename: string) => string;
75
104
  }
105
+ /**
106
+ * フォントデータ
107
+ */
108
+ export interface FontsData {
109
+ /** 利用可能なフォント一覧 */
110
+ fonts: WorkFont[];
111
+ /** 選択されているフォントファミリー */
112
+ selectedFontFamily: string | undefined;
113
+ /** フォントが読み込み完了しているかどうか */
114
+ isLoaded: boolean;
115
+ }
76
116
  /**
77
117
  * 全データコンテキスト
78
118
  */
@@ -85,6 +125,16 @@ export interface DataContext {
85
125
  settings: PlayerSettingsData;
86
126
  /** プラグインアセット */
87
127
  pluginAssets: PluginAssetsData;
128
+ /** 会話分岐データ */
129
+ branchData?: ConversationBranchState;
130
+ /** 分岐履歴 */
131
+ branchHistory?: BranchChoiceHistory[];
132
+ /** 現在の背景データ(単一、後方互換性用) */
133
+ background?: BackgroundData | null;
134
+ /** 現在の背景データ(複数、背景グループ対応) */
135
+ backgrounds?: BackgroundData[];
136
+ /** フォント設定 */
137
+ fonts?: FontsData;
88
138
  }
89
139
  /**
90
140
  * データ購読コールバック
@@ -168,6 +218,68 @@ export interface DataAPI {
168
218
  * @returns unsubscribe関数
169
219
  */
170
220
  watch<K extends keyof DataContext, P extends keyof DataContext[K]>(key: K, property: P, callback: DataSubscriber<DataContext[K][P]>): () => void;
221
+ /**
222
+ * プレイヤー設定を更新
223
+ * @param settings - 更新する設定値(部分更新可能)
224
+ */
225
+ updateSettings(settings: Partial<PlayerSettingsData>): void;
226
+ /**
227
+ * BGM音量を設定
228
+ * @param volume - 音量(0-1の範囲)
229
+ */
230
+ setBgmVolume(volume: number): void;
231
+ /**
232
+ * SE音量を設定
233
+ * @param volume - 音量(0-1の範囲)
234
+ */
235
+ setSeVolume(volume: number): void;
236
+ /**
237
+ * ボイス音量を設定
238
+ * @param volume - 音量(0-1の範囲)
239
+ */
240
+ setVoiceVolume(volume: number): void;
241
+ /**
242
+ * 全カテゴリの音量を一括設定
243
+ * @param volumes - カテゴリ別音量設定
244
+ */
245
+ setVolumes(volumes: {
246
+ bgm?: number;
247
+ se?: number;
248
+ voice?: number;
249
+ }): void;
250
+ /**
251
+ * 現在のブロックのオプション値を型安全に取得
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * // プラグイン側で型を定義
256
+ * type MyBlockOptions = {
257
+ * ultemist_bubble_style: "normal" | "monologue" | "star";
258
+ * ultemist_effect_type: "none" | "shake" | "fade";
259
+ * };
260
+ *
261
+ * // コンポーネントで使用
262
+ * const bubbleStyle = dataAPI.getBlockOption<MyBlockOptions, "ultemist_bubble_style">("ultemist_bubble_style");
263
+ * // 型: "normal" | "monologue" | "star" | undefined
264
+ *
265
+ * // または簡易版(キーのみ指定)
266
+ * const bubbleStyle = dataAPI.getBlockOption<MyBlockOptions>("ultemist_bubble_style");
267
+ * ```
268
+ *
269
+ * @param key - オプションのキー
270
+ * @returns オプションの値、または未設定の場合undefined
271
+ */
272
+ getBlockOption<T extends Record<string, unknown>, K extends keyof T = keyof T>(key: K): T[K] | undefined;
273
+ }
274
+ /**
275
+ * ブロックオプション登録API
276
+ */
277
+ export interface BlockOptionsAPI {
278
+ /**
279
+ * ブロックオプションを登録
280
+ * @param definition - ブロックオプションの定義
281
+ */
282
+ register(definition: BlockOptionDefinition): void;
171
283
  }
172
284
  export interface PluginAPI {
173
285
  style: StyleAPI;
@@ -179,9 +291,18 @@ export interface PluginAPI {
179
291
  components: ComponentAPI;
180
292
  data: DataAPI;
181
293
  ui: UIAPI;
294
+ blockOptions: BlockOptionsAPI;
182
295
  React: typeof React;
183
296
  setNextCharacterSpeakHandler(callback: (context: CharacterSpeakContext) => void): void;
184
297
  getConfig?(): unknown;
298
+ selectChoice?(choiceId: string): void;
299
+ getBranchState?(): ConversationBranchState | null;
300
+ /**
301
+ * ビルトインのクリック音を上書き
302
+ * プラグインが独自のクリック音を再生する場合に呼び出す
303
+ * onBlockChangeフック内で呼び出すことで、そのブロック遷移でのビルトインクリック音を抑制する
304
+ */
305
+ overrideClickSound?(): void;
185
306
  }
186
307
  export interface StyleAPI {
187
308
  elements: {
@@ -191,6 +312,8 @@ export interface StyleAPI {
191
312
  gameScreen: StyleElement;
192
313
  characterSprite: StyleElement;
193
314
  background: StyleElement;
315
+ fullscreenTextOverlay: StyleElement;
316
+ fullscreenTextContainer: StyleElement;
194
317
  };
195
318
  injectCSS(css: string): void;
196
319
  enableTailwind(): void;
@@ -225,7 +348,7 @@ export interface AttributeDefinition {
225
348
  name: string;
226
349
  type: "text" | "textarea" | "number" | "select" | "entity";
227
350
  label: string;
228
- default?: any;
351
+ default?: string | number | boolean;
229
352
  required?: boolean;
230
353
  placeholder?: string;
231
354
  min?: number;
@@ -272,7 +395,7 @@ export interface ObjectAttributeDefinition {
272
395
  displayName: string;
273
396
  dataType: "string" | "number" | "boolean" | "text";
274
397
  isRequired: boolean;
275
- defaultValue?: any;
398
+ defaultValue?: string | number | boolean;
276
399
  sortOrder?: number;
277
400
  }
278
401
  /** 簡易的なオブジェクトタイプ情報 */
@@ -294,16 +417,23 @@ export interface PluginHooks {
294
417
  onScenarioReady(callback: (context: ScenarioReadyContext) => void): void;
295
418
  onBlockChange(callback: (context: BlockChangeContext) => void): void;
296
419
  onCharacterEnter(callback: (context: CharacterContext) => void): void;
297
- onCharacterExit(callback: (context: CharacterContext) => void): void;
298
420
  onDialogueShow(callback: (context: DialogueContext) => void): void;
299
421
  onActionExecute(callback: (context: ActionExecutionContext) => void): void;
300
422
  onScenarioStart(callback: (context: ScenarioContext) => void): void;
301
423
  onScenarioEnd(callback: (context: ScenarioContext) => void): void;
424
+ onBranchStart?(callback: (context: BranchStartContext) => void): void;
425
+ onChoiceSelected?(callback: (context: ChoiceSelectedContext) => void): void;
426
+ onBranchEnd?(callback: () => void): void;
427
+ onBranchBlockChange?(callback: (context: BranchBlockChangeContext) => void): void;
302
428
  }
429
+ /** 遷移の種類 */
430
+ export type TransitionSource = "click" | "auto" | "time_wait";
303
431
  export interface BlockChangeContext {
304
432
  previousBlock?: ScenarioBlock;
305
433
  currentBlock: ScenarioBlock;
306
434
  blockIndex: number;
435
+ /** 遷移の種類(クリック、自動、時間待ち) */
436
+ transitionSource?: TransitionSource;
307
437
  }
308
438
  export interface CharacterContext {
309
439
  character: Character;
@@ -358,6 +488,22 @@ export interface ScenarioReadyContext {
358
488
  currentBlockIndex: number;
359
489
  currentBlock: ScenarioBlock;
360
490
  }
491
+ export interface BranchStartContext {
492
+ branchBlockId: string;
493
+ choices: Array<{
494
+ id: string;
495
+ text: string;
496
+ order: number;
497
+ }>;
498
+ }
499
+ export interface ChoiceSelectedContext {
500
+ choiceId: string;
501
+ choiceText: string;
502
+ }
503
+ export interface BranchBlockChangeContext {
504
+ blockIndex: number;
505
+ block: ScenarioBlock;
506
+ }
361
507
  export interface EffectAPI {
362
508
  show(options: EffectOptions): string;
363
509
  hide(effectId: string): void;
@@ -372,8 +518,8 @@ export interface EffectOptions {
372
518
  animation?: "fade" | "slide" | "bounce" | "none";
373
519
  }
374
520
  export interface StorageAPI {
375
- get<T = any>(key: string): T | null;
376
- set<T = any>(key: string, value: T): void;
521
+ get<T = unknown>(key: string): T | null;
522
+ set<T = unknown>(key: string, value: T): void;
377
523
  remove(key: string): void;
378
524
  clear(): void;
379
525
  }
@@ -382,6 +528,12 @@ export interface AssetAPI {
382
528
  preload(filenames: string[]): Promise<void>;
383
529
  playSound(filename: string, options?: SoundOptions): void;
384
530
  stopSound(filename: string): void;
531
+ /**
532
+ * 作品のサウンドをIDで再生
533
+ * @param soundId - 作品に登録されたサウンドのID
534
+ * @param options - 再生オプション(音量、ループなど)
535
+ */
536
+ playWorkSound(soundId: string, options?: SoundOptions): void;
385
537
  }
386
538
  export interface SoundOptions {
387
539
  volume?: number;
@@ -398,7 +550,10 @@ export declare enum ComponentType {
398
550
  LoadMenu = "LoadMenu",
399
551
  SettingsMenu = "SettingsMenu",
400
552
  GameMenu = "GameMenu",
401
- Config = "Config"
553
+ Config = "Config",
554
+ ConversationBranch = "ConversationBranch",
555
+ Background = "Background",
556
+ FullscreenTextBox = "FullscreenTextBox"
402
557
  }
403
558
  /**
404
559
  * コンポーネント登録API
@@ -407,24 +562,17 @@ export declare enum ComponentType {
407
562
  export interface ComponentAPI {
408
563
  registerComponent(type: ComponentType, component: React.ComponentType): void;
409
564
  }
410
- export type { BacklogEntry };
411
- export interface DisplayedCharacter {
412
- objectId: string;
413
- stateId?: string;
414
- position?: {
415
- x: number;
416
- y: number;
417
- };
418
- scale?: number;
419
- }
565
+ export type { BacklogEntry, DisplayedCharacter } from "./types";
420
566
  export interface PlayerSettings {
421
567
  textSpeed: number;
422
568
  autoPlaySpeed: number;
423
569
  bgmVolume: number;
424
570
  seVolume: number;
425
571
  voiceVolume: number;
572
+ /** 選択されたフォントファミリー */
573
+ selectedFontFamily?: string;
426
574
  }
427
- export type { ScenarioBlock, Character, EntityState, ActionNode };
575
+ export type { ActionNode, BackgroundData, BackgroundGroupData, BackgroundGroupItem, BackgroundMediaType, BlockOptions, Character, EntityState, FontType, ScenarioBlock, ScenarioBlockType, WorkFont, } from "./types";
428
576
  export declare function definePlugin(plugin: LunaPlugin): LunaPlugin;
429
577
  export declare function defineComponent(type: ComponentType, component: React.ComponentType): {
430
578
  type: ComponentType;
@@ -510,3 +658,17 @@ export declare function useScreenSizeAtom(): [
510
658
  ];
511
659
  export { OverlayUI } from "./components/OverlayUI";
512
660
  export { aspectRatio, BasisHeight, BasisWidth } from "./constants/screen-size";
661
+ /**
662
+ * テキスト内の改行文字(\n)を<br />タグに変換してReact要素を返す
663
+ * プラグインがDialogueBoxなどのコンポーネントでテキストを表示する際に使用
664
+ *
665
+ * @param text 表示するテキスト(改行文字を含む可能性がある)
666
+ * @returns 改行が<br />タグに変換されたReact要素
667
+ *
668
+ * @example
669
+ * ```tsx
670
+ * const content = dataAPI.get("playback", "displayText") || "";
671
+ * return <div>{renderTextWithLineBreaks(content)}</div>;
672
+ * ```
673
+ */
674
+ export declare function renderTextWithLineBreaks(text: string): React.ReactElement | string;
package/dist/sdk.js CHANGED
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
  // SDK exports for plugin development
3
2
  // This file contains all types and utilities needed for plugin development
4
3
  import React from "react";
@@ -15,6 +14,9 @@ export var ComponentType;
15
14
  ComponentType["SettingsMenu"] = "SettingsMenu";
16
15
  ComponentType["GameMenu"] = "GameMenu";
17
16
  ComponentType["Config"] = "Config";
17
+ ComponentType["ConversationBranch"] = "ConversationBranch";
18
+ ComponentType["Background"] = "Background";
19
+ ComponentType["FullscreenTextBox"] = "FullscreenTextBox";
18
20
  })(ComponentType || (ComponentType = {}));
19
21
  // Component types are already exported as part of the interfaces above
20
22
  // Plugin utility function
@@ -47,7 +49,6 @@ export function calculateFaceRelativePosition(options) {
47
49
  case "chin":
48
50
  baseY = facePosition.y + facePosition.height * 0.3;
49
51
  break;
50
- case "center":
51
52
  default:
52
53
  // Use face center as is
53
54
  break;
@@ -62,3 +63,27 @@ export { React };
62
63
  export { OverlayUI } from "./components/OverlayUI";
63
64
  // Screen size constants
64
65
  export { aspectRatio, BasisHeight, BasisWidth } from "./constants/screen-size";
66
+ // ============================================================================
67
+ // Text Utilities - テキスト処理ユーティリティ
68
+ // ============================================================================
69
+ /**
70
+ * テキスト内の改行文字(\n)を<br />タグに変換してReact要素を返す
71
+ * プラグインがDialogueBoxなどのコンポーネントでテキストを表示する際に使用
72
+ *
73
+ * @param text 表示するテキスト(改行文字を含む可能性がある)
74
+ * @returns 改行が<br />タグに変換されたReact要素
75
+ *
76
+ * @example
77
+ * ```tsx
78
+ * const content = dataAPI.get("playback", "displayText") || "";
79
+ * return <div>{renderTextWithLineBreaks(content)}</div>;
80
+ * ```
81
+ */
82
+ export function renderTextWithLineBreaks(text) {
83
+ if (!text.includes("\n")) {
84
+ return text;
85
+ }
86
+ return React.createElement(React.Fragment, null, text
87
+ .split("\n")
88
+ .map((line, index, array) => React.createElement("span", { key: index }, line, index < array.length - 1 && React.createElement("br"))));
89
+ }