@luna-editor/engine 0.2.0 → 0.3.1

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 (74) hide show
  1. package/dist/Player.d.ts +1 -1
  2. package/dist/Player.js +676 -95
  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 +220 -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 +9 -2
  17. package/dist/components/GameScreen.js +396 -80
  18. package/dist/components/OverlayUI.d.ts +2 -3
  19. package/dist/components/OverlayUI.js +3 -14
  20. package/dist/components/PluginComponentProvider.d.ts +3 -3
  21. package/dist/components/PluginComponentProvider.js +22 -4
  22. package/dist/components/TimeWaitIndicator.d.ts +15 -0
  23. package/dist/components/TimeWaitIndicator.js +17 -0
  24. package/dist/contexts/AudioContext.d.ts +1 -0
  25. package/dist/contexts/AudioContext.js +1 -0
  26. package/dist/contexts/DataContext.d.ts +3 -1
  27. package/dist/contexts/DataContext.js +104 -17
  28. package/dist/contexts/PlaybackTextContext.d.ts +32 -0
  29. package/dist/contexts/PlaybackTextContext.js +29 -0
  30. package/dist/data-api-types.d.ts +251 -0
  31. package/dist/data-api-types.js +6 -0
  32. package/dist/emotion-effect-types.d.ts +86 -0
  33. package/dist/emotion-effect-types.js +6 -0
  34. package/dist/hooks/useBacklog.js +3 -1
  35. package/dist/hooks/useConversationBranch.d.ts +16 -0
  36. package/dist/hooks/useConversationBranch.js +125 -0
  37. package/dist/hooks/useFontLoader.d.ts +30 -0
  38. package/dist/hooks/useFontLoader.js +192 -0
  39. package/dist/hooks/useFullscreenText.d.ts +17 -0
  40. package/dist/hooks/useFullscreenText.js +120 -0
  41. package/dist/hooks/useImagePreloader.d.ts +5 -0
  42. package/dist/hooks/useImagePreloader.js +53 -0
  43. package/dist/hooks/usePlayerLogic.d.ts +10 -3
  44. package/dist/hooks/usePlayerLogic.js +115 -18
  45. package/dist/hooks/usePluginAPI.js +1 -1
  46. package/dist/hooks/usePluginEvents.d.ts +4 -1
  47. package/dist/hooks/usePluginEvents.js +16 -11
  48. package/dist/hooks/usePreloadImages.js +27 -7
  49. package/dist/hooks/useSoundPlayer.d.ts +15 -0
  50. package/dist/hooks/useSoundPlayer.js +209 -0
  51. package/dist/hooks/useTypewriter.d.ts +6 -2
  52. package/dist/hooks/useTypewriter.js +42 -6
  53. package/dist/hooks/useVoice.js +4 -1
  54. package/dist/index.d.ts +5 -3
  55. package/dist/index.js +3 -1
  56. package/dist/plugin/PluginManager.d.ts +86 -5
  57. package/dist/plugin/PluginManager.js +427 -94
  58. package/dist/sdk.d.ts +133 -162
  59. package/dist/sdk.js +39 -4
  60. package/dist/types.d.ts +300 -4
  61. package/dist/utils/branchBlockConverter.d.ts +2 -0
  62. package/dist/utils/branchBlockConverter.js +21 -0
  63. package/dist/utils/branchNavigator.d.ts +14 -0
  64. package/dist/utils/branchNavigator.js +55 -0
  65. package/dist/utils/facePositionCalculator.js +0 -1
  66. package/dist/utils/variableManager.d.ts +18 -0
  67. package/dist/utils/variableManager.js +159 -0
  68. package/package.json +6 -6
  69. package/dist/components/ConversationLogUI.d.ts +0 -2
  70. package/dist/components/ConversationLogUI.js +0 -115
  71. package/dist/hooks/useConversationLog.d.ts +0 -14
  72. package/dist/hooks/useConversationLog.js +0 -82
  73. package/dist/hooks/useUIVisibility.d.ts +0 -9
  74. package/dist/hooks/useUIVisibility.js +0 -19
package/dist/sdk.d.ts CHANGED
@@ -1,120 +1,49 @@
1
1
  import React from "react";
2
- import type { ActionNode, BacklogEntry, Character, EntityState, ScenarioBlock } from "./types";
2
+ import { useDataAPI } from "./contexts/DataContext";
3
+ import type { DataAPI, DataContext, DataSubscriber } from "./data-api-types";
4
+ import type { FacePosition } from "./emotion-effect-types";
5
+ import type { Character, ConversationBranchState, EntityState, ScenarioBlock, ScenarioBlockType } from "./types";
6
+ /**
7
+ * ブロックオプションの定義
8
+ * プラグインがシナリオブロックに追加できるカスタムオプションを定義
9
+ */
10
+ export interface BlockOptionDefinition {
11
+ /** オプションのキー(プラグイン固有のプレフィックス推奨: "myplugin_option_name") */
12
+ key: string;
13
+ /** 表示名 */
14
+ name: string;
15
+ /** 対象のブロックタイプ(nullまたは未指定で全タイプ対象) */
16
+ targetBlockTypes?: ScenarioBlockType[] | null;
17
+ /** オプションの入力タイプ */
18
+ type: "select" | "text" | "number" | "boolean";
19
+ /** select型の場合の選択肢 */
20
+ options?: BlockOptionChoice[];
21
+ /** select以外の場合のデフォルト値 */
22
+ default?: string | number | boolean;
23
+ }
24
+ /**
25
+ * select型オプションの選択肢
26
+ */
27
+ export interface BlockOptionChoice {
28
+ value: string;
29
+ label: string;
30
+ /** デフォルト選択かどうか */
31
+ isDefault?: boolean;
32
+ }
3
33
  export interface LunaPlugin {
4
34
  name: string;
5
35
  version: string;
6
36
  description: string;
37
+ /** プラグインが定義するブロックオプション */
38
+ blockOptions?: BlockOptionDefinition[];
7
39
  /** プラグインインストール時の処理(オプション) */
8
40
  onInstall?(api: PluginInstallAPI): Promise<void>;
9
41
  /** プラグインアンインストール時の処理(オプション) */
10
42
  onUninstall?(api: PluginInstallAPI): Promise<void>;
11
43
  setup(api: PluginAPI): void;
12
44
  }
13
- /**
14
- * シナリオ再生の動的データ
15
- */
16
- export interface ScenarioPlaybackData {
17
- /** 現在のブロックインデックス(0始まり) */
18
- currentBlockIndex: number;
19
- /** 総ブロック数 */
20
- totalBlocks: number;
21
- /** 現在のシナリオID */
22
- scenarioId: string;
23
- /** シナリオ名 */
24
- scenarioName: string;
25
- /** 現在のブロック */
26
- currentBlock: ScenarioBlock | null;
27
- /** 表示中のテキスト */
28
- displayText?: string;
29
- /** テキストアニメーション中かどうか */
30
- isTyping?: boolean;
31
- /** 表示中のキャラクター */
32
- displayedCharacters?: any[];
33
- }
34
- /**
35
- * バックログデータ
36
- */
37
- export interface BacklogData {
38
- /** バックログエントリ */
39
- entries: BacklogEntry[];
40
- /** 総エントリ数 */
41
- totalEntries: number;
42
- /** ログエントリを追加 */
43
- addLogEntry?: (entry: BacklogEntry) => void;
44
- /** ログをクリア */
45
- clearLogs?: () => void;
46
- }
47
- /**
48
- * プレイヤー設定データ
49
- */
50
- export interface PlayerSettingsData extends PlayerSettings {
51
- /** テキスト速度 (ミリ秒/文字) */
52
- textSpeed: number;
53
- /** 自動再生速度 (秒) */
54
- autoPlaySpeed: number;
55
- /** BGM音量 (0-1) */
56
- bgmVolume: number;
57
- /** SE音量 (0-1) */
58
- seVolume: number;
59
- /** ボイス音量 (0-1) */
60
- voiceVolume: number;
61
- /** スキップ設定 */
62
- skipMode?: "all" | "unread" | "none";
63
- }
64
- /**
65
- * プラグインアセットデータ
66
- */
67
- export interface PluginAssetsData {
68
- /**
69
- * プラグインのアセットURLを取得
70
- * @param pluginName - プラグインのパッケージ名
71
- * @param filename - アセットファイル名
72
- * @returns アセットのURL
73
- */
74
- getAssetUrl: (pluginName: string, filename: string) => string;
75
- }
76
- /**
77
- * 全データコンテキスト
78
- */
79
- export interface DataContext {
80
- /** シナリオ再生情報 */
81
- playback: ScenarioPlaybackData;
82
- /** バックログ情報 */
83
- backlog: BacklogData;
84
- /** プレイヤー設定 */
85
- settings: PlayerSettingsData;
86
- /** プラグインアセット */
87
- pluginAssets: PluginAssetsData;
88
- }
89
- /**
90
- * データ購読コールバック
91
- */
92
- export type DataSubscriber<T> = (data: T) => void;
93
- /**
94
- * データAPI - プラグインからのデータアクセスインターフェース
95
- *
96
- * @example Pull型(現在値の取得)
97
- * ```typescript
98
- * const blockIndex = api.data.get('playback', 'currentBlockIndex');
99
- * const playback = api.data.get('playback');
100
- * ```
101
- *
102
- * @example Push型(変更の監視)
103
- * ```typescript
104
- * const unsubscribe = api.data.subscribe('playback', (data) => {
105
- * console.log('Playback updated:', data);
106
- * });
107
- * // cleanup
108
- * unsubscribe();
109
- * ```
110
- *
111
- * @example プロパティ単位での監視
112
- * ```typescript
113
- * api.data.watch('playback', 'currentBlockIndex', (index) => {
114
- * console.log('Block changed to:', index);
115
- * });
116
- * ```
117
- */
45
+ export type { BacklogData, FontsData, PlayerSettingsData, PluginAssetsData, ScenarioPlaybackData, } from "./data-api-types";
46
+ export type { DataAPI, DataContext, DataSubscriber };
118
47
  /**
119
48
  * UI表示管理API - プラグインUIコンポーネントの表示/非表示を制御
120
49
  */
@@ -141,38 +70,15 @@ export interface UIAPI {
141
70
  */
142
71
  isVisible(type: ComponentType): boolean;
143
72
  }
144
- export interface DataAPI {
145
- /**
146
- * データの現在値を取得(Pull型)
147
- * @param key - データカテゴリ
148
- */
149
- get<K extends keyof DataContext>(key: K): DataContext[K];
150
- /**
151
- * データの特定プロパティを取得(Pull型)
152
- * @param key - データカテゴリ
153
- * @param property - プロパティ名
154
- */
155
- get<K extends keyof DataContext, P extends keyof DataContext[K]>(key: K, property: P): DataContext[K][P];
156
- /**
157
- * データカテゴリ全体の変更を監視(Push型)
158
- * @param key - データカテゴリ
159
- * @param callback - 変更時のコールバック
160
- * @returns unsubscribe関数
161
- */
162
- subscribe<K extends keyof DataContext>(key: K, callback: DataSubscriber<DataContext[K]>): () => void;
163
- /**
164
- * 特定プロパティの変更を監視(Push型)
165
- * @param key - データカテゴリ
166
- * @param property - プロパティ名
167
- * @param callback - 変更時のコールバック
168
- * @returns unsubscribe関数
169
- */
170
- watch<K extends keyof DataContext, P extends keyof DataContext[K]>(key: K, property: P, callback: DataSubscriber<DataContext[K][P]>): () => void;
73
+ /**
74
+ * ブロックオプション登録API
75
+ */
76
+ export interface BlockOptionsAPI {
171
77
  /**
172
- * プレイヤー設定を更新
173
- * @param settings - 更新する設定値(部分更新可能)
78
+ * ブロックオプションを登録
79
+ * @param definition - ブロックオプションの定義
174
80
  */
175
- updateSettings(settings: Partial<PlayerSettingsData>): void;
81
+ register(definition: BlockOptionDefinition): void;
176
82
  }
177
83
  export interface PluginAPI {
178
84
  style: StyleAPI;
@@ -184,9 +90,18 @@ export interface PluginAPI {
184
90
  components: ComponentAPI;
185
91
  data: DataAPI;
186
92
  ui: UIAPI;
93
+ blockOptions: BlockOptionsAPI;
187
94
  React: typeof React;
188
95
  setNextCharacterSpeakHandler(callback: (context: CharacterSpeakContext) => void): void;
189
96
  getConfig?(): unknown;
97
+ selectChoice?(choiceId: string): void;
98
+ getBranchState?(): ConversationBranchState | null;
99
+ /**
100
+ * ビルトインのクリック音を上書き
101
+ * プラグインが独自のクリック音を再生する場合に呼び出す
102
+ * onBlockChangeフック内で呼び出すことで、そのブロック遷移でのビルトインクリック音を抑制する
103
+ */
104
+ overrideClickSound?(): void;
190
105
  }
191
106
  export interface StyleAPI {
192
107
  elements: {
@@ -196,6 +111,8 @@ export interface StyleAPI {
196
111
  gameScreen: StyleElement;
197
112
  characterSprite: StyleElement;
198
113
  background: StyleElement;
114
+ fullscreenTextOverlay: StyleElement;
115
+ fullscreenTextContainer: StyleElement;
199
116
  };
200
117
  injectCSS(css: string): void;
201
118
  enableTailwind(): void;
@@ -230,7 +147,7 @@ export interface AttributeDefinition {
230
147
  name: string;
231
148
  type: "text" | "textarea" | "number" | "select" | "entity";
232
149
  label: string;
233
- default?: any;
150
+ default?: string | number | boolean;
234
151
  required?: boolean;
235
152
  placeholder?: string;
236
153
  min?: number;
@@ -277,7 +194,7 @@ export interface ObjectAttributeDefinition {
277
194
  displayName: string;
278
195
  dataType: "string" | "number" | "boolean" | "text";
279
196
  isRequired: boolean;
280
- defaultValue?: any;
197
+ defaultValue?: string | number | boolean;
281
198
  sortOrder?: number;
282
199
  }
283
200
  /** 簡易的なオブジェクトタイプ情報 */
@@ -299,16 +216,23 @@ export interface PluginHooks {
299
216
  onScenarioReady(callback: (context: ScenarioReadyContext) => void): void;
300
217
  onBlockChange(callback: (context: BlockChangeContext) => void): void;
301
218
  onCharacterEnter(callback: (context: CharacterContext) => void): void;
302
- onCharacterExit(callback: (context: CharacterContext) => void): void;
303
219
  onDialogueShow(callback: (context: DialogueContext) => void): void;
304
220
  onActionExecute(callback: (context: ActionExecutionContext) => void): void;
305
221
  onScenarioStart(callback: (context: ScenarioContext) => void): void;
306
222
  onScenarioEnd(callback: (context: ScenarioContext) => void): void;
223
+ onBranchStart?(callback: (context: BranchStartContext) => void): void;
224
+ onChoiceSelected?(callback: (context: ChoiceSelectedContext) => void): void;
225
+ onBranchEnd?(callback: () => void): void;
226
+ onBranchBlockChange?(callback: (context: BranchBlockChangeContext) => void): void;
307
227
  }
228
+ /** 遷移の種類 */
229
+ export type TransitionSource = "click" | "auto" | "time_wait";
308
230
  export interface BlockChangeContext {
309
231
  previousBlock?: ScenarioBlock;
310
232
  currentBlock: ScenarioBlock;
311
233
  blockIndex: number;
234
+ /** 遷移の種類(クリック、自動、時間待ち) */
235
+ transitionSource?: TransitionSource;
312
236
  }
313
237
  export interface CharacterContext {
314
238
  character: Character;
@@ -341,12 +265,15 @@ export interface CharacterSpeakContext {
341
265
  id?: string;
342
266
  name?: string;
343
267
  };
344
- facePosition?: {
345
- x: number;
346
- y: number;
347
- width: number;
348
- height: number;
349
- };
268
+ /**
269
+ * 【機能概要】: 顔位置情報(感情エフェクト用)
270
+ * 【実装方針】: インライン定義からFacePosition型に変更し、型の再利用性を向上
271
+ * 【テスト対応】: TC-009を通すための実装
272
+ * 🔵 信頼性レベル: note.md(行301-308)の推奨事項に基づく
273
+ *
274
+ * @see FacePosition - 完全な型定義は emotion-effect-types.ts を参照
275
+ */
276
+ facePosition?: FacePosition;
350
277
  }
351
278
  export interface ScenarioContext {
352
279
  scenario: {
@@ -363,6 +290,22 @@ export interface ScenarioReadyContext {
363
290
  currentBlockIndex: number;
364
291
  currentBlock: ScenarioBlock;
365
292
  }
293
+ export interface BranchStartContext {
294
+ branchBlockId: string;
295
+ choices: Array<{
296
+ id: string;
297
+ text: string;
298
+ order: number;
299
+ }>;
300
+ }
301
+ export interface ChoiceSelectedContext {
302
+ choiceId: string;
303
+ choiceText: string;
304
+ }
305
+ export interface BranchBlockChangeContext {
306
+ blockIndex: number;
307
+ block: ScenarioBlock;
308
+ }
366
309
  export interface EffectAPI {
367
310
  show(options: EffectOptions): string;
368
311
  hide(effectId: string): void;
@@ -377,8 +320,8 @@ export interface EffectOptions {
377
320
  animation?: "fade" | "slide" | "bounce" | "none";
378
321
  }
379
322
  export interface StorageAPI {
380
- get<T = any>(key: string): T | null;
381
- set<T = any>(key: string, value: T): void;
323
+ get<T = unknown>(key: string): T | null;
324
+ set<T = unknown>(key: string, value: T): void;
382
325
  remove(key: string): void;
383
326
  clear(): void;
384
327
  }
@@ -387,6 +330,12 @@ export interface AssetAPI {
387
330
  preload(filenames: string[]): Promise<void>;
388
331
  playSound(filename: string, options?: SoundOptions): void;
389
332
  stopSound(filename: string): void;
333
+ /**
334
+ * 作品のサウンドをIDで再生
335
+ * @param soundId - 作品に登録されたサウンドのID
336
+ * @param options - 再生オプション(音量、ループなど)
337
+ */
338
+ playWorkSound(soundId: string, options?: SoundOptions): void;
390
339
  }
391
340
  export interface SoundOptions {
392
341
  volume?: number;
@@ -403,33 +352,41 @@ export declare enum ComponentType {
403
352
  LoadMenu = "LoadMenu",
404
353
  SettingsMenu = "SettingsMenu",
405
354
  GameMenu = "GameMenu",
406
- Config = "Config"
355
+ Config = "Config",
356
+ ConversationBranch = "ConversationBranch",
357
+ Background = "Background",
358
+ FullscreenTextBox = "FullscreenTextBox",
359
+ /**
360
+ * 【機能概要】: 感情エフェクトコンポーネント登録用の型定義
361
+ * 【実装方針】: 既存のComponentType値と同じパターン(PascalCase、文字列リテラル型)で追加
362
+ * 【テスト対応】: TC-001, TC-003, TC-004, TC-012を通すための実装
363
+ * 🔵 信頼性レベル: タスクノート、要件定義書、設計文書に明確に定義されている
364
+ *
365
+ * @see EmotionEffectState - 関連する型定義は emotion-effect-types.ts を参照
366
+ */
367
+ EmotionEffect = "EmotionEffect"
407
368
  }
408
369
  /**
409
370
  * コンポーネント登録API
410
- * すべてのデータはDataContext経由で提供されるため、propsは使用しません
371
+ * DataAPIはPluginComponentProviderから自動的にpropsとして渡されます
411
372
  */
412
373
  export interface ComponentAPI {
413
- registerComponent(type: ComponentType, component: React.ComponentType): void;
414
- }
415
- export type { BacklogEntry };
416
- export interface DisplayedCharacter {
417
- objectId: string;
418
- stateId?: string;
419
- position?: {
420
- x: number;
421
- y: number;
422
- };
423
- scale?: number;
374
+ registerComponent(type: ComponentType, component: React.ComponentType<{
375
+ dataAPI?: DataAPI;
376
+ }>): void;
424
377
  }
378
+ export type { EffectPosition, EmotionEffectPosition, EmotionEffectState, EmotionType, FacePosition, PositionType, } from "./emotion-effect-types";
379
+ export type { BacklogEntry, DisplayedCharacter } from "./types";
425
380
  export interface PlayerSettings {
426
381
  textSpeed: number;
427
382
  autoPlaySpeed: number;
428
383
  bgmVolume: number;
429
384
  seVolume: number;
430
385
  voiceVolume: number;
386
+ /** 選択されたフォントファミリー */
387
+ selectedFontFamily?: string;
431
388
  }
432
- export type { ScenarioBlock, Character, EntityState, ActionNode };
389
+ export type { ActionNode, BackgroundData, BackgroundGroupData, BackgroundGroupItem, BackgroundMediaType, BlockOptions, Character, EntityState, FontType, ScenarioBlock, ScenarioBlockType, WorkFont, } from "./types";
433
390
  export declare function definePlugin(plugin: LunaPlugin): LunaPlugin;
434
391
  export declare function defineComponent(type: ComponentType, component: React.ComponentType): {
435
392
  type: ComponentType;
@@ -454,7 +411,7 @@ export declare function calculateFaceRelativePosition(options: FaceRelativeEffec
454
411
  x: number;
455
412
  y: number;
456
413
  };
457
- export { React };
414
+ export { React, useDataAPI };
458
415
  /**
459
416
  * 画面サイズ変換ユーティリティの型定義
460
417
  */
@@ -515,3 +472,17 @@ export declare function useScreenSizeAtom(): [
515
472
  ];
516
473
  export { OverlayUI } from "./components/OverlayUI";
517
474
  export { aspectRatio, BasisHeight, BasisWidth } from "./constants/screen-size";
475
+ /**
476
+ * テキスト内の改行文字(\n)を<br />タグに変換してReact要素を返す
477
+ * プラグインがDialogueBoxなどのコンポーネントでテキストを表示する際に使用
478
+ *
479
+ * @param text 表示するテキスト(改行文字を含む可能性がある)
480
+ * @returns 改行が<br />タグに変換されたReact要素
481
+ *
482
+ * @example
483
+ * ```tsx
484
+ * const content = dataAPI.get("playback", "displayText") || "";
485
+ * return <div>{renderTextWithLineBreaks(content)}</div>;
486
+ * ```
487
+ */
488
+ export declare function renderTextWithLineBreaks(text: string): React.ReactElement | string;
package/dist/sdk.js CHANGED
@@ -1,7 +1,7 @@
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";
4
+ import { useDataAPI } from "./contexts/DataContext";
5
5
  // Component registration types
6
6
  export var ComponentType;
7
7
  (function (ComponentType) {
@@ -15,6 +15,18 @@ export var ComponentType;
15
15
  ComponentType["SettingsMenu"] = "SettingsMenu";
16
16
  ComponentType["GameMenu"] = "GameMenu";
17
17
  ComponentType["Config"] = "Config";
18
+ ComponentType["ConversationBranch"] = "ConversationBranch";
19
+ ComponentType["Background"] = "Background";
20
+ ComponentType["FullscreenTextBox"] = "FullscreenTextBox";
21
+ /**
22
+ * 【機能概要】: 感情エフェクトコンポーネント登録用の型定義
23
+ * 【実装方針】: 既存のComponentType値と同じパターン(PascalCase、文字列リテラル型)で追加
24
+ * 【テスト対応】: TC-001, TC-003, TC-004, TC-012を通すための実装
25
+ * 🔵 信頼性レベル: タスクノート、要件定義書、設計文書に明確に定義されている
26
+ *
27
+ * @see EmotionEffectState - 関連する型定義は emotion-effect-types.ts を参照
28
+ */
29
+ ComponentType["EmotionEffect"] = "EmotionEffect";
18
30
  })(ComponentType || (ComponentType = {}));
19
31
  // Component types are already exported as part of the interfaces above
20
32
  // Plugin utility function
@@ -47,7 +59,6 @@ export function calculateFaceRelativePosition(options) {
47
59
  case "chin":
48
60
  baseY = facePosition.y + facePosition.height * 0.3;
49
61
  break;
50
- case "center":
51
62
  default:
52
63
  // Use face center as is
53
64
  break;
@@ -57,8 +68,32 @@ export function calculateFaceRelativePosition(options) {
57
68
  y: baseY + offsetY,
58
69
  };
59
70
  }
60
- // Export React for plugin use
61
- export { React };
71
+ // Export React and hooks for plugin use
72
+ export { React, useDataAPI };
62
73
  export { OverlayUI } from "./components/OverlayUI";
63
74
  // Screen size constants
64
75
  export { aspectRatio, BasisHeight, BasisWidth } from "./constants/screen-size";
76
+ // ============================================================================
77
+ // Text Utilities - テキスト処理ユーティリティ
78
+ // ============================================================================
79
+ /**
80
+ * テキスト内の改行文字(\n)を<br />タグに変換してReact要素を返す
81
+ * プラグインがDialogueBoxなどのコンポーネントでテキストを表示する際に使用
82
+ *
83
+ * @param text 表示するテキスト(改行文字を含む可能性がある)
84
+ * @returns 改行が<br />タグに変換されたReact要素
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * const content = dataAPI.get("playback", "displayText") || "";
89
+ * return <div>{renderTextWithLineBreaks(content)}</div>;
90
+ * ```
91
+ */
92
+ export function renderTextWithLineBreaks(text) {
93
+ if (!text.includes("\n")) {
94
+ return text;
95
+ }
96
+ return React.createElement(React.Fragment, null, text
97
+ .split("\n")
98
+ .map((line, index, array) => React.createElement("span", { key: index }, line, index < array.length - 1 && React.createElement("br"))));
99
+ }