sa2kit 1.2.1 → 1.4.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.
- package/dist/{UniversalFileService-C1rUWWU-.d.ts → UniversalFileService-BuHN-jrR.d.ts} +46 -2
- package/dist/{UniversalFileService-DrCK0-NL.d.mts → UniversalFileService-CGGzYeeF.d.mts} +46 -2
- package/dist/{chunk-3XG5OHFD.mjs → chunk-CIVO4R6N.mjs} +2 -2
- package/dist/{chunk-3XG5OHFD.mjs.map → chunk-CIVO4R6N.mjs.map} +1 -1
- package/dist/chunk-EV6BCVOQ.mjs +204 -0
- package/dist/chunk-EV6BCVOQ.mjs.map +1 -0
- package/dist/chunk-W35VTQAW.js +211 -0
- package/dist/chunk-W35VTQAW.js.map +1 -0
- package/dist/{chunk-HWJ34NL6.js → chunk-ZRAW3HXA.js} +2 -2
- package/dist/{chunk-HWJ34NL6.js.map → chunk-ZRAW3HXA.js.map} +1 -1
- package/dist/drizzle-schema-BNhqj2AZ.d.mts +1114 -0
- package/dist/drizzle-schema-BNhqj2AZ.d.ts +1114 -0
- package/dist/mmd/admin/index.d.mts +8 -1115
- package/dist/mmd/admin/index.d.ts +8 -1115
- package/dist/mmd/admin/index.js +98 -248
- package/dist/mmd/admin/index.js.map +1 -1
- package/dist/mmd/admin/index.mjs +75 -244
- package/dist/mmd/admin/index.mjs.map +1 -1
- package/dist/mmd/index.d.mts +265 -3
- package/dist/mmd/index.d.ts +265 -3
- package/dist/mmd/index.js +1266 -15
- package/dist/mmd/index.js.map +1 -1
- package/dist/mmd/index.mjs +1261 -16
- package/dist/mmd/index.mjs.map +1 -1
- package/dist/mmd/server/index.d.mts +138 -0
- package/dist/mmd/server/index.d.ts +138 -0
- package/dist/mmd/server/index.js +245 -0
- package/dist/mmd/server/index.js.map +1 -0
- package/dist/mmd/server/index.mjs +207 -0
- package/dist/mmd/server/index.mjs.map +1 -0
- package/dist/testYourself/index.d.mts +145 -0
- package/dist/testYourself/index.d.ts +145 -0
- package/dist/testYourself/index.js +1004 -0
- package/dist/testYourself/index.js.map +1 -0
- package/dist/testYourself/index.mjs +993 -0
- package/dist/testYourself/index.mjs.map +1 -0
- package/dist/{types-C2ale3d9.d.mts → types-Bc_p-zAR.d.mts} +1 -1
- package/dist/{types-C2ale3d9.d.ts → types-Bc_p-zAR.d.ts} +1 -1
- package/dist/{types-Dg-U_chI.d.mts → types-CK4We_aI.d.mts} +13 -1
- package/dist/{types-Dg-U_chI.d.ts → types-CK4We_aI.d.ts} +13 -1
- package/dist/universalFile/index.d.mts +3 -3
- package/dist/universalFile/index.d.ts +3 -3
- package/dist/universalFile/index.js +48 -10
- package/dist/universalFile/index.js.map +1 -1
- package/dist/universalFile/index.mjs +43 -5
- package/dist/universalFile/index.mjs.map +1 -1
- package/dist/universalFile/server/index.d.mts +3 -3
- package/dist/universalFile/server/index.d.ts +3 -3
- package/dist/universalFile/server/index.js +239 -7
- package/dist/universalFile/server/index.js.map +1 -1
- package/dist/universalFile/server/index.mjs +234 -2
- package/dist/universalFile/server/index.mjs.map +1 -1
- package/package.json +19 -1
package/dist/mmd/index.js
CHANGED
|
@@ -5,6 +5,7 @@ var React6 = require('react');
|
|
|
5
5
|
var THREE = require('three');
|
|
6
6
|
var threeStdlib = require('three-stdlib');
|
|
7
7
|
var lucideReact = require('lucide-react');
|
|
8
|
+
var reactDom = require('react-dom');
|
|
8
9
|
|
|
9
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
|
|
@@ -71,6 +72,102 @@ var loadAmmo = (path = "/libs/ammo.wasm.js") => {
|
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
// src/mmd/components/MMDPlayerBase.tsx
|
|
75
|
+
async function waitForMaterialsReady(object, renderer, scene, camera) {
|
|
76
|
+
const textures = [];
|
|
77
|
+
let meshCount = 0;
|
|
78
|
+
object.traverse((obj) => {
|
|
79
|
+
if (obj instanceof THREE__namespace.Mesh || obj instanceof THREE__namespace.SkinnedMesh) {
|
|
80
|
+
meshCount++;
|
|
81
|
+
const materials = Array.isArray(obj.material) ? obj.material : [obj.material];
|
|
82
|
+
materials.forEach((material) => {
|
|
83
|
+
if (material instanceof THREE__namespace.Material) {
|
|
84
|
+
const textureProps = [
|
|
85
|
+
"map",
|
|
86
|
+
"lightMap",
|
|
87
|
+
"bumpMap",
|
|
88
|
+
"normalMap",
|
|
89
|
+
"specularMap",
|
|
90
|
+
"envMap",
|
|
91
|
+
"alphaMap",
|
|
92
|
+
"emissiveMap",
|
|
93
|
+
"displacementMap",
|
|
94
|
+
"roughnessMap",
|
|
95
|
+
"metalnessMap",
|
|
96
|
+
"aoMap",
|
|
97
|
+
// MMD 特有纹理
|
|
98
|
+
"gradientMap",
|
|
99
|
+
"toonMap",
|
|
100
|
+
"sphereMap",
|
|
101
|
+
"matcap"
|
|
102
|
+
];
|
|
103
|
+
textureProps.forEach((prop) => {
|
|
104
|
+
const texture = material[prop];
|
|
105
|
+
if (texture instanceof THREE__namespace.Texture && !textures.includes(texture)) {
|
|
106
|
+
textures.push(texture);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
console.log(`[MMDPlayerBase] Found ${meshCount} meshes and ${textures.length} unique textures`);
|
|
114
|
+
const texturePromises = textures.map((texture, index) => {
|
|
115
|
+
return new Promise((resolve) => {
|
|
116
|
+
const image = texture.image;
|
|
117
|
+
if (!image) {
|
|
118
|
+
console.log(`[MMDPlayerBase] Texture ${index + 1}/${textures.length}: No image`);
|
|
119
|
+
resolve();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (image instanceof HTMLImageElement) {
|
|
123
|
+
if (image.complete && image.naturalWidth > 0) {
|
|
124
|
+
console.log(`[MMDPlayerBase] Texture ${index + 1}/${textures.length}: Already loaded`);
|
|
125
|
+
resolve();
|
|
126
|
+
} else {
|
|
127
|
+
const onLoad = () => {
|
|
128
|
+
console.log(`[MMDPlayerBase] Texture ${index + 1}/${textures.length}: Loaded`);
|
|
129
|
+
image.removeEventListener("load", onLoad);
|
|
130
|
+
image.removeEventListener("error", onError);
|
|
131
|
+
resolve();
|
|
132
|
+
};
|
|
133
|
+
const onError = (e) => {
|
|
134
|
+
console.warn(`[MMDPlayerBase] Texture ${index + 1}/${textures.length}: Failed to load`, e);
|
|
135
|
+
image.removeEventListener("load", onLoad);
|
|
136
|
+
image.removeEventListener("error", onError);
|
|
137
|
+
resolve();
|
|
138
|
+
};
|
|
139
|
+
image.addEventListener("load", onLoad);
|
|
140
|
+
image.addEventListener("error", onError);
|
|
141
|
+
setTimeout(() => {
|
|
142
|
+
image.removeEventListener("load", onLoad);
|
|
143
|
+
image.removeEventListener("error", onError);
|
|
144
|
+
console.warn(`[MMDPlayerBase] Texture ${index + 1}/${textures.length}: Timeout`);
|
|
145
|
+
resolve();
|
|
146
|
+
}, 5e3);
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
console.log(`[MMDPlayerBase] Texture ${index + 1}/${textures.length}: Non-image type`);
|
|
150
|
+
resolve();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
await Promise.all(texturePromises);
|
|
155
|
+
console.log("[MMDPlayerBase] All texture images loaded");
|
|
156
|
+
textures.forEach((texture) => {
|
|
157
|
+
texture.needsUpdate = true;
|
|
158
|
+
});
|
|
159
|
+
console.log("[MMDPlayerBase] Warming up renderer...");
|
|
160
|
+
for (let i = 0; i < 3; i++) {
|
|
161
|
+
await new Promise((resolve) => {
|
|
162
|
+
requestAnimationFrame(() => {
|
|
163
|
+
renderer.render(scene, camera);
|
|
164
|
+
console.log(`[MMDPlayerBase] Warmup render ${i + 1}/3`);
|
|
165
|
+
resolve();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
console.log("[MMDPlayerBase] All materials and textures fully ready");
|
|
170
|
+
}
|
|
74
171
|
var MMDPlayerBase = React6.forwardRef((props, ref) => {
|
|
75
172
|
const {
|
|
76
173
|
resources,
|
|
@@ -256,7 +353,9 @@ var MMDPlayerBase = React6.forwardRef((props, ref) => {
|
|
|
256
353
|
preserveDrawingBuffer: true
|
|
257
354
|
});
|
|
258
355
|
renderer.setSize(width, height);
|
|
259
|
-
|
|
356
|
+
const pixelRatio = mobileOptimization.enabled ? mobileOptimization.pixelRatio || Math.min(window.devicePixelRatio, 2) : window.devicePixelRatio;
|
|
357
|
+
renderer.setPixelRatio(pixelRatio);
|
|
358
|
+
console.log("[MMDPlayerBase] Pixel ratio set to:", pixelRatio);
|
|
260
359
|
if (checkCancelled()) {
|
|
261
360
|
renderer.dispose();
|
|
262
361
|
return;
|
|
@@ -266,6 +365,7 @@ var MMDPlayerBase = React6.forwardRef((props, ref) => {
|
|
|
266
365
|
renderer.domElement.style.width = "100%";
|
|
267
366
|
renderer.domElement.style.height = "100%";
|
|
268
367
|
renderer.domElement.style.outline = "none";
|
|
368
|
+
renderer.domElement.style.position = "relative";
|
|
269
369
|
if (stage.enableShadow !== false && !mobileOptimization.reduceShadowQuality) {
|
|
270
370
|
renderer.shadowMap.enabled = true;
|
|
271
371
|
renderer.shadowMap.type = THREE__namespace.PCFSoftShadowMap;
|
|
@@ -312,6 +412,8 @@ var MMDPlayerBase = React6.forwardRef((props, ref) => {
|
|
|
312
412
|
resizeObserver.observe(container);
|
|
313
413
|
resizeObserverRef.current = resizeObserver;
|
|
314
414
|
onResize();
|
|
415
|
+
console.log("[MMDPlayerBase] Starting render loop (animation paused)");
|
|
416
|
+
animate();
|
|
315
417
|
console.log("[MMDPlayerBase] Start loading resources...", resources);
|
|
316
418
|
const loader = new threeStdlib.MMDLoader();
|
|
317
419
|
const helper = new threeStdlib.MMDAnimationHelper({
|
|
@@ -360,6 +462,15 @@ var MMDPlayerBase = React6.forwardRef((props, ref) => {
|
|
|
360
462
|
durationRef.current = animation.duration;
|
|
361
463
|
console.log("[MMDPlayerBase] Animation duration:", animation.duration);
|
|
362
464
|
}
|
|
465
|
+
mesh.castShadow = true;
|
|
466
|
+
mesh.receiveShadow = true;
|
|
467
|
+
console.log("[MMDPlayerBase] Waiting for all materials and textures to load...");
|
|
468
|
+
const tempScene = new THREE__namespace.Scene();
|
|
469
|
+
tempScene.add(mesh);
|
|
470
|
+
await waitForMaterialsReady(mesh, renderer, tempScene, camera);
|
|
471
|
+
if (checkCancelled()) return;
|
|
472
|
+
console.log("[MMDPlayerBase] \u2705 All materials and textures loaded");
|
|
473
|
+
tempScene.remove(mesh);
|
|
363
474
|
const box = new THREE__namespace.Box3().setFromObject(mesh);
|
|
364
475
|
if (!box.isEmpty()) {
|
|
365
476
|
const center = box.getCenter(new THREE__namespace.Vector3());
|
|
@@ -383,14 +494,13 @@ var MMDPlayerBase = React6.forwardRef((props, ref) => {
|
|
|
383
494
|
controls.update();
|
|
384
495
|
}
|
|
385
496
|
}
|
|
386
|
-
mesh.castShadow = true;
|
|
387
|
-
mesh.receiveShadow = true;
|
|
388
497
|
const enablePhysics = stage.enablePhysics !== false && !mobileOptimization.disablePhysics;
|
|
389
498
|
helper.add(mesh, {
|
|
390
499
|
animation,
|
|
391
500
|
physics: enablePhysics
|
|
392
501
|
});
|
|
393
502
|
scene.add(mesh);
|
|
503
|
+
console.log("[MMDPlayerBase] \u2705 Model added to scene (fully loaded)");
|
|
394
504
|
if (resources.cameraPath) {
|
|
395
505
|
loader.loadAnimation(
|
|
396
506
|
resources.cameraPath,
|
|
@@ -427,31 +537,56 @@ var MMDPlayerBase = React6.forwardRef((props, ref) => {
|
|
|
427
537
|
(err) => console.error("Failed to load audio:", err)
|
|
428
538
|
);
|
|
429
539
|
}
|
|
540
|
+
let stageMesh = null;
|
|
430
541
|
if (resources.stageModelPath) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
(
|
|
441
|
-
|
|
542
|
+
try {
|
|
543
|
+
stageMesh = await new Promise((resolve, reject) => {
|
|
544
|
+
loader.load(
|
|
545
|
+
resources.stageModelPath,
|
|
546
|
+
(mesh2) => resolve(mesh2),
|
|
547
|
+
void 0,
|
|
548
|
+
(err) => reject(err)
|
|
549
|
+
);
|
|
550
|
+
});
|
|
551
|
+
if (checkCancelled()) return;
|
|
552
|
+
console.log("[MMDPlayerBase] Stage model loaded:", stageMesh);
|
|
553
|
+
stageMesh.castShadow = true;
|
|
554
|
+
stageMesh.receiveShadow = true;
|
|
555
|
+
console.log("[MMDPlayerBase] Waiting for stage materials and textures...");
|
|
556
|
+
const tempStageScene = new THREE__namespace.Scene();
|
|
557
|
+
tempStageScene.add(stageMesh);
|
|
558
|
+
await waitForMaterialsReady(stageMesh, renderer, tempStageScene, camera);
|
|
559
|
+
tempStageScene.remove(stageMesh);
|
|
560
|
+
if (checkCancelled()) return;
|
|
561
|
+
console.log("[MMDPlayerBase] \u2705 Stage materials and textures loaded");
|
|
562
|
+
scene.add(stageMesh);
|
|
563
|
+
console.log("[MMDPlayerBase] \u2705 Stage added to scene (fully loaded)");
|
|
564
|
+
} catch (err) {
|
|
565
|
+
console.error("Failed to load stage:", err);
|
|
566
|
+
}
|
|
442
567
|
}
|
|
443
568
|
if (checkCancelled()) return;
|
|
444
569
|
isReadyRef.current = true;
|
|
570
|
+
console.log("[MMDPlayerBase] \u{1F389} All resources fully loaded and ready!");
|
|
571
|
+
console.log("[MMDPlayerBase] \u{1F4CA} Summary:");
|
|
572
|
+
console.log(`[MMDPlayerBase] - Model: \u2705 Fully loaded with all textures`);
|
|
573
|
+
if (resources.stageModelPath) {
|
|
574
|
+
console.log(`[MMDPlayerBase] - Stage: \u2705 Fully loaded with all textures`);
|
|
575
|
+
}
|
|
576
|
+
if (animation) {
|
|
577
|
+
console.log(`[MMDPlayerBase] - Animation: \u2705 Ready (${animation.duration.toFixed(2)}s)`);
|
|
578
|
+
}
|
|
579
|
+
console.log("[MMDPlayerBase] \u{1F514} Triggering onLoad callback");
|
|
445
580
|
onLoad?.();
|
|
446
581
|
if (autoPlay) {
|
|
447
582
|
setTimeout(() => {
|
|
448
583
|
if (checkCancelled()) return;
|
|
584
|
+
console.log("[MMDPlayerBase] \u{1F3AC} Starting animation playback (after materials fully loaded)");
|
|
449
585
|
isPlayingRef.current = true;
|
|
450
586
|
if (!clockRef.current.running) clockRef.current.start();
|
|
451
587
|
onPlay?.();
|
|
452
588
|
}, 100);
|
|
453
589
|
}
|
|
454
|
-
animate();
|
|
455
590
|
} catch (error) {
|
|
456
591
|
if (checkCancelled()) return;
|
|
457
592
|
console.error("MMDPlayerBase initialization failed:", error);
|
|
@@ -900,6 +1035,7 @@ ${errorMessage}
|
|
|
900
1035
|
height: "100%",
|
|
901
1036
|
overflow: "hidden",
|
|
902
1037
|
position: "relative",
|
|
1038
|
+
// 恢复 relative,作为 canvas 的定位容器
|
|
903
1039
|
backgroundColor: stage.backgroundColor || "#000",
|
|
904
1040
|
...style
|
|
905
1041
|
}
|
|
@@ -1613,12 +1749,1127 @@ var MMDPlaylist = ({
|
|
|
1613
1749
|
))
|
|
1614
1750
|
);
|
|
1615
1751
|
};
|
|
1752
|
+
if (typeof document !== "undefined" && !document.getElementById("dialogue-box-animations")) {
|
|
1753
|
+
const style = document.createElement("style");
|
|
1754
|
+
style.id = "dialogue-box-animations";
|
|
1755
|
+
style.textContent = `
|
|
1756
|
+
@keyframes gradientShift {
|
|
1757
|
+
0%, 100% { background-position: 0% 50%; }
|
|
1758
|
+
50% { background-position: 100% 50%; }
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
@keyframes shimmer {
|
|
1762
|
+
0% { background-position: -200% 0; }
|
|
1763
|
+
100% { background-position: 200% 0; }
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
@keyframes cursorBlink {
|
|
1767
|
+
0%, 100% { opacity: 1; transform: scaleY(1); }
|
|
1768
|
+
50% { opacity: 0.3; transform: scaleY(0.8); }
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
@keyframes textFadeIn {
|
|
1772
|
+
from { opacity: 0; transform: translateY(2px); }
|
|
1773
|
+
to { opacity: 1; transform: translateY(0); }
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
@keyframes bounce {
|
|
1777
|
+
0%, 100% { transform: translateY(0); }
|
|
1778
|
+
50% { transform: translateY(-4px); }
|
|
1779
|
+
}
|
|
1780
|
+
`;
|
|
1781
|
+
document.head.appendChild(style);
|
|
1782
|
+
}
|
|
1783
|
+
var defaultTheme = {
|
|
1784
|
+
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
|
1785
|
+
borderColor: "rgba(255, 255, 255, 0.25)",
|
|
1786
|
+
textColor: "#ffffff",
|
|
1787
|
+
speakerBgColor: "rgba(255, 255, 255, 0.25)",
|
|
1788
|
+
speakerTextColor: "#ffffff",
|
|
1789
|
+
opacity: 0.98,
|
|
1790
|
+
blur: "24px",
|
|
1791
|
+
continueHint: "\u70B9\u51FB\u7EE7\u7EED \u25BC",
|
|
1792
|
+
showContinueHint: true
|
|
1793
|
+
};
|
|
1794
|
+
var DialogueBox = ({
|
|
1795
|
+
dialogue,
|
|
1796
|
+
theme: userTheme,
|
|
1797
|
+
isTyping = false,
|
|
1798
|
+
isAutoMode = false,
|
|
1799
|
+
onClick,
|
|
1800
|
+
onSkipTyping,
|
|
1801
|
+
onToggleAuto,
|
|
1802
|
+
onOpenHistory,
|
|
1803
|
+
onSkip,
|
|
1804
|
+
showControls = true,
|
|
1805
|
+
showSkipButton = true,
|
|
1806
|
+
showAutoButton = true,
|
|
1807
|
+
showHistoryButton = true,
|
|
1808
|
+
className
|
|
1809
|
+
}) => {
|
|
1810
|
+
const theme = { ...defaultTheme, ...userTheme };
|
|
1811
|
+
const [displayedText, setDisplayedText] = React6.useState("");
|
|
1812
|
+
const [isComplete, setIsComplete] = React6.useState(false);
|
|
1813
|
+
const [isMounted, setIsMounted] = React6.useState(false);
|
|
1814
|
+
const typingRef = React6.useRef(null);
|
|
1815
|
+
const currentTextRef = React6.useRef("");
|
|
1816
|
+
React6.useEffect(() => {
|
|
1817
|
+
setIsMounted(true);
|
|
1818
|
+
}, []);
|
|
1819
|
+
React6.useEffect(() => {
|
|
1820
|
+
if (!dialogue) {
|
|
1821
|
+
setDisplayedText("");
|
|
1822
|
+
setIsComplete(false);
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
const text = dialogue.text;
|
|
1826
|
+
const speed = dialogue.typeSpeed ?? 50;
|
|
1827
|
+
if (typingRef.current) {
|
|
1828
|
+
clearTimeout(typingRef.current);
|
|
1829
|
+
}
|
|
1830
|
+
setDisplayedText("");
|
|
1831
|
+
setIsComplete(false);
|
|
1832
|
+
currentTextRef.current = text;
|
|
1833
|
+
let index = 0;
|
|
1834
|
+
const typeNext = () => {
|
|
1835
|
+
if (index < text.length && currentTextRef.current === text) {
|
|
1836
|
+
setDisplayedText(text.slice(0, index + 1));
|
|
1837
|
+
index++;
|
|
1838
|
+
typingRef.current = setTimeout(typeNext, speed);
|
|
1839
|
+
} else if (currentTextRef.current === text) {
|
|
1840
|
+
setIsComplete(true);
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
typingRef.current = setTimeout(typeNext, speed);
|
|
1844
|
+
return () => {
|
|
1845
|
+
if (typingRef.current) {
|
|
1846
|
+
clearTimeout(typingRef.current);
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
}, [dialogue]);
|
|
1850
|
+
const handleSkipTyping = React6.useCallback(() => {
|
|
1851
|
+
if (typingRef.current) {
|
|
1852
|
+
clearTimeout(typingRef.current);
|
|
1853
|
+
}
|
|
1854
|
+
if (dialogue) {
|
|
1855
|
+
setDisplayedText(dialogue.text);
|
|
1856
|
+
setIsComplete(true);
|
|
1857
|
+
}
|
|
1858
|
+
onSkipTyping?.();
|
|
1859
|
+
}, [dialogue, onSkipTyping]);
|
|
1860
|
+
const handleClick = React6.useCallback(() => {
|
|
1861
|
+
if (!isComplete) {
|
|
1862
|
+
handleSkipTyping();
|
|
1863
|
+
} else {
|
|
1864
|
+
onClick?.();
|
|
1865
|
+
}
|
|
1866
|
+
}, [isComplete, handleSkipTyping, onClick]);
|
|
1867
|
+
if (!dialogue) {
|
|
1868
|
+
return null;
|
|
1869
|
+
}
|
|
1870
|
+
dialogue.speakerColor || theme.speakerBgColor;
|
|
1871
|
+
console.log("[DialogueBox] Rendering:", {
|
|
1872
|
+
speaker: dialogue.speaker,
|
|
1873
|
+
text: dialogue.text,
|
|
1874
|
+
displayedText,
|
|
1875
|
+
isComplete
|
|
1876
|
+
});
|
|
1877
|
+
const dialogueContent = /* @__PURE__ */ React6__default.default.createElement(
|
|
1878
|
+
"div",
|
|
1879
|
+
{
|
|
1880
|
+
className: `${className || ""}`,
|
|
1881
|
+
style: {
|
|
1882
|
+
position: "fixed",
|
|
1883
|
+
bottom: 0,
|
|
1884
|
+
left: 0,
|
|
1885
|
+
right: 0,
|
|
1886
|
+
height: "30vh",
|
|
1887
|
+
minHeight: "200px",
|
|
1888
|
+
maxHeight: "30vh",
|
|
1889
|
+
zIndex: 1,
|
|
1890
|
+
pointerEvents: "auto"
|
|
1891
|
+
}
|
|
1892
|
+
},
|
|
1893
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
1894
|
+
"div",
|
|
1895
|
+
{
|
|
1896
|
+
className: "w-full h-full rounded-t-3xl border cursor-pointer select-none transition-all hover:border-white/50 hover:shadow-2xl flex flex-col relative overflow-hidden",
|
|
1897
|
+
onClick: handleClick,
|
|
1898
|
+
style: {
|
|
1899
|
+
borderColor: theme.borderColor,
|
|
1900
|
+
backdropFilter: `blur(${theme.blur}) saturate(200%)`,
|
|
1901
|
+
WebkitBackdropFilter: `blur(${theme.blur}) saturate(200%)`,
|
|
1902
|
+
opacity: theme.opacity,
|
|
1903
|
+
pointerEvents: "auto",
|
|
1904
|
+
position: "relative",
|
|
1905
|
+
display: "flex",
|
|
1906
|
+
background: `linear-gradient(135deg,
|
|
1907
|
+
rgba(255, 255, 255, 0.15) 0%,
|
|
1908
|
+
rgba(255, 255, 255, 0.12) 50%,
|
|
1909
|
+
rgba(255, 255, 255, 0.1) 100%)`,
|
|
1910
|
+
boxShadow: `
|
|
1911
|
+
0 -8px 40px rgba(255, 255, 255, 0.1),
|
|
1912
|
+
0 -4px 16px rgba(255, 255, 255, 0.05),
|
|
1913
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.3),
|
|
1914
|
+
inset 0 -1px 0 rgba(255, 255, 255, 0.1)
|
|
1915
|
+
`
|
|
1916
|
+
}
|
|
1917
|
+
},
|
|
1918
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
1919
|
+
"div",
|
|
1920
|
+
{
|
|
1921
|
+
className: "absolute inset-0 opacity-20 pointer-events-none",
|
|
1922
|
+
style: {
|
|
1923
|
+
background: `linear-gradient(45deg,
|
|
1924
|
+
rgba(255, 182, 193, 0.2) 0%,
|
|
1925
|
+
rgba(173, 216, 230, 0.2) 25%,
|
|
1926
|
+
rgba(221, 160, 221, 0.2) 50%,
|
|
1927
|
+
rgba(255, 218, 185, 0.2) 75%,
|
|
1928
|
+
rgba(255, 182, 193, 0.2) 100%)`,
|
|
1929
|
+
backgroundSize: "400% 400%",
|
|
1930
|
+
animation: "gradientShift 15s ease infinite"
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
),
|
|
1934
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
1935
|
+
"div",
|
|
1936
|
+
{
|
|
1937
|
+
className: "absolute top-0 left-0 right-0 h-1",
|
|
1938
|
+
style: {
|
|
1939
|
+
background: "linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent)"
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
),
|
|
1943
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
1944
|
+
"div",
|
|
1945
|
+
{
|
|
1946
|
+
className: "absolute bottom-0 left-0 right-0 h-px",
|
|
1947
|
+
style: {
|
|
1948
|
+
background: "linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent)"
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
),
|
|
1952
|
+
showControls && /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex justify-end gap-3 px-6 pt-4 pb-2 flex-shrink-0 relative z-10" }, showHistoryButton && /* @__PURE__ */ React6__default.default.createElement(
|
|
1953
|
+
"button",
|
|
1954
|
+
{
|
|
1955
|
+
onClick: (e) => {
|
|
1956
|
+
e.stopPropagation();
|
|
1957
|
+
onOpenHistory?.();
|
|
1958
|
+
},
|
|
1959
|
+
className: "px-4 py-2 text-xs rounded-xl text-white font-medium hover:text-white transition-all backdrop-blur-lg border border-white/30 hover:border-white/50 hover:scale-105 active:scale-95 shadow-lg",
|
|
1960
|
+
style: {
|
|
1961
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
1962
|
+
boxShadow: "0 4px 16px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.3)"
|
|
1963
|
+
},
|
|
1964
|
+
title: "\u5386\u53F2\u8BB0\u5F55"
|
|
1965
|
+
},
|
|
1966
|
+
"\u{1F4DC} \u5386\u53F2"
|
|
1967
|
+
), showAutoButton && /* @__PURE__ */ React6__default.default.createElement(
|
|
1968
|
+
"button",
|
|
1969
|
+
{
|
|
1970
|
+
onClick: (e) => {
|
|
1971
|
+
e.stopPropagation();
|
|
1972
|
+
onToggleAuto?.();
|
|
1973
|
+
},
|
|
1974
|
+
className: `px-4 py-2 text-xs rounded-xl font-medium transition-all backdrop-blur-lg border hover:scale-105 active:scale-95 shadow-lg ${isAutoMode ? "border-white/50 text-white" : "border-white/30 hover:border-white/50 text-white"}`,
|
|
1975
|
+
style: {
|
|
1976
|
+
background: isAutoMode ? "linear-gradient(135deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.25))" : "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
1977
|
+
boxShadow: isAutoMode ? "0 4px 20px rgba(255, 255, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.4)" : "0 4px 16px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.3)"
|
|
1978
|
+
},
|
|
1979
|
+
title: "\u81EA\u52A8\u64AD\u653E"
|
|
1980
|
+
},
|
|
1981
|
+
"\u25B6 \u81EA\u52A8"
|
|
1982
|
+
), showSkipButton && /* @__PURE__ */ React6__default.default.createElement(
|
|
1983
|
+
"button",
|
|
1984
|
+
{
|
|
1985
|
+
onClick: (e) => {
|
|
1986
|
+
e.stopPropagation();
|
|
1987
|
+
onSkip?.();
|
|
1988
|
+
},
|
|
1989
|
+
className: "px-4 py-2 text-xs rounded-xl text-white font-medium hover:text-white transition-all backdrop-blur-lg border border-white/30 hover:border-white/50 hover:scale-105 active:scale-95 shadow-lg",
|
|
1990
|
+
style: {
|
|
1991
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
1992
|
+
boxShadow: "0 4px 16px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.3)"
|
|
1993
|
+
},
|
|
1994
|
+
title: "\u5FEB\u8FDB"
|
|
1995
|
+
},
|
|
1996
|
+
"\u23E9 \u5FEB\u8FDB"
|
|
1997
|
+
)),
|
|
1998
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "px-8 pb-6 flex-1 flex flex-col justify-center overflow-y-auto relative z-10" }, dialogue.speaker && /* @__PURE__ */ React6__default.default.createElement(
|
|
1999
|
+
"div",
|
|
2000
|
+
{
|
|
2001
|
+
className: "inline-block px-6 py-2.5 rounded-2xl mb-4 text-sm font-bold shadow-2xl self-start relative overflow-hidden transition-all hover:scale-105",
|
|
2002
|
+
style: {
|
|
2003
|
+
color: "#ffffff",
|
|
2004
|
+
background: `linear-gradient(135deg,
|
|
2005
|
+
rgba(255, 255, 255, 0.3) 0%,
|
|
2006
|
+
rgba(255, 255, 255, 0.2) 100%)`,
|
|
2007
|
+
backdropFilter: "blur(20px)",
|
|
2008
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
2009
|
+
boxShadow: "0 8px 32px rgba(255, 255, 255, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.4)",
|
|
2010
|
+
border: "1px solid rgba(255, 255, 255, 0.3)"
|
|
2011
|
+
}
|
|
2012
|
+
},
|
|
2013
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2014
|
+
"div",
|
|
2015
|
+
{
|
|
2016
|
+
className: "absolute inset-0 opacity-30",
|
|
2017
|
+
style: {
|
|
2018
|
+
background: "linear-gradient(45deg, transparent 30%, rgba(255,255,255,0.5) 50%, transparent 70%)",
|
|
2019
|
+
backgroundSize: "200% 200%",
|
|
2020
|
+
animation: "shimmer 3s infinite"
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
),
|
|
2024
|
+
/* @__PURE__ */ React6__default.default.createElement("span", { className: "relative z-10 drop-shadow-lg" }, dialogue.speaker)
|
|
2025
|
+
), /* @__PURE__ */ React6__default.default.createElement(
|
|
2026
|
+
"div",
|
|
2027
|
+
{
|
|
2028
|
+
className: "text-lg leading-relaxed relative",
|
|
2029
|
+
style: {
|
|
2030
|
+
color: theme.textColor,
|
|
2031
|
+
textShadow: "0 2px 8px rgba(0, 0, 0, 0.5)"
|
|
2032
|
+
}
|
|
2033
|
+
},
|
|
2034
|
+
/* @__PURE__ */ React6__default.default.createElement("span", { className: "inline-block", style: {
|
|
2035
|
+
animation: !isComplete ? "textFadeIn 0.3s ease-out" : "none"
|
|
2036
|
+
} }, displayedText),
|
|
2037
|
+
!isComplete && /* @__PURE__ */ React6__default.default.createElement(
|
|
2038
|
+
"span",
|
|
2039
|
+
{
|
|
2040
|
+
className: "inline-block w-1 h-6 ml-1 align-middle",
|
|
2041
|
+
style: {
|
|
2042
|
+
background: "linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0.6))",
|
|
2043
|
+
animation: "cursorBlink 1s ease-in-out infinite",
|
|
2044
|
+
boxShadow: "0 0 12px rgba(255, 255, 255, 0.8)"
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
)
|
|
2048
|
+
), isComplete && theme.showContinueHint && /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex justify-end mt-4" }, /* @__PURE__ */ React6__default.default.createElement(
|
|
2049
|
+
"span",
|
|
2050
|
+
{
|
|
2051
|
+
className: "text-sm px-4 py-2 rounded-full backdrop-blur-lg font-medium",
|
|
2052
|
+
style: {
|
|
2053
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.15))",
|
|
2054
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
2055
|
+
animation: "bounce 2s ease-in-out infinite",
|
|
2056
|
+
boxShadow: "0 4px 16px rgba(255, 255, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
|
|
2057
|
+
border: "1px solid rgba(255, 255, 255, 0.3)"
|
|
2058
|
+
}
|
|
2059
|
+
},
|
|
2060
|
+
theme.continueHint
|
|
2061
|
+
)))
|
|
2062
|
+
)
|
|
2063
|
+
);
|
|
2064
|
+
if (!isMounted) {
|
|
2065
|
+
return null;
|
|
2066
|
+
}
|
|
2067
|
+
let portalContainer = document.getElementById("dialogue-portal-root");
|
|
2068
|
+
if (!portalContainer) {
|
|
2069
|
+
portalContainer = document.createElement("div");
|
|
2070
|
+
portalContainer.id = "dialogue-portal-root";
|
|
2071
|
+
portalContainer.style.cssText = "position: fixed; inset: 0; pointer-events: none; z-index: 999999;";
|
|
2072
|
+
document.body.appendChild(portalContainer);
|
|
2073
|
+
}
|
|
2074
|
+
return reactDom.createPortal(dialogueContent, portalContainer);
|
|
2075
|
+
};
|
|
2076
|
+
var HistoryPanel = ({
|
|
2077
|
+
history,
|
|
2078
|
+
theme,
|
|
2079
|
+
onClose,
|
|
2080
|
+
className
|
|
2081
|
+
}) => {
|
|
2082
|
+
const [isMounted, setIsMounted] = React6.useState(false);
|
|
2083
|
+
React6.useEffect(() => {
|
|
2084
|
+
setIsMounted(true);
|
|
2085
|
+
}, []);
|
|
2086
|
+
const historyContent = /* @__PURE__ */ React6__default.default.createElement(
|
|
2087
|
+
"div",
|
|
2088
|
+
{
|
|
2089
|
+
className: `fixed inset-0 flex flex-col ${className}`,
|
|
2090
|
+
style: {
|
|
2091
|
+
zIndex: 1,
|
|
2092
|
+
pointerEvents: "auto",
|
|
2093
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.05))"
|
|
2094
|
+
},
|
|
2095
|
+
onClick: onClose
|
|
2096
|
+
},
|
|
2097
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2098
|
+
"div",
|
|
2099
|
+
{
|
|
2100
|
+
className: "absolute inset-0 opacity-25 pointer-events-none",
|
|
2101
|
+
style: {
|
|
2102
|
+
background: `linear-gradient(45deg,
|
|
2103
|
+
rgba(255, 182, 193, 0.15) 0%,
|
|
2104
|
+
rgba(173, 216, 230, 0.15) 25%,
|
|
2105
|
+
rgba(221, 160, 221, 0.15) 50%,
|
|
2106
|
+
rgba(255, 218, 185, 0.15) 75%,
|
|
2107
|
+
rgba(255, 182, 193, 0.15) 100%)`,
|
|
2108
|
+
backgroundSize: "400% 400%",
|
|
2109
|
+
animation: "gradientShift 15s ease infinite"
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
),
|
|
2113
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2114
|
+
"div",
|
|
2115
|
+
{
|
|
2116
|
+
className: "absolute inset-0 pointer-events-none",
|
|
2117
|
+
style: {
|
|
2118
|
+
backdropFilter: "blur(32px) saturate(200%)",
|
|
2119
|
+
WebkitBackdropFilter: "blur(32px) saturate(200%)"
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
),
|
|
2123
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "relative z-10 flex flex-col h-full", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React6__default.default.createElement(
|
|
2124
|
+
"div",
|
|
2125
|
+
{
|
|
2126
|
+
className: "flex items-center justify-between px-8 py-6 border-b relative",
|
|
2127
|
+
style: {
|
|
2128
|
+
borderColor: "rgba(255, 255, 255, 0.25)",
|
|
2129
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
2130
|
+
backdropFilter: "blur(20px)",
|
|
2131
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
2132
|
+
boxShadow: "0 4px 24px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.3)"
|
|
2133
|
+
}
|
|
2134
|
+
},
|
|
2135
|
+
/* @__PURE__ */ React6__default.default.createElement("h2", { className: "text-2xl font-bold text-white flex items-center gap-3" }, /* @__PURE__ */ React6__default.default.createElement("span", { className: "text-3xl" }, "\u{1F4DC}"), /* @__PURE__ */ React6__default.default.createElement("span", { style: { textShadow: "0 2px 12px rgba(255, 255, 255, 0.3)" } }, "\u5BF9\u8BDD\u5386\u53F2")),
|
|
2136
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2137
|
+
"button",
|
|
2138
|
+
{
|
|
2139
|
+
onClick: onClose,
|
|
2140
|
+
className: "p-3 hover:bg-white/20 rounded-2xl transition-all text-white hover:text-white hover:scale-110 active:scale-95",
|
|
2141
|
+
style: {
|
|
2142
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
2143
|
+
backdropFilter: "blur(12px)",
|
|
2144
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
2145
|
+
boxShadow: "0 4px 16px rgba(255, 255, 255, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
|
|
2146
|
+
border: "1px solid rgba(255, 255, 255, 0.25)"
|
|
2147
|
+
},
|
|
2148
|
+
"aria-label": "\u5173\u95ED"
|
|
2149
|
+
},
|
|
2150
|
+
/* @__PURE__ */ React6__default.default.createElement("svg", { className: "w-6 h-6", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ React6__default.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }))
|
|
2151
|
+
)
|
|
2152
|
+
), /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex-1 overflow-y-auto p-6 space-y-4" }, history.length === 0 ? /* @__PURE__ */ React6__default.default.createElement("div", { className: "text-center text-white/70 py-20 text-lg font-medium", style: { textShadow: "0 2px 8px rgba(0, 0, 0, 0.3)" } }, "\u6682\u65E0\u5BF9\u8BDD\u5386\u53F2") : history.map((item, index) => /* @__PURE__ */ React6__default.default.createElement(
|
|
2153
|
+
"div",
|
|
2154
|
+
{
|
|
2155
|
+
key: `${item.nodeIndex}-${item.dialogueIndex}-${index}`,
|
|
2156
|
+
className: "p-6 rounded-2xl transition-all hover:scale-[1.01] relative overflow-hidden cursor-pointer",
|
|
2157
|
+
style: {
|
|
2158
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.1))",
|
|
2159
|
+
backdropFilter: "blur(16px)",
|
|
2160
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
2161
|
+
border: "1px solid rgba(255, 255, 255, 0.2)",
|
|
2162
|
+
boxShadow: "0 8px 24px rgba(255, 255, 255, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.25)"
|
|
2163
|
+
}
|
|
2164
|
+
},
|
|
2165
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2166
|
+
"div",
|
|
2167
|
+
{
|
|
2168
|
+
className: "absolute top-0 left-0 right-0 h-0.5",
|
|
2169
|
+
style: {
|
|
2170
|
+
background: "linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.5), transparent)"
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
),
|
|
2174
|
+
item.speaker && /* @__PURE__ */ React6__default.default.createElement(
|
|
2175
|
+
"div",
|
|
2176
|
+
{
|
|
2177
|
+
className: "inline-block px-5 py-2 rounded-xl mb-3 text-sm font-bold shadow-lg relative overflow-hidden",
|
|
2178
|
+
style: {
|
|
2179
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.2))",
|
|
2180
|
+
backdropFilter: "blur(12px)",
|
|
2181
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
2182
|
+
color: "#ffffff",
|
|
2183
|
+
boxShadow: "0 4px 12px rgba(255, 255, 255, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
|
|
2184
|
+
border: "1px solid rgba(255, 255, 255, 0.25)"
|
|
2185
|
+
}
|
|
2186
|
+
},
|
|
2187
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2188
|
+
"div",
|
|
2189
|
+
{
|
|
2190
|
+
className: "absolute inset-0 opacity-30",
|
|
2191
|
+
style: {
|
|
2192
|
+
background: "linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.4) 50%, transparent 70%)",
|
|
2193
|
+
backgroundSize: "200% 200%",
|
|
2194
|
+
animation: "shimmer 3s infinite"
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
),
|
|
2198
|
+
/* @__PURE__ */ React6__default.default.createElement("span", { className: "relative z-10 drop-shadow-lg" }, item.speaker)
|
|
2199
|
+
),
|
|
2200
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2201
|
+
"p",
|
|
2202
|
+
{
|
|
2203
|
+
className: "text-base leading-relaxed",
|
|
2204
|
+
style: {
|
|
2205
|
+
color: "#ffffff",
|
|
2206
|
+
textShadow: "0 2px 8px rgba(0, 0, 0, 0.3)"
|
|
2207
|
+
}
|
|
2208
|
+
},
|
|
2209
|
+
item.text
|
|
2210
|
+
)
|
|
2211
|
+
))), /* @__PURE__ */ React6__default.default.createElement(
|
|
2212
|
+
"div",
|
|
2213
|
+
{
|
|
2214
|
+
className: "px-8 py-4 border-t text-center",
|
|
2215
|
+
style: {
|
|
2216
|
+
borderColor: "rgba(255, 255, 255, 0.2)",
|
|
2217
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.1))",
|
|
2218
|
+
backdropFilter: "blur(20px)",
|
|
2219
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
2220
|
+
boxShadow: "inset 0 1px 0 rgba(255, 255, 255, 0.2)"
|
|
2221
|
+
}
|
|
2222
|
+
},
|
|
2223
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2224
|
+
"span",
|
|
2225
|
+
{
|
|
2226
|
+
className: "text-sm px-5 py-2.5 rounded-full inline-block font-medium",
|
|
2227
|
+
style: {
|
|
2228
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
2229
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
2230
|
+
backdropFilter: "blur(12px)",
|
|
2231
|
+
WebkitBackdropFilter: "blur(12px)",
|
|
2232
|
+
boxShadow: "0 4px 16px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
|
|
2233
|
+
border: "1px solid rgba(255, 255, 255, 0.25)",
|
|
2234
|
+
textShadow: "0 2px 8px rgba(0, 0, 0, 0.3)"
|
|
2235
|
+
}
|
|
2236
|
+
},
|
|
2237
|
+
"\u70B9\u51FB\u80CC\u666F\u5173\u95ED"
|
|
2238
|
+
)
|
|
2239
|
+
))
|
|
2240
|
+
);
|
|
2241
|
+
if (!isMounted) {
|
|
2242
|
+
return null;
|
|
2243
|
+
}
|
|
2244
|
+
let portalContainer = document.getElementById("history-portal-root");
|
|
2245
|
+
if (!portalContainer) {
|
|
2246
|
+
portalContainer = document.createElement("div");
|
|
2247
|
+
portalContainer.id = "history-portal-root";
|
|
2248
|
+
portalContainer.style.cssText = "position: fixed; inset: 0; pointer-events: none; z-index: 999999;";
|
|
2249
|
+
document.body.appendChild(portalContainer);
|
|
2250
|
+
}
|
|
2251
|
+
return reactDom.createPortal(historyContent, portalContainer);
|
|
2252
|
+
};
|
|
2253
|
+
var LoadingScreen = ({
|
|
2254
|
+
isLoading = true,
|
|
2255
|
+
loadingText = "\u6B63\u5728\u51C6\u5907\u573A\u666F\u4E2D...",
|
|
2256
|
+
className = ""
|
|
2257
|
+
}) => {
|
|
2258
|
+
const [isMounted, setIsMounted] = React6.useState(false);
|
|
2259
|
+
React6.useEffect(() => {
|
|
2260
|
+
setIsMounted(true);
|
|
2261
|
+
}, []);
|
|
2262
|
+
console.log("[LoadingScreen] Render state:", {
|
|
2263
|
+
isLoading,
|
|
2264
|
+
isMounted
|
|
2265
|
+
});
|
|
2266
|
+
if (!isMounted) {
|
|
2267
|
+
return null;
|
|
2268
|
+
}
|
|
2269
|
+
if (!isLoading) {
|
|
2270
|
+
console.log("[LoadingScreen] Not showing, returning null");
|
|
2271
|
+
return null;
|
|
2272
|
+
}
|
|
2273
|
+
const content = /* @__PURE__ */ React6__default.default.createElement(
|
|
2274
|
+
"div",
|
|
2275
|
+
{
|
|
2276
|
+
className: `fixed inset-0 w-screen h-screen flex items-center justify-center ${className}`,
|
|
2277
|
+
style: {
|
|
2278
|
+
zIndex: 999998,
|
|
2279
|
+
pointerEvents: "auto",
|
|
2280
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
2281
|
+
margin: 0,
|
|
2282
|
+
padding: 0
|
|
2283
|
+
}
|
|
2284
|
+
},
|
|
2285
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2286
|
+
"div",
|
|
2287
|
+
{
|
|
2288
|
+
className: "absolute inset-0 w-full h-full pointer-events-none",
|
|
2289
|
+
style: {
|
|
2290
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.1))",
|
|
2291
|
+
backdropFilter: "blur(32px) saturate(200%)",
|
|
2292
|
+
WebkitBackdropFilter: "blur(32px) saturate(200%)"
|
|
2293
|
+
}
|
|
2294
|
+
},
|
|
2295
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2296
|
+
"div",
|
|
2297
|
+
{
|
|
2298
|
+
className: "flex items-center justify-center flex-col inset-0 w-full h-full opacity-25 pointer-events-none",
|
|
2299
|
+
style: {
|
|
2300
|
+
background: `linear-gradient(45deg,
|
|
2301
|
+
rgba(255, 182, 193, 0.2) 0%,
|
|
2302
|
+
rgba(173, 216, 230, 0.2) 25%,
|
|
2303
|
+
rgba(221, 160, 221, 0.2) 50%,
|
|
2304
|
+
rgba(255, 218, 185, 0.2) 75%,
|
|
2305
|
+
rgba(255, 182, 193, 0.2) 100%)`,
|
|
2306
|
+
backgroundSize: "400% 400%",
|
|
2307
|
+
animation: "gradientShift 15s ease infinite"
|
|
2308
|
+
}
|
|
2309
|
+
},
|
|
2310
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2311
|
+
"div",
|
|
2312
|
+
{
|
|
2313
|
+
className: "text-lg font-medium text-white text-center px-6 py-3 rounded-2xl"
|
|
2314
|
+
},
|
|
2315
|
+
loadingText
|
|
2316
|
+
)
|
|
2317
|
+
)
|
|
2318
|
+
)
|
|
2319
|
+
);
|
|
2320
|
+
let portalContainer = document.getElementById("loading-screen-portal-root");
|
|
2321
|
+
if (!portalContainer) {
|
|
2322
|
+
portalContainer = document.createElement("div");
|
|
2323
|
+
portalContainer.id = "loading-screen-portal-root";
|
|
2324
|
+
document.body.appendChild(portalContainer);
|
|
2325
|
+
}
|
|
2326
|
+
portalContainer.style.cssText = `
|
|
2327
|
+
position: fixed;
|
|
2328
|
+
top: 0;
|
|
2329
|
+
left: 0;
|
|
2330
|
+
right: 0;
|
|
2331
|
+
bottom: 0;
|
|
2332
|
+
width: 100vw;
|
|
2333
|
+
height: 100vh;
|
|
2334
|
+
margin: 0;
|
|
2335
|
+
padding: 0;
|
|
2336
|
+
overflow: hidden;
|
|
2337
|
+
z-index: 999998;
|
|
2338
|
+
pointer-events: none;
|
|
2339
|
+
`.replace(/\s+/g, " ").trim();
|
|
2340
|
+
return reactDom.createPortal(content, portalContainer);
|
|
2341
|
+
};
|
|
2342
|
+
LoadingScreen.displayName = "LoadingScreen";
|
|
2343
|
+
var StartScreen = ({
|
|
2344
|
+
showStartScreen = false,
|
|
2345
|
+
scriptName = "",
|
|
2346
|
+
startText = "\u70B9\u51FB\u5F00\u59CB",
|
|
2347
|
+
onStart,
|
|
2348
|
+
className = ""
|
|
2349
|
+
}) => {
|
|
2350
|
+
const [isMounted, setIsMounted] = React6.useState(false);
|
|
2351
|
+
React6.useEffect(() => {
|
|
2352
|
+
setIsMounted(true);
|
|
2353
|
+
}, []);
|
|
2354
|
+
console.log("[StartScreen] Render state:", {
|
|
2355
|
+
showStartScreen,
|
|
2356
|
+
scriptName,
|
|
2357
|
+
isMounted
|
|
2358
|
+
});
|
|
2359
|
+
if (!isMounted) {
|
|
2360
|
+
return null;
|
|
2361
|
+
}
|
|
2362
|
+
if (!showStartScreen) {
|
|
2363
|
+
console.log("[StartScreen] Not showing, returning null");
|
|
2364
|
+
return null;
|
|
2365
|
+
}
|
|
2366
|
+
const content = /* @__PURE__ */ React6__default.default.createElement(
|
|
2367
|
+
"div",
|
|
2368
|
+
{
|
|
2369
|
+
className: `fixed inset-0 w-screen h-screen flex items-center justify-center cursor-pointer ${className}`,
|
|
2370
|
+
style: {
|
|
2371
|
+
zIndex: 999999,
|
|
2372
|
+
pointerEvents: "auto",
|
|
2373
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
2374
|
+
margin: 0,
|
|
2375
|
+
padding: 0
|
|
2376
|
+
},
|
|
2377
|
+
onClick: onStart
|
|
2378
|
+
},
|
|
2379
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2380
|
+
"div",
|
|
2381
|
+
{
|
|
2382
|
+
className: "absolute inset-0 w-full h-full pointer-events-none",
|
|
2383
|
+
style: {
|
|
2384
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
2385
|
+
backdropFilter: "blur(40px) saturate(200%)",
|
|
2386
|
+
WebkitBackdropFilter: "blur(40px) saturate(200%)"
|
|
2387
|
+
}
|
|
2388
|
+
},
|
|
2389
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2390
|
+
"div",
|
|
2391
|
+
{
|
|
2392
|
+
className: "flex items-center justify-center flex-col inset-0 w-full h-full opacity-30 pointer-events-none",
|
|
2393
|
+
style: {
|
|
2394
|
+
background: `linear-gradient(45deg,
|
|
2395
|
+
rgba(255, 182, 193, 0.25) 0%,
|
|
2396
|
+
rgba(173, 216, 230, 0.25) 25%,
|
|
2397
|
+
rgba(221, 160, 221, 0.25) 50%,
|
|
2398
|
+
rgba(255, 218, 185, 0.25) 75%,
|
|
2399
|
+
rgba(255, 182, 193, 0.25) 100%)`,
|
|
2400
|
+
backgroundSize: "400% 400%",
|
|
2401
|
+
animation: "gradientShift 15s ease infinite"
|
|
2402
|
+
}
|
|
2403
|
+
},
|
|
2404
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2405
|
+
"div",
|
|
2406
|
+
{
|
|
2407
|
+
className: "relative z-10 text-center px-16 py-14 rounded-3xl max-w-2xl mx-auto transform transition-all hover:scale-105",
|
|
2408
|
+
style: {
|
|
2409
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.15))",
|
|
2410
|
+
backdropFilter: "blur(24px)",
|
|
2411
|
+
WebkitBackdropFilter: "blur(24px)",
|
|
2412
|
+
border: "2px solid rgba(255, 255, 255, 0.3)",
|
|
2413
|
+
boxShadow: `
|
|
2414
|
+
0 12px 48px rgba(255, 255, 255, 0.15),
|
|
2415
|
+
0 4px 16px rgba(255, 255, 255, 0.1),
|
|
2416
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.4)
|
|
2417
|
+
`
|
|
2418
|
+
}
|
|
2419
|
+
},
|
|
2420
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2421
|
+
"div",
|
|
2422
|
+
{
|
|
2423
|
+
className: "absolute top-0 left-0 right-0 h-1 margin-auto",
|
|
2424
|
+
style: {
|
|
2425
|
+
background: "linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent)"
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
),
|
|
2429
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2430
|
+
"h1",
|
|
2431
|
+
{
|
|
2432
|
+
className: "text-5xl font-bold text-white mb-8 relative",
|
|
2433
|
+
style: {
|
|
2434
|
+
textShadow: "0 4px 16px rgba(255, 255, 255, 0.3), 0 2px 8px rgba(0, 0, 0, 0.5)"
|
|
2435
|
+
}
|
|
2436
|
+
},
|
|
2437
|
+
scriptName,
|
|
2438
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2439
|
+
"div",
|
|
2440
|
+
{
|
|
2441
|
+
className: "absolute -bottom-3 left-1/2 transform -translate-x-1/2 h-1 rounded-full",
|
|
2442
|
+
style: {
|
|
2443
|
+
width: "60%",
|
|
2444
|
+
background: "linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.5), transparent)"
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
)
|
|
2448
|
+
),
|
|
2449
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2450
|
+
"div",
|
|
2451
|
+
{
|
|
2452
|
+
className: "inline-block px-10 py-4 rounded-2xl font-bold text-xl text-white transition-all hover:scale-110 active:scale-95",
|
|
2453
|
+
style: {
|
|
2454
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0.25))",
|
|
2455
|
+
backdropFilter: "blur(16px)",
|
|
2456
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
2457
|
+
border: "2px solid rgba(255, 255, 255, 0.4)",
|
|
2458
|
+
boxShadow: `
|
|
2459
|
+
0 8px 32px rgba(255, 255, 255, 0.2),
|
|
2460
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.5)
|
|
2461
|
+
`,
|
|
2462
|
+
textShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
|
|
2463
|
+
animation: "pulse 2s ease-in-out infinite"
|
|
2464
|
+
}
|
|
2465
|
+
},
|
|
2466
|
+
/* @__PURE__ */ React6__default.default.createElement("span", { className: "relative z-10" }, startText)
|
|
2467
|
+
),
|
|
2468
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2469
|
+
"div",
|
|
2470
|
+
{
|
|
2471
|
+
className: "absolute bottom-0 left-0 right-0 h-px",
|
|
2472
|
+
style: {
|
|
2473
|
+
background: "linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent)"
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
)
|
|
2477
|
+
)
|
|
2478
|
+
)
|
|
2479
|
+
)
|
|
2480
|
+
);
|
|
2481
|
+
let portalContainer = document.getElementById("start-screen-portal-root");
|
|
2482
|
+
if (!portalContainer) {
|
|
2483
|
+
portalContainer = document.createElement("div");
|
|
2484
|
+
portalContainer.id = "start-screen-portal-root";
|
|
2485
|
+
document.body.appendChild(portalContainer);
|
|
2486
|
+
}
|
|
2487
|
+
portalContainer.style.cssText = `
|
|
2488
|
+
position: fixed;
|
|
2489
|
+
top: 0;
|
|
2490
|
+
left: 0;
|
|
2491
|
+
right: 0;
|
|
2492
|
+
bottom: 0;
|
|
2493
|
+
width: 100vw;
|
|
2494
|
+
height: 100vh;
|
|
2495
|
+
margin: 0;
|
|
2496
|
+
padding: 0;
|
|
2497
|
+
overflow: hidden;
|
|
2498
|
+
z-index: 999999;
|
|
2499
|
+
pointer-events: none;
|
|
2500
|
+
`.replace(/\s+/g, " ").trim();
|
|
2501
|
+
return reactDom.createPortal(content, portalContainer);
|
|
2502
|
+
};
|
|
2503
|
+
StartScreen.displayName = "StartScreen";
|
|
2504
|
+
|
|
2505
|
+
// src/mmd/visual-novel/LoadingOverlay.tsx
|
|
2506
|
+
if (typeof document !== "undefined" && !document.getElementById("loading-overlay-animations")) {
|
|
2507
|
+
const style = document.createElement("style");
|
|
2508
|
+
style.id = "loading-overlay-animations";
|
|
2509
|
+
style.textContent = `
|
|
2510
|
+
@keyframes gradientShift {
|
|
2511
|
+
0%, 100% { background-position: 0% 50%; }
|
|
2512
|
+
50% { background-position: 100% 50%; }
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
@keyframes pulse {
|
|
2516
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
2517
|
+
50% { opacity: 0.9; transform: scale(1.05); }
|
|
2518
|
+
}
|
|
2519
|
+
`;
|
|
2520
|
+
document.head.appendChild(style);
|
|
2521
|
+
}
|
|
2522
|
+
var LoadingOverlay = ({
|
|
2523
|
+
isLoading = true,
|
|
2524
|
+
showStartScreen = false,
|
|
2525
|
+
scriptName = "",
|
|
2526
|
+
loadingText = "\u6B63\u5728\u51C6\u5907\u573A\u666F\u4E2D...",
|
|
2527
|
+
startText = "\u70B9\u51FB\u5F00\u59CB",
|
|
2528
|
+
onStart,
|
|
2529
|
+
className = ""
|
|
2530
|
+
}) => {
|
|
2531
|
+
return /* @__PURE__ */ React6__default.default.createElement(React6__default.default.Fragment, null, /* @__PURE__ */ React6__default.default.createElement(
|
|
2532
|
+
LoadingScreen,
|
|
2533
|
+
{
|
|
2534
|
+
isLoading,
|
|
2535
|
+
loadingText,
|
|
2536
|
+
className
|
|
2537
|
+
}
|
|
2538
|
+
), /* @__PURE__ */ React6__default.default.createElement(
|
|
2539
|
+
StartScreen,
|
|
2540
|
+
{
|
|
2541
|
+
showStartScreen,
|
|
2542
|
+
scriptName,
|
|
2543
|
+
startText,
|
|
2544
|
+
onStart,
|
|
2545
|
+
className
|
|
2546
|
+
}
|
|
2547
|
+
));
|
|
2548
|
+
};
|
|
2549
|
+
LoadingOverlay.displayName = "LoadingOverlay";
|
|
2550
|
+
|
|
2551
|
+
// src/mmd/visual-novel/MMDVisualNovel.tsx
|
|
2552
|
+
var MMDVisualNovel = React6.forwardRef(
|
|
2553
|
+
({
|
|
2554
|
+
script,
|
|
2555
|
+
stage,
|
|
2556
|
+
mobileOptimization,
|
|
2557
|
+
dialogueTheme,
|
|
2558
|
+
autoStart = false,
|
|
2559
|
+
initialNodeIndex = 0,
|
|
2560
|
+
initialDialogueIndex = 0,
|
|
2561
|
+
onNodeChange,
|
|
2562
|
+
onDialogueChange,
|
|
2563
|
+
onScriptComplete,
|
|
2564
|
+
onError,
|
|
2565
|
+
showDebugInfo = false,
|
|
2566
|
+
showSkipButton = true,
|
|
2567
|
+
showAutoButton = true,
|
|
2568
|
+
showHistoryButton = true,
|
|
2569
|
+
className,
|
|
2570
|
+
style
|
|
2571
|
+
}, ref) => {
|
|
2572
|
+
const { nodes, loop = false } = script;
|
|
2573
|
+
const [currentNodeIndex, setCurrentNodeIndex] = React6.useState(initialNodeIndex);
|
|
2574
|
+
const [currentDialogueIndex, setCurrentDialogueIndex] = React6.useState(initialDialogueIndex);
|
|
2575
|
+
const [isLoading, setIsLoading] = React6.useState(true);
|
|
2576
|
+
const [isAnimationPlaying, setIsAnimationPlaying] = React6.useState(false);
|
|
2577
|
+
const [isTransitioning, setIsTransitioning] = React6.useState(false);
|
|
2578
|
+
const [isAutoMode, setIsAutoMode] = React6.useState(false);
|
|
2579
|
+
const [isTyping, setIsTyping] = React6.useState(false);
|
|
2580
|
+
const [showHistory, setShowHistory] = React6.useState(false);
|
|
2581
|
+
const [history, setHistory] = React6.useState([]);
|
|
2582
|
+
const [isStarted, setIsStarted] = React6.useState(autoStart);
|
|
2583
|
+
const playerRef = React6.useRef(null);
|
|
2584
|
+
const containerRef = React6.useRef(null);
|
|
2585
|
+
const autoTimerRef = React6.useRef(null);
|
|
2586
|
+
const typingCompleteRef = React6.useRef(false);
|
|
2587
|
+
const isStartedRef = React6.useRef(autoStart);
|
|
2588
|
+
const currentNode = nodes[currentNodeIndex];
|
|
2589
|
+
const currentDialogue = currentNode?.dialogues[currentDialogueIndex] || null;
|
|
2590
|
+
const addToHistory = React6.useCallback((dialogue, nodeIndex, dialogueIndex) => {
|
|
2591
|
+
setHistory((prev) => [
|
|
2592
|
+
...prev,
|
|
2593
|
+
{
|
|
2594
|
+
nodeIndex,
|
|
2595
|
+
dialogueIndex,
|
|
2596
|
+
speaker: dialogue.speaker,
|
|
2597
|
+
text: dialogue.text,
|
|
2598
|
+
timestamp: Date.now()
|
|
2599
|
+
}
|
|
2600
|
+
]);
|
|
2601
|
+
}, []);
|
|
2602
|
+
const goToNextDialogue = React6.useCallback(() => {
|
|
2603
|
+
if (!currentNode) return;
|
|
2604
|
+
if (autoTimerRef.current) {
|
|
2605
|
+
clearTimeout(autoTimerRef.current);
|
|
2606
|
+
autoTimerRef.current = null;
|
|
2607
|
+
}
|
|
2608
|
+
const nextDialogueIndex = currentDialogueIndex + 1;
|
|
2609
|
+
if (nextDialogueIndex < currentNode.dialogues.length && currentNode?.dialogues[nextDialogueIndex] !== void 0) {
|
|
2610
|
+
const nextDialogue = currentNode.dialogues[nextDialogueIndex];
|
|
2611
|
+
setCurrentDialogueIndex(nextDialogueIndex);
|
|
2612
|
+
addToHistory(nextDialogue, currentNodeIndex, nextDialogueIndex);
|
|
2613
|
+
onDialogueChange?.(nextDialogue, nextDialogueIndex, currentNodeIndex);
|
|
2614
|
+
typingCompleteRef.current = false;
|
|
2615
|
+
} else {
|
|
2616
|
+
const nextNodeIndex = currentNodeIndex + 1;
|
|
2617
|
+
if (nextNodeIndex < nodes.length) {
|
|
2618
|
+
goToNode(nextNodeIndex);
|
|
2619
|
+
} else if (loop) {
|
|
2620
|
+
goToNode(0);
|
|
2621
|
+
} else {
|
|
2622
|
+
onScriptComplete?.();
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}, [currentNode, currentDialogueIndex, currentNodeIndex, nodes.length, loop, addToHistory, onDialogueChange, onScriptComplete]);
|
|
2626
|
+
const goToNode = React6.useCallback(
|
|
2627
|
+
(nodeIndex) => {
|
|
2628
|
+
if (nodeIndex < 0 || nodeIndex >= nodes.length) return;
|
|
2629
|
+
if (isTransitioning) return;
|
|
2630
|
+
const node = nodes[nodeIndex];
|
|
2631
|
+
if (!node) return;
|
|
2632
|
+
console.log(`[MMDVisualNovel] Transitioning to node ${nodeIndex}`);
|
|
2633
|
+
setIsTransitioning(true);
|
|
2634
|
+
setIsLoading(true);
|
|
2635
|
+
setIsAnimationPlaying(false);
|
|
2636
|
+
setTimeout(() => {
|
|
2637
|
+
setCurrentNodeIndex(nodeIndex);
|
|
2638
|
+
setCurrentDialogueIndex(0);
|
|
2639
|
+
typingCompleteRef.current = false;
|
|
2640
|
+
if (node.dialogues.length > 0 && node?.dialogues[0] !== void 0) {
|
|
2641
|
+
addToHistory(node.dialogues[0], nodeIndex, 0);
|
|
2642
|
+
}
|
|
2643
|
+
onNodeChange?.(node, nodeIndex);
|
|
2644
|
+
if (node.dialogues.length > 0 && node?.dialogues[0] !== void 0) {
|
|
2645
|
+
onDialogueChange?.(node.dialogues[0], 0, nodeIndex);
|
|
2646
|
+
}
|
|
2647
|
+
setTimeout(() => {
|
|
2648
|
+
setIsTransitioning(false);
|
|
2649
|
+
console.log(`[MMDVisualNovel] Transition to node ${nodeIndex} completed, waiting for model load`);
|
|
2650
|
+
}, 100);
|
|
2651
|
+
}, 300);
|
|
2652
|
+
},
|
|
2653
|
+
[nodes, isTransitioning, addToHistory, onNodeChange, onDialogueChange]
|
|
2654
|
+
);
|
|
2655
|
+
const goToDialogue = React6.useCallback(
|
|
2656
|
+
(dialogueIndex) => {
|
|
2657
|
+
if (!currentNode) return;
|
|
2658
|
+
const dialogue = currentNode.dialogues[dialogueIndex];
|
|
2659
|
+
if (dialogueIndex < 0 || dialogueIndex >= currentNode.dialogues.length || dialogue === void 0) return;
|
|
2660
|
+
setCurrentDialogueIndex(dialogueIndex);
|
|
2661
|
+
addToHistory(dialogue, currentNodeIndex, dialogueIndex);
|
|
2662
|
+
onDialogueChange?.(dialogue, dialogueIndex, currentNodeIndex);
|
|
2663
|
+
typingCompleteRef.current = false;
|
|
2664
|
+
},
|
|
2665
|
+
[currentNode, currentNodeIndex, addToHistory, onDialogueChange]
|
|
2666
|
+
);
|
|
2667
|
+
const handleDialogueClick = React6.useCallback(() => {
|
|
2668
|
+
if (!typingCompleteRef.current) {
|
|
2669
|
+
typingCompleteRef.current = true;
|
|
2670
|
+
return;
|
|
2671
|
+
}
|
|
2672
|
+
goToNextDialogue();
|
|
2673
|
+
}, [goToNextDialogue]);
|
|
2674
|
+
const handleTypingComplete = React6.useCallback(() => {
|
|
2675
|
+
typingCompleteRef.current = true;
|
|
2676
|
+
setIsTyping(false);
|
|
2677
|
+
if (isAutoMode || currentDialogue?.waitForClick === false) {
|
|
2678
|
+
const delay = currentDialogue?.autoDelay ?? 2e3;
|
|
2679
|
+
autoTimerRef.current = setTimeout(() => {
|
|
2680
|
+
goToNextDialogue();
|
|
2681
|
+
}, delay);
|
|
2682
|
+
}
|
|
2683
|
+
}, [isAutoMode, currentDialogue, goToNextDialogue]);
|
|
2684
|
+
React6.useEffect(() => {
|
|
2685
|
+
if (currentDialogue) {
|
|
2686
|
+
setIsTyping(true);
|
|
2687
|
+
typingCompleteRef.current = false;
|
|
2688
|
+
const text = currentDialogue.text;
|
|
2689
|
+
const speed = currentDialogue.typeSpeed ?? 50;
|
|
2690
|
+
const typingDuration = text.length * speed;
|
|
2691
|
+
const timer = setTimeout(() => {
|
|
2692
|
+
handleTypingComplete();
|
|
2693
|
+
}, typingDuration);
|
|
2694
|
+
return () => clearTimeout(timer);
|
|
2695
|
+
}
|
|
2696
|
+
return void 0;
|
|
2697
|
+
}, [currentDialogue, handleTypingComplete]);
|
|
2698
|
+
const toggleAutoMode = React6.useCallback(() => {
|
|
2699
|
+
setIsAutoMode((prev) => !prev);
|
|
2700
|
+
}, []);
|
|
2701
|
+
const handleSkip = React6.useCallback(() => {
|
|
2702
|
+
const nextNodeIndex = currentNodeIndex + 1;
|
|
2703
|
+
if (nextNodeIndex < nodes.length) {
|
|
2704
|
+
goToNode(nextNodeIndex);
|
|
2705
|
+
} else if (loop) {
|
|
2706
|
+
goToNode(0);
|
|
2707
|
+
} else {
|
|
2708
|
+
onScriptComplete?.();
|
|
2709
|
+
}
|
|
2710
|
+
}, [currentNodeIndex, nodes.length, loop, goToNode, onScriptComplete]);
|
|
2711
|
+
const handleStart = React6.useCallback(() => {
|
|
2712
|
+
setIsStarted(true);
|
|
2713
|
+
isStartedRef.current = true;
|
|
2714
|
+
if (currentNode && currentNode.dialogues.length > 0 && currentNode?.dialogues[0] !== void 0) {
|
|
2715
|
+
addToHistory(currentNode?.dialogues[0], currentNodeIndex, 0);
|
|
2716
|
+
}
|
|
2717
|
+
setTimeout(() => {
|
|
2718
|
+
playerRef.current?.play();
|
|
2719
|
+
}, 100);
|
|
2720
|
+
}, [currentNode, currentNodeIndex, addToHistory]);
|
|
2721
|
+
React6.useImperativeHandle(
|
|
2722
|
+
ref,
|
|
2723
|
+
() => ({
|
|
2724
|
+
goToNode,
|
|
2725
|
+
goToDialogue,
|
|
2726
|
+
getCurrentNodeIndex: () => currentNodeIndex,
|
|
2727
|
+
getCurrentDialogueIndex: () => currentDialogueIndex,
|
|
2728
|
+
getHistory: () => history,
|
|
2729
|
+
setAutoMode: setIsAutoMode,
|
|
2730
|
+
skipTyping: () => {
|
|
2731
|
+
typingCompleteRef.current = true;
|
|
2732
|
+
}
|
|
2733
|
+
}),
|
|
2734
|
+
[goToNode, goToDialogue, currentNodeIndex, currentDialogueIndex, history]
|
|
2735
|
+
);
|
|
2736
|
+
React6.useEffect(() => {
|
|
2737
|
+
if (autoStart && currentNode && currentNode.dialogues.length > 0 && history.length === 0 && currentNode?.dialogues[0] !== void 0) {
|
|
2738
|
+
addToHistory(currentNode?.dialogues[0], currentNodeIndex, 0);
|
|
2739
|
+
}
|
|
2740
|
+
}, [autoStart, currentNode, currentNodeIndex, history.length, addToHistory]);
|
|
2741
|
+
React6.useEffect(() => {
|
|
2742
|
+
return () => {
|
|
2743
|
+
if (autoTimerRef.current) {
|
|
2744
|
+
clearTimeout(autoTimerRef.current);
|
|
2745
|
+
}
|
|
2746
|
+
};
|
|
2747
|
+
}, []);
|
|
2748
|
+
if (!currentNode) {
|
|
2749
|
+
return /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex h-full w-full items-center justify-center bg-black text-white" }, "\u5267\u672C\u4E3A\u7A7A");
|
|
2750
|
+
}
|
|
2751
|
+
return /* @__PURE__ */ React6__default.default.createElement(
|
|
2752
|
+
"div",
|
|
2753
|
+
{
|
|
2754
|
+
ref: containerRef,
|
|
2755
|
+
className: `relative bg-black ${className}`,
|
|
2756
|
+
style: { width: "100%", height: "100%", overflow: "hidden", ...style }
|
|
2757
|
+
},
|
|
2758
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2759
|
+
"div",
|
|
2760
|
+
{
|
|
2761
|
+
className: "absolute inset-0 w-full h-full",
|
|
2762
|
+
style: {
|
|
2763
|
+
zIndex: 0,
|
|
2764
|
+
// 在加载期间隐藏,避免看到模型加载过程
|
|
2765
|
+
opacity: isLoading || isTransitioning || !isAnimationPlaying ? 0 : 1,
|
|
2766
|
+
transition: "opacity 0.3s ease-in-out"
|
|
2767
|
+
}
|
|
2768
|
+
},
|
|
2769
|
+
!isTransitioning && /* @__PURE__ */ React6__default.default.createElement(
|
|
2770
|
+
MMDPlayerBase,
|
|
2771
|
+
{
|
|
2772
|
+
key: currentNode.id,
|
|
2773
|
+
ref: playerRef,
|
|
2774
|
+
resources: currentNode.resources,
|
|
2775
|
+
stage,
|
|
2776
|
+
autoPlay: isStarted,
|
|
2777
|
+
loop: currentNode.loopAnimation === true,
|
|
2778
|
+
mobileOptimization,
|
|
2779
|
+
onLoad: () => {
|
|
2780
|
+
console.log("[MMDVisualNovel] MMDPlayerBase onLoad called");
|
|
2781
|
+
setIsLoading(false);
|
|
2782
|
+
if (isStartedRef.current) {
|
|
2783
|
+
console.log("[MMDVisualNovel] Game already started, triggering play");
|
|
2784
|
+
setTimeout(() => {
|
|
2785
|
+
playerRef.current?.play();
|
|
2786
|
+
}, 100);
|
|
2787
|
+
}
|
|
2788
|
+
},
|
|
2789
|
+
onPlay: () => {
|
|
2790
|
+
console.log("[MMDVisualNovel] MMDPlayerBase onPlay called");
|
|
2791
|
+
setIsAnimationPlaying(true);
|
|
2792
|
+
},
|
|
2793
|
+
onError
|
|
2794
|
+
}
|
|
2795
|
+
)
|
|
2796
|
+
),
|
|
2797
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2798
|
+
LoadingOverlay,
|
|
2799
|
+
{
|
|
2800
|
+
isLoading: (() => {
|
|
2801
|
+
const shouldShowLoading = (isLoading || isTransitioning || !isAnimationPlaying) && isStarted;
|
|
2802
|
+
console.log("[MMDVisualNovel] LoadingOverlay conditions:", {
|
|
2803
|
+
isLoading,
|
|
2804
|
+
isTransitioning,
|
|
2805
|
+
isAnimationPlaying,
|
|
2806
|
+
isStarted,
|
|
2807
|
+
shouldShowLoading
|
|
2808
|
+
});
|
|
2809
|
+
return shouldShowLoading;
|
|
2810
|
+
})(),
|
|
2811
|
+
showStartScreen: !isStarted,
|
|
2812
|
+
scriptName: script.name,
|
|
2813
|
+
loadingText: "\u6B63\u5728\u51C6\u5907\u573A\u666F\u4E2D...",
|
|
2814
|
+
startText: "\u70B9\u51FB\u5F00\u59CB",
|
|
2815
|
+
onStart: handleStart
|
|
2816
|
+
}
|
|
2817
|
+
),
|
|
2818
|
+
(() => {
|
|
2819
|
+
const shouldShow = isStarted && isAnimationPlaying && currentDialogue && !showHistory;
|
|
2820
|
+
console.log("[MMDVisualNovel] DialogueBox render condition:", {
|
|
2821
|
+
isStarted,
|
|
2822
|
+
isAnimationPlaying,
|
|
2823
|
+
hasDialogue: !!currentDialogue,
|
|
2824
|
+
showHistory,
|
|
2825
|
+
shouldShow,
|
|
2826
|
+
dialogue: currentDialogue
|
|
2827
|
+
});
|
|
2828
|
+
return shouldShow ? /* @__PURE__ */ React6__default.default.createElement(
|
|
2829
|
+
DialogueBox,
|
|
2830
|
+
{
|
|
2831
|
+
dialogue: currentDialogue,
|
|
2832
|
+
theme: dialogueTheme,
|
|
2833
|
+
isTyping,
|
|
2834
|
+
isAutoMode,
|
|
2835
|
+
onClick: handleDialogueClick,
|
|
2836
|
+
onSkipTyping: () => {
|
|
2837
|
+
typingCompleteRef.current = true;
|
|
2838
|
+
},
|
|
2839
|
+
onToggleAuto: toggleAutoMode,
|
|
2840
|
+
onOpenHistory: () => setShowHistory(true),
|
|
2841
|
+
onSkip: handleSkip,
|
|
2842
|
+
showControls: true,
|
|
2843
|
+
showSkipButton,
|
|
2844
|
+
showAutoButton,
|
|
2845
|
+
showHistoryButton
|
|
2846
|
+
}
|
|
2847
|
+
) : null;
|
|
2848
|
+
})(),
|
|
2849
|
+
showHistory && /* @__PURE__ */ React6__default.default.createElement(
|
|
2850
|
+
HistoryPanel,
|
|
2851
|
+
{
|
|
2852
|
+
history,
|
|
2853
|
+
theme: dialogueTheme,
|
|
2854
|
+
onClose: () => setShowHistory(false)
|
|
2855
|
+
}
|
|
2856
|
+
)
|
|
2857
|
+
);
|
|
2858
|
+
}
|
|
2859
|
+
);
|
|
2860
|
+
MMDVisualNovel.displayName = "MMDVisualNovel";
|
|
1616
2861
|
|
|
2862
|
+
exports.DialogueBox = DialogueBox;
|
|
2863
|
+
exports.HistoryPanel = HistoryPanel;
|
|
2864
|
+
exports.LoadingOverlay = LoadingOverlay;
|
|
2865
|
+
exports.LoadingScreen = LoadingScreen;
|
|
1617
2866
|
exports.MMDPlayerBase = MMDPlayerBase;
|
|
1618
2867
|
exports.MMDPlayerEnhanced = MMDPlayerEnhanced;
|
|
1619
2868
|
exports.MMDPlayerEnhancedDebugInfo = MMDPlayerEnhancedDebugInfo;
|
|
1620
2869
|
exports.MMDPlaylist = MMDPlaylist;
|
|
1621
2870
|
exports.MMDPlaylistDebugInfo = MMDPlaylistDebugInfo;
|
|
2871
|
+
exports.MMDVisualNovel = MMDVisualNovel;
|
|
2872
|
+
exports.StartScreen = StartScreen;
|
|
1622
2873
|
exports.loadAmmo = loadAmmo;
|
|
1623
2874
|
//# sourceMappingURL=index.js.map
|
|
1624
2875
|
//# sourceMappingURL=index.js.map
|