@luna-editor/engine 0.5.10 → 0.5.11

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.
@@ -1,4 +1,38 @@
1
1
  import { useCallback, useEffect, useRef, useState } from "react";
2
+ /**
3
+ * speakerIdからキャラクター画像URLとクロップ情報を解決する
4
+ * 優先順位: speakerState > baseBodyState > characters[].entityState
5
+ */
6
+ function resolveSpeakerImage(block, allBlocks) {
7
+ var _a, _b, _c, _d;
8
+ // 1. speakerState(単一画像キャラ)
9
+ if ((_a = block.speakerState) === null || _a === void 0 ? void 0 : _a.imageUrl) {
10
+ return {
11
+ imageUrl: block.speakerState.imageUrl,
12
+ cropArea: (_b = block.speakerState.cropArea) !== null && _b !== void 0 ? _b : undefined,
13
+ };
14
+ }
15
+ if (!block.speakerId)
16
+ return {};
17
+ // 2. character_entranceブロックからbaseBodyState or entityStateを探す
18
+ for (const b of allBlocks) {
19
+ if (b.characters) {
20
+ const char = b.characters.find((c) => c.object.id === block.speakerId);
21
+ if (char) {
22
+ if ((_c = char.baseBodyState) === null || _c === void 0 ? void 0 : _c.imageUrl) {
23
+ return { imageUrl: char.baseBodyState.imageUrl };
24
+ }
25
+ if (char.entityState.imageUrl) {
26
+ return {
27
+ imageUrl: char.entityState.imageUrl,
28
+ cropArea: (_d = char.entityState.cropArea) !== null && _d !== void 0 ? _d : undefined,
29
+ };
30
+ }
31
+ }
32
+ }
33
+ }
34
+ return {};
35
+ }
2
36
  export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
3
37
  const [logs, setLogs] = useState([]);
4
38
  const hasBuiltInitialHistory = useRef(false);
@@ -26,8 +60,9 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
26
60
  .map((block, index) => ({ block, realIndex: index }))
27
61
  .filter(({ block }) => block.blockType === "dialogue" || block.blockType === "narration");
28
62
  conversationBlocks.forEach(({ block, realIndex }) => {
29
- var _a, _b, _c, _d, _e;
63
+ var _a, _b, _c;
30
64
  if (!processedBlocks.current.has(realIndex)) {
65
+ const speakerImage = resolveSpeakerImage(block, scenario.blocks);
31
66
  const logEntry = {
32
67
  id: `${block.id}_init`,
33
68
  timestamp: Date.now(),
@@ -37,7 +72,8 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
37
72
  speakerName: (_a = block.speaker) === null || _a === void 0 ? void 0 : _a.name,
38
73
  speakerState: (_b = block.speakerState) === null || _b === void 0 ? void 0 : _b.name,
39
74
  speakerId: (_c = block.speakerId) !== null && _c !== void 0 ? _c : undefined,
40
- speakerImageUrl: (_e = (_d = block.speakerState) === null || _d === void 0 ? void 0 : _d.imageUrl) !== null && _e !== void 0 ? _e : undefined,
75
+ speakerImageUrl: speakerImage.imageUrl,
76
+ speakerCropArea: speakerImage.cropArea,
41
77
  options: block.options,
42
78
  };
43
79
  addLogEntry(logEntry);
@@ -48,7 +84,7 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
48
84
  }, [scenario.blocks, addLogEntry]);
49
85
  // 新しいブロックを処理
50
86
  useEffect(() => {
51
- var _a, _b, _c, _d, _e;
87
+ var _a, _b, _c;
52
88
  if (!currentBlock || !hasBuiltInitialHistory.current) {
53
89
  return;
54
90
  }
@@ -56,7 +92,7 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
56
92
  if (currentBlock.blockType === "dialogue" ||
57
93
  currentBlock.blockType === "narration") {
58
94
  if (!processedBlocks.current.has(currentBlockIndex)) {
59
- console.log("Adding new conversation block to log:", currentBlock);
95
+ const speakerImage = resolveSpeakerImage(currentBlock, scenario.blocks);
60
96
  const logEntry = {
61
97
  id: `${currentBlock.id}_${Date.now()}`,
62
98
  timestamp: Date.now(),
@@ -66,7 +102,8 @@ export function useBacklog({ scenario, currentBlockIndex, currentBlock, }) {
66
102
  speakerName: (_a = currentBlock.speaker) === null || _a === void 0 ? void 0 : _a.name,
67
103
  speakerState: (_b = currentBlock.speakerState) === null || _b === void 0 ? void 0 : _b.name,
68
104
  speakerId: (_c = currentBlock.speakerId) !== null && _c !== void 0 ? _c : undefined,
69
- speakerImageUrl: (_e = (_d = currentBlock.speakerState) === null || _d === void 0 ? void 0 : _d.imageUrl) !== null && _e !== void 0 ? _e : undefined,
105
+ speakerImageUrl: speakerImage.imageUrl,
106
+ speakerCropArea: speakerImage.cropArea,
70
107
  options: currentBlock.options,
71
108
  };
72
109
  addLogEntry(logEntry);
package/dist/types.d.ts CHANGED
@@ -392,8 +392,10 @@ export interface BacklogEntry {
392
392
  speakerState?: string;
393
393
  /** 話者のオブジェクトID */
394
394
  speakerId?: string;
395
- /** 話者の画像URL(そのブロック時点の状態の画像) */
395
+ /** 話者の画像URL(そのブロック時点の状態の画像、またはレイヤーキャラの素体画像) */
396
396
  speakerImageUrl?: string;
397
+ /** 話者の画像クロップ情報(JSON: {x, y, width, height}) */
398
+ speakerCropArea?: string;
397
399
  /** Block options (for plugin-defined options like bubble style) */
398
400
  options?: BlockOptions | null;
399
401
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luna-editor/engine",
3
- "version": "0.5.10",
3
+ "version": "0.5.11",
4
4
  "description": "Luna Editor scenario playback engine",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",