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.
Files changed (53) hide show
  1. package/dist/{UniversalFileService-C1rUWWU-.d.ts → UniversalFileService-BuHN-jrR.d.ts} +46 -2
  2. package/dist/{UniversalFileService-DrCK0-NL.d.mts → UniversalFileService-CGGzYeeF.d.mts} +46 -2
  3. package/dist/{chunk-3XG5OHFD.mjs → chunk-CIVO4R6N.mjs} +2 -2
  4. package/dist/{chunk-3XG5OHFD.mjs.map → chunk-CIVO4R6N.mjs.map} +1 -1
  5. package/dist/chunk-EV6BCVOQ.mjs +204 -0
  6. package/dist/chunk-EV6BCVOQ.mjs.map +1 -0
  7. package/dist/chunk-W35VTQAW.js +211 -0
  8. package/dist/chunk-W35VTQAW.js.map +1 -0
  9. package/dist/{chunk-HWJ34NL6.js → chunk-ZRAW3HXA.js} +2 -2
  10. package/dist/{chunk-HWJ34NL6.js.map → chunk-ZRAW3HXA.js.map} +1 -1
  11. package/dist/drizzle-schema-BNhqj2AZ.d.mts +1114 -0
  12. package/dist/drizzle-schema-BNhqj2AZ.d.ts +1114 -0
  13. package/dist/mmd/admin/index.d.mts +8 -1115
  14. package/dist/mmd/admin/index.d.ts +8 -1115
  15. package/dist/mmd/admin/index.js +98 -248
  16. package/dist/mmd/admin/index.js.map +1 -1
  17. package/dist/mmd/admin/index.mjs +75 -244
  18. package/dist/mmd/admin/index.mjs.map +1 -1
  19. package/dist/mmd/index.d.mts +265 -3
  20. package/dist/mmd/index.d.ts +265 -3
  21. package/dist/mmd/index.js +1266 -15
  22. package/dist/mmd/index.js.map +1 -1
  23. package/dist/mmd/index.mjs +1261 -16
  24. package/dist/mmd/index.mjs.map +1 -1
  25. package/dist/mmd/server/index.d.mts +138 -0
  26. package/dist/mmd/server/index.d.ts +138 -0
  27. package/dist/mmd/server/index.js +245 -0
  28. package/dist/mmd/server/index.js.map +1 -0
  29. package/dist/mmd/server/index.mjs +207 -0
  30. package/dist/mmd/server/index.mjs.map +1 -0
  31. package/dist/testYourself/index.d.mts +145 -0
  32. package/dist/testYourself/index.d.ts +145 -0
  33. package/dist/testYourself/index.js +1004 -0
  34. package/dist/testYourself/index.js.map +1 -0
  35. package/dist/testYourself/index.mjs +993 -0
  36. package/dist/testYourself/index.mjs.map +1 -0
  37. package/dist/{types-C2ale3d9.d.mts → types-Bc_p-zAR.d.mts} +1 -1
  38. package/dist/{types-C2ale3d9.d.ts → types-Bc_p-zAR.d.ts} +1 -1
  39. package/dist/{types-Dg-U_chI.d.mts → types-CK4We_aI.d.mts} +13 -1
  40. package/dist/{types-Dg-U_chI.d.ts → types-CK4We_aI.d.ts} +13 -1
  41. package/dist/universalFile/index.d.mts +3 -3
  42. package/dist/universalFile/index.d.ts +3 -3
  43. package/dist/universalFile/index.js +48 -10
  44. package/dist/universalFile/index.js.map +1 -1
  45. package/dist/universalFile/index.mjs +43 -5
  46. package/dist/universalFile/index.mjs.map +1 -1
  47. package/dist/universalFile/server/index.d.mts +3 -3
  48. package/dist/universalFile/server/index.d.ts +3 -3
  49. package/dist/universalFile/server/index.js +239 -7
  50. package/dist/universalFile/server/index.js.map +1 -1
  51. package/dist/universalFile/server/index.mjs +234 -2
  52. package/dist/universalFile/server/index.mjs.map +1 -1
  53. 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
- renderer.setPixelRatio(mobileOptimization.enabled ? mobileOptimization.pixelRatio || 1 : window.devicePixelRatio);
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
- loader.load(
432
- resources.stageModelPath,
433
- (stageMesh) => {
434
- if (checkCancelled()) return;
435
- stageMesh.castShadow = true;
436
- stageMesh.receiveShadow = true;
437
- scene.add(stageMesh);
438
- },
439
- void 0,
440
- (err) => console.error("Failed to load stage:", err)
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