@luna-editor/engine 0.2.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 (64) hide show
  1. package/dist/Player.d.ts +1 -1
  2. package/dist/Player.js +504 -77
  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 +1 -0
  23. package/dist/contexts/AudioContext.js +1 -0
  24. package/dist/contexts/DataContext.js +69 -11
  25. package/dist/hooks/useBacklog.js +3 -0
  26. package/dist/hooks/useConversationBranch.d.ts +16 -0
  27. package/dist/hooks/useConversationBranch.js +125 -0
  28. package/dist/hooks/useFontLoader.d.ts +23 -0
  29. package/dist/hooks/useFontLoader.js +153 -0
  30. package/dist/hooks/useFullscreenText.d.ts +17 -0
  31. package/dist/hooks/useFullscreenText.js +120 -0
  32. package/dist/hooks/usePlayerLogic.d.ts +10 -3
  33. package/dist/hooks/usePlayerLogic.js +115 -18
  34. package/dist/hooks/usePluginEvents.d.ts +4 -1
  35. package/dist/hooks/usePluginEvents.js +16 -11
  36. package/dist/hooks/usePreloadImages.js +27 -7
  37. package/dist/hooks/useSoundPlayer.d.ts +15 -0
  38. package/dist/hooks/useSoundPlayer.js +209 -0
  39. package/dist/hooks/useTypewriter.d.ts +6 -2
  40. package/dist/hooks/useTypewriter.js +42 -6
  41. package/dist/hooks/useVoice.js +4 -1
  42. package/dist/index.d.ts +4 -3
  43. package/dist/index.js +2 -1
  44. package/dist/plugin/PluginManager.d.ts +66 -2
  45. package/dist/plugin/PluginManager.js +349 -79
  46. package/dist/sdk.d.ts +178 -21
  47. package/dist/sdk.js +27 -2
  48. package/dist/types.d.ts +288 -4
  49. package/dist/utils/branchBlockConverter.d.ts +2 -0
  50. package/dist/utils/branchBlockConverter.js +21 -0
  51. package/dist/utils/branchNavigator.d.ts +14 -0
  52. package/dist/utils/branchNavigator.js +55 -0
  53. package/dist/utils/facePositionCalculator.js +0 -1
  54. package/dist/utils/variableManager.d.ts +18 -0
  55. package/dist/utils/variableManager.js +159 -0
  56. package/package.json +1 -1
  57. package/dist/components/ConversationLogUI.d.ts +0 -2
  58. package/dist/components/ConversationLogUI.js +0 -115
  59. package/dist/hooks/useConversationLog.d.ts +0 -14
  60. package/dist/hooks/useConversationLog.js +0 -82
  61. package/dist/hooks/useUIVisibility.d.ts +0 -9
  62. package/dist/hooks/useUIVisibility.js +0 -19
  63. package/dist/plugin/luna-react.d.ts +0 -41
  64. package/dist/plugin/luna-react.js +0 -99
@@ -4,31 +4,59 @@ export const useTypewriter = (options = {}) => {
4
4
  const [displayText, setDisplayText] = useState("");
5
5
  const [isTyping, setIsTyping] = useState(false);
6
6
  const typingTimeoutRef = useRef(null);
7
- const startTyping = useCallback((text) => {
8
- setDisplayText("");
9
- setIsTyping(true);
7
+ // 連続表示用の蓄積テキスト(refに変更して無限ループを防止)
8
+ const accumulatedTextRef = useRef("");
9
+ // タイピング中のターゲットテキスト(スキップ時に使用)
10
+ const targetTextRef = useRef("");
11
+ const startTyping = useCallback((text, continueMode = false) => {
10
12
  if (typingTimeoutRef.current) {
11
13
  clearTimeout(typingTimeoutRef.current);
12
14
  }
15
+ // 連続表示の場合は前のテキストを保持
16
+ let prefix = "";
17
+ if (continueMode && accumulatedTextRef.current) {
18
+ // continueWithNewline: 改行ありで連続、continue: 改行なしで連続
19
+ prefix =
20
+ continueMode === "continueWithNewline"
21
+ ? `${accumulatedTextRef.current}\n`
22
+ : accumulatedTextRef.current;
23
+ }
24
+ const fullText = prefix + text;
25
+ // ターゲットテキストを保存(スキップ時に使用)
26
+ targetTextRef.current = fullText;
27
+ // speed <= 0 の場合は即座に全テキストを表示
28
+ if (speed <= 0) {
29
+ setDisplayText(fullText);
30
+ accumulatedTextRef.current = fullText;
31
+ setIsTyping(false);
32
+ onComplete === null || onComplete === void 0 ? void 0 : onComplete();
33
+ return;
34
+ }
35
+ // 蓄積テキストから開始
36
+ setDisplayText(prefix);
37
+ setIsTyping(true);
13
38
  let index = 0;
14
39
  const typeChar = () => {
15
40
  if (index < text.length) {
16
- setDisplayText(text.slice(0, index + 1));
41
+ setDisplayText(prefix + text.slice(0, index + 1));
17
42
  index++;
18
43
  typingTimeoutRef.current = setTimeout(typeChar, speed);
19
44
  }
20
45
  else {
46
+ accumulatedTextRef.current = fullText;
21
47
  setIsTyping(false);
22
48
  onComplete === null || onComplete === void 0 ? void 0 : onComplete();
23
49
  }
24
50
  };
25
51
  typeChar();
26
52
  }, [speed, onComplete]);
27
- const skipTyping = useCallback((text) => {
53
+ const skipTyping = useCallback(() => {
28
54
  if (typingTimeoutRef.current) {
29
55
  clearTimeout(typingTimeoutRef.current);
30
56
  }
31
- setDisplayText(text);
57
+ const fullText = targetTextRef.current;
58
+ setDisplayText(fullText);
59
+ accumulatedTextRef.current = fullText;
32
60
  setIsTyping(false);
33
61
  onComplete === null || onComplete === void 0 ? void 0 : onComplete();
34
62
  }, [onComplete]);
@@ -37,8 +65,14 @@ export const useTypewriter = (options = {}) => {
37
65
  clearTimeout(typingTimeoutRef.current);
38
66
  }
39
67
  setDisplayText("");
68
+ accumulatedTextRef.current = "";
69
+ targetTextRef.current = "";
40
70
  setIsTyping(false);
41
71
  }, []);
72
+ // 蓄積テキストのみをリセット(次のブロックが連続でない場合に呼び出し)
73
+ const resetAccumulated = useCallback(() => {
74
+ accumulatedTextRef.current = "";
75
+ }, []);
42
76
  useEffect(() => {
43
77
  return () => {
44
78
  if (typingTimeoutRef.current) {
@@ -52,5 +86,7 @@ export const useTypewriter = (options = {}) => {
52
86
  startTyping,
53
87
  skipTyping,
54
88
  reset,
89
+ resetAccumulated,
90
+ accumulatedText: accumulatedTextRef.current,
55
91
  };
56
92
  };
@@ -4,13 +4,16 @@ export const useVoice = () => {
4
4
  const audioRef = useRef(null);
5
5
  const audioSettings = useAudioSettings();
6
6
  const playVoice = useCallback((voiceUrl) => {
7
+ // ミュート中は再生しない
8
+ if (audioSettings.muteAudio)
9
+ return;
7
10
  if (!audioRef.current) {
8
11
  audioRef.current = new Audio();
9
12
  }
10
13
  audioRef.current.src = voiceUrl;
11
14
  audioRef.current.volume = audioSettings.voiceVolume;
12
15
  audioRef.current.play().catch(console.error);
13
- }, [audioSettings.voiceVolume]);
16
+ }, [audioSettings.voiceVolume, audioSettings.muteAudio]);
14
17
  const stopVoice = useCallback(() => {
15
18
  if (audioRef.current) {
16
19
  audioRef.current.pause();
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { useScreenSizeAtom } from "./atoms/screen-size";
2
+ export { FontSettingsPanel } from "./components/FontSettingsPanel";
2
3
  export { OverlayUI } from "./components/OverlayUI";
3
4
  export { aspectRatio, BasisHeight, BasisWidth } from "./constants/screen-size";
4
5
  export type { AudioSettings } from "./contexts/AudioContext";
@@ -7,6 +8,6 @@ export { useDataAPI } from "./contexts/DataContext";
7
8
  export { setGlobalUIAPI, usePluginAPI, useUIVisibility, } from "./hooks/usePluginAPI";
8
9
  export { useScreenScale, useScreenSize, useToPixel, } from "./hooks/useScreenSize";
9
10
  export { Player } from "./Player";
10
- export type { BacklogData, DataAPI, DataContext, PlayerSettingsData, ScenarioPlaybackData, } from "./sdk";
11
- export { ComponentType } from "./sdk";
12
- export type { ActionNode, BacklogEntry, Character, DisplayedCharacter, EntityState, PlayerProps, PlayerSettings, PlayerState, PluginConfig, PublishedScenario, ScenarioBlock, ScenarioBlockAttributeValue, ScenarioBlockCharacter, ScenarioBlockEntityAttributeValue, ScenarioBlockType, } from "./types";
11
+ export type { BacklogData, BlockChangeContext, DataAPI, DataContext, FontsData, PlayerSettingsData, ScenarioPlaybackData, TransitionSource, } from "./sdk";
12
+ export { ComponentType, renderTextWithLineBreaks } from "./sdk";
13
+ export type { ActionNode, BacklogEntry, Character, DisplayedCharacter, EntityState, FontType, PlayerProps, PlayerSettings, PlayerState, PluginConfig, PublishedScenario, ScenarioBlock, ScenarioBlockAttributeValue, ScenarioBlockCharacter, ScenarioBlockEntityAttributeValue, ScenarioBlockType, WorkFont, WorkSound, } from "./types";
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // Screen size system
2
2
  export { useScreenSizeAtom } from "./atoms/screen-size";
3
+ export { FontSettingsPanel } from "./components/FontSettingsPanel";
3
4
  export { OverlayUI } from "./components/OverlayUI";
4
5
  export { aspectRatio, BasisHeight, BasisWidth } from "./constants/screen-size";
5
6
  export { useAudioSettings } from "./contexts/AudioContext";
@@ -7,4 +8,4 @@ export { useDataAPI } from "./contexts/DataContext";
7
8
  export { setGlobalUIAPI, usePluginAPI, useUIVisibility, } from "./hooks/usePluginAPI";
8
9
  export { useScreenScale, useScreenSize, useToPixel, } from "./hooks/useScreenSize";
9
10
  export { Player } from "./Player";
10
- export { ComponentType } from "./sdk";
11
+ export { ComponentType, renderTextWithLineBreaks } from "./sdk";
@@ -11,12 +11,15 @@ interface PluginHooksImpl {
11
11
  onScenarioReady?: (context: ScenarioReadyContext) => void;
12
12
  onBlockChange?: (context: BlockChangeContext) => void;
13
13
  onCharacterEnter?: (context: CharacterContext) => void;
14
- onCharacterExit?: (context: CharacterContext) => void;
15
14
  onDialogueShow?: (context: DialogueContext) => void;
16
15
  characterSpeakHandler?: (context: CharacterSpeakContext) => void;
17
16
  onActionExecute?: (context: ActionExecutionContext) => void;
18
17
  onScenarioStart?: (context: ScenarioContext) => void;
19
18
  onScenarioEnd?: (context: ScenarioContext) => void;
19
+ onBranchStart?: (context: import("../sdk").BranchStartContext) => void;
20
+ onChoiceSelected?: (context: import("../sdk").ChoiceSelectedContext) => void;
21
+ onBranchEnd?: () => void;
22
+ onBranchBlockChange?: (context: import("../sdk").BranchBlockChangeContext) => void;
20
23
  }
21
24
  export interface PluginInstance {
22
25
  actionNodes: Map<string, ActionNodeDefinition>;
@@ -24,7 +27,7 @@ export interface PluginInstance {
24
27
  styles: Map<string, string[]>;
25
28
  effects: Map<string, HTMLElement>;
26
29
  overlays: Map<string, HTMLElement>;
27
- components: Map<ComponentType, React.ComponentType<any>>;
30
+ components: Map<ComponentType, React.ComponentType<unknown>>;
28
31
  assetUrls: Map<string, string>;
29
32
  }
30
33
  export declare class PluginManager {
@@ -35,12 +38,22 @@ export declare class PluginManager {
35
38
  private componentRegistry;
36
39
  private uiVisibilityState;
37
40
  private uiVisibilityListeners;
41
+ private selectChoiceCallback;
42
+ private getBranchStateCallback;
43
+ private preloadPromises;
44
+ private muteAudio;
45
+ private workSounds;
46
+ private clickSoundUrl;
47
+ private clickSoundVolume;
48
+ private clickSoundOverridden;
38
49
  constructor();
39
50
  /**
40
51
  * グローバルReactランタイムを初期化(クライアントサイドのみ)
52
+ * 既に初期化済みの場合はスキップ
41
53
  */
42
54
  private initializeReactRuntime;
43
55
  loadPlugin(packageName: string, bundleUrl: string, config?: unknown): Promise<void>;
56
+ private doLoadPlugin;
44
57
  private loadPluginScript;
45
58
  private createPluginAPI;
46
59
  private applyStyles;
@@ -104,5 +117,56 @@ export declare class PluginManager {
104
117
  * @param type - コンポーネントタイプ
105
118
  */
106
119
  hideUI(type: ComponentType): void;
120
+ setSelectChoiceCallback(callback: (choiceId: string) => void): void;
121
+ setGetBranchStateCallback(callback: () => import("../types").ConversationBranchState | null): void;
122
+ /**
123
+ * 全てのアセットプリロードが完了するまで待機
124
+ * @returns プリロード完了時にresolveするPromise
125
+ */
126
+ waitForPreloads(): Promise<void>;
127
+ /**
128
+ * 音声のミュート状態を設定
129
+ * @param mute - ミュートするかどうか
130
+ */
131
+ setMuteAudio(mute: boolean): void;
132
+ /**
133
+ * 作品のサウンドデータを設定
134
+ * @param sounds - サウンドIDをキーとしたURL/名前のマップ
135
+ */
136
+ setWorkSounds(sounds: Array<{
137
+ id: string;
138
+ url: string;
139
+ name: string;
140
+ }>): void;
141
+ /**
142
+ * 作品のサウンドURLを取得
143
+ * @param soundId - サウンドID
144
+ */
145
+ getWorkSoundUrl(soundId: string): string | null;
146
+ /**
147
+ * ビルトインのクリック音を設定
148
+ * @param url - サウンドファイルのURL(nullで無効化)
149
+ * @param volume - 音量(0.0 - 1.0)
150
+ */
151
+ setClickSound(url: string | null, volume?: number): void;
152
+ /**
153
+ * プラグインがクリック音を上書きする
154
+ * これを呼び出すと、ビルトインのクリック音は再生されなくなる
155
+ */
156
+ overrideClickSound(): void;
157
+ /**
158
+ * プラグインのクリック音上書きをリセット
159
+ * 各ブロック遷移の前に呼び出す
160
+ */
161
+ resetClickSoundOverride(): void;
162
+ /**
163
+ * クリック音が上書きされているかを取得
164
+ */
165
+ isClickSoundOverridden(): boolean;
166
+ /**
167
+ * ビルトインのクリック音を再生
168
+ * プラグインで上書きされている場合やミュート中は再生しない
169
+ */
170
+ playClickSound(): void;
107
171
  }
108
172
  export {};