sa2kit 1.6.14 → 1.6.15

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 (43) hide show
  1. package/dist/audioDetection/index.js.map +1 -1
  2. package/dist/audioDetection/index.mjs.map +1 -1
  3. package/dist/auth/index.js +3 -3
  4. package/dist/auth/index.mjs +1 -1
  5. package/dist/{chunk-GGGTJETD.mjs → chunk-3WOAPLEG.mjs} +3 -3
  6. package/dist/{chunk-GGGTJETD.mjs.map → chunk-3WOAPLEG.mjs.map} +1 -1
  7. package/dist/{chunk-5D7ZFZIM.js → chunk-5YQ5B7IZ.js} +2 -2
  8. package/dist/{chunk-5D7ZFZIM.js.map → chunk-5YQ5B7IZ.js.map} +1 -1
  9. package/dist/{chunk-VZFHU553.mjs → chunk-6MQUBPKB.mjs} +2 -2
  10. package/dist/{chunk-VZFHU553.mjs.map → chunk-6MQUBPKB.mjs.map} +1 -1
  11. package/dist/{chunk-LFM5QSFW.js → chunk-A3UP56MS.js} +2 -2
  12. package/dist/{chunk-LFM5QSFW.js.map → chunk-A3UP56MS.js.map} +1 -1
  13. package/dist/{chunk-66EHKQVS.js → chunk-CLKKZSPZ.js} +2 -2
  14. package/dist/{chunk-66EHKQVS.js.map → chunk-CLKKZSPZ.js.map} +1 -1
  15. package/dist/{chunk-MRGFYQTC.mjs → chunk-CNTILN5J.mjs} +2 -2
  16. package/dist/{chunk-MRGFYQTC.mjs.map → chunk-CNTILN5J.mjs.map} +1 -1
  17. package/dist/{chunk-UUM5BIOU.js → chunk-E7RGBAYJ.js} +7 -7
  18. package/dist/{chunk-UUM5BIOU.js.map → chunk-E7RGBAYJ.js.map} +1 -1
  19. package/dist/{chunk-TGL6BATG.mjs → chunk-MW4BCIZC.mjs} +2 -2
  20. package/dist/{chunk-TGL6BATG.mjs.map → chunk-MW4BCIZC.mjs.map} +1 -1
  21. package/dist/imageCrop/index.js.map +1 -1
  22. package/dist/imageCrop/index.mjs.map +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +1 -1
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/mmd/index.d.mts +169 -5
  28. package/dist/mmd/index.d.ts +169 -5
  29. package/dist/mmd/index.js +463 -67
  30. package/dist/mmd/index.js.map +1 -1
  31. package/dist/mmd/index.mjs +463 -69
  32. package/dist/mmd/index.mjs.map +1 -1
  33. package/dist/music/index.js +16 -16
  34. package/dist/music/index.mjs +2 -2
  35. package/dist/music/server/index.js +8 -8
  36. package/dist/music/server/index.mjs +1 -1
  37. package/dist/testYourself/admin/index.js +3 -3
  38. package/dist/testYourself/admin/index.mjs +1 -1
  39. package/dist/testYourself/index.js +7 -7
  40. package/dist/testYourself/index.js.map +1 -1
  41. package/dist/testYourself/index.mjs +2 -2
  42. package/dist/testYourself/index.mjs.map +1 -1
  43. package/package.json +17 -19
package/dist/mmd/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkUUM5BIOU_js = require('../chunk-UUM5BIOU.js');
4
- require('../chunk-LFM5QSFW.js');
3
+ var chunkE7RGBAYJ_js = require('../chunk-E7RGBAYJ.js');
4
+ require('../chunk-A3UP56MS.js');
5
5
  var chunkJZXJQMVE_js = require('../chunk-JZXJQMVE.js');
6
6
  require('../chunk-DGUM43GV.js');
7
7
  var React10 = require('react');
@@ -1177,6 +1177,7 @@ var MMDPlayerBase = React10.forwardRef((props, ref) => {
1177
1177
  const audioRef = React10.useRef(null);
1178
1178
  const audioListenerRef = React10.useRef(null);
1179
1179
  const audioLoaderRef = React10.useRef(new THREE2__namespace.AudioLoader());
1180
+ const [isAudioSystemReady, setIsAudioSystemReady] = React10.useState(false);
1180
1181
  const latestCallbacks = React10.useRef({ onPlay, onPause, onEnded, onTimeUpdate });
1181
1182
  React10.useEffect(() => {
1182
1183
  latestCallbacks.current = { onPlay, onPause, onEnded, onTimeUpdate };
@@ -1194,6 +1195,10 @@ var MMDPlayerBase = React10.forwardRef((props, ref) => {
1194
1195
  React10.useImperativeHandle(ref, () => ({
1195
1196
  play: () => {
1196
1197
  if (!isReadyRef.current) return;
1198
+ if (isPlayingRef.current) {
1199
+ console.log("[MMDPlayerBase] play() called but already playing, skipping");
1200
+ return;
1201
+ }
1197
1202
  console.log("[MMDPlayerBase] play() called, audioRef:", !!audioRef.current, "isPlaying:", audioRef.current?.isPlaying);
1198
1203
  isPlayingRef.current = true;
1199
1204
  if (!clockRef.current.running) clockRef.current.start();
@@ -1436,6 +1441,7 @@ var MMDPlayerBase = React10.forwardRef((props, ref) => {
1436
1441
  afterglow: 2
1437
1442
  });
1438
1443
  helperRef.current = helper;
1444
+ setIsAudioSystemReady(true);
1439
1445
  const loadModelPromise = new Promise((resolve, reject) => {
1440
1446
  if (resources.motionPath) {
1441
1447
  loader.loadWithAnimation(
@@ -1853,6 +1859,7 @@ ${errorMessage}
1853
1859
  console.warn("[MMDPlayerBase] Error cleaning up AnimationHelper:", e);
1854
1860
  }
1855
1861
  helperRef.current = null;
1862
+ setIsAudioSystemReady(false);
1856
1863
  }
1857
1864
  animationClipRef.current = null;
1858
1865
  if (axesHelperRef.current) {
@@ -2009,9 +2016,19 @@ ${errorMessage}
2009
2016
  };
2010
2017
  }, [resources.modelPath, resources.motionPath, resources.stageModelPath, stage.enablePhysics, stage.physicsPath]);
2011
2018
  React10.useEffect(() => {
2012
- if (!audioListenerRef.current || !helperRef.current || !resources.audioPath) return;
2019
+ if (!isAudioSystemReady || !audioListenerRef.current || !helperRef.current || !resources.audioPath) {
2020
+ console.log("[MMDPlayerBase] \u{1F3B5} Audio loading skipped:", {
2021
+ isAudioSystemReady,
2022
+ hasListener: !!audioListenerRef.current,
2023
+ hasHelper: !!helperRef.current,
2024
+ audioPath: resources.audioPath
2025
+ });
2026
+ return;
2027
+ }
2013
2028
  const listener = audioListenerRef.current;
2014
2029
  const helper = helperRef.current;
2030
+ let retryTimer = null;
2031
+ console.log("[MMDPlayerBase] \u{1F3B5} Starting audio load for:", resources.audioPath);
2015
2032
  if (audioRef.current) {
2016
2033
  const oldSound = audioRef.current;
2017
2034
  if (oldSound.isPlaying) oldSound.stop();
@@ -2031,14 +2048,29 @@ ${errorMessage}
2031
2048
  delay: 0,
2032
2049
  duration: buffer.duration
2033
2050
  });
2051
+ console.log("[MMDPlayerBase] \u{1F3B5} Audio loaded, isPlayingRef:", isPlayingRef.current, "autoPlay:", autoPlay, "isReadyRef:", isReadyRef.current);
2034
2052
  if (isPlayingRef.current) {
2053
+ console.log("[MMDPlayerBase] \u{1F3B5} Playing audio immediately (isPlayingRef=true)");
2035
2054
  sound.play();
2055
+ } else if (autoPlay) {
2056
+ console.log("[MMDPlayerBase] \u{1F3B5} Audio loaded before autoPlay triggered, waiting for play state...");
2057
+ retryTimer = setTimeout(() => {
2058
+ if (isPlayingRef.current && audioRef.current && !audioRef.current.isPlaying) {
2059
+ console.log("[MMDPlayerBase] \u{1F3B5} Playing audio after delay (autoPlay=true)");
2060
+ audioRef.current.play();
2061
+ }
2062
+ }, 150);
2036
2063
  }
2037
2064
  },
2038
2065
  void 0,
2039
2066
  (err) => console.error("[MMDPlayerBase] Failed to load audio track:", err)
2040
2067
  );
2041
- }, [resources.audioPath, volume]);
2068
+ return () => {
2069
+ if (retryTimer) {
2070
+ clearTimeout(retryTimer);
2071
+ }
2072
+ };
2073
+ }, [resources.audioPath, volume, autoPlay, isAudioSystemReady]);
2042
2074
  React10.useEffect(() => {
2043
2075
  if (!sceneRef.current) return;
2044
2076
  if (showAxes && !axesHelperRef.current) {
@@ -4438,7 +4470,9 @@ var StartScreen = ({
4438
4470
  settingsText = "\u6E38\u620F\u8BBE\u7F6E",
4439
4471
  aboutText = "\u5173\u4E8E\u4F5C\u54C1",
4440
4472
  onStart,
4441
- className = ""
4473
+ className = "",
4474
+ customSettingsContent,
4475
+ customAboutContent
4442
4476
  }) => {
4443
4477
  const [isMounted, setIsMounted] = React10.useState(false);
4444
4478
  const [showSettings, setShowSettings] = React10.useState(false);
@@ -4543,7 +4577,7 @@ var StartScreen = ({
4543
4577
  background: "rgba(248, 250, 252, 0.8)",
4544
4578
  borderColor: "rgba(203, 213, 225, 0.3)"
4545
4579
  } }, /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[8px] sm:text-[10px] md:text-xs tracking-[0.3em] sm:tracking-[0.5em] font-light uppercase", style: { color: "rgba(100, 116, 139, 0.5)" } }, "Ver 1.6.2 \u2014 ENGINE POWERED BY SA2KIT"))),
4546
- /* @__PURE__ */ React10__default.default.createElement(VNModal, { title: settingsText, show: showSettings, onClose: () => setShowSettings(false) }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-6 sm:space-y-8 py-2 sm:py-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-center text-xs sm:text-sm font-bold tracking-wider sm:tracking-widest", style: { color: "#64748b" } }, /* @__PURE__ */ React10__default.default.createElement("span", null, "MUSIC VOLUME"), /* @__PURE__ */ React10__default.default.createElement("span", null, "80%")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "h-2.5 sm:h-3 rounded-full p-0.5 border", style: { background: "rgba(241, 245, 249, 0.5)", borderColor: "rgba(203, 213, 225, 0.4)" } }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "h-full w-[80%] rounded-full", style: { background: "linear-gradient(to right, #22c55e, #4ade80)", boxShadow: "0 0 15px rgba(34, 197, 94, 0.5)" } }))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-center text-xs sm:text-sm font-bold tracking-wider sm:tracking-widest", style: { color: "#64748b" } }, /* @__PURE__ */ React10__default.default.createElement("span", null, "TEXT SPEED"), /* @__PURE__ */ React10__default.default.createElement("span", null, "NORMAL")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex gap-2 sm:gap-3" }, ["SLOW", "NORMAL", "FAST"].map((s, i) => /* @__PURE__ */ React10__default.default.createElement(
4580
+ /* @__PURE__ */ React10__default.default.createElement(VNModal, { title: settingsText, show: showSettings, onClose: () => setShowSettings(false) }, customSettingsContent ? /* @__PURE__ */ React10__default.default.createElement("div", { className: "py-2 sm:py-4" }, customSettingsContent) : /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-6 sm:space-y-8 py-2 sm:py-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-center text-xs sm:text-sm font-bold tracking-wider sm:tracking-widest", style: { color: "#64748b" } }, /* @__PURE__ */ React10__default.default.createElement("span", null, "MUSIC VOLUME"), /* @__PURE__ */ React10__default.default.createElement("span", null, "80%")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "h-2.5 sm:h-3 rounded-full p-0.5 border", style: { background: "rgba(241, 245, 249, 0.5)", borderColor: "rgba(203, 213, 225, 0.4)" } }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "h-full w-[80%] rounded-full", style: { background: "linear-gradient(to right, #22c55e, #4ade80)", boxShadow: "0 0 15px rgba(34, 197, 94, 0.5)" } }))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-center text-xs sm:text-sm font-bold tracking-wider sm:tracking-widest", style: { color: "#64748b" } }, /* @__PURE__ */ React10__default.default.createElement("span", null, "TEXT SPEED"), /* @__PURE__ */ React10__default.default.createElement("span", null, "NORMAL")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex gap-2 sm:gap-3" }, ["SLOW", "NORMAL", "FAST"].map((s, i) => /* @__PURE__ */ React10__default.default.createElement(
4547
4581
  "div",
4548
4582
  {
4549
4583
  key: s,
@@ -4560,7 +4594,7 @@ var StartScreen = ({
4560
4594
  },
4561
4595
  s
4562
4596
  )))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "pt-3 sm:pt-4 flex flex-col sm:flex-row items-center justify-between gap-2 sm:gap-0 opacity-50 italic text-[10px] sm:text-xs border-t", style: { borderColor: "rgba(203, 213, 225, 0.3)" } }, /* @__PURE__ */ React10__default.default.createElement("span", null, "Auto Save Enabled"), /* @__PURE__ */ React10__default.default.createElement("span", null, "Cloud Sync Active")))),
4563
- /* @__PURE__ */ React10__default.default.createElement(VNModal, { title: aboutText, show: showAbout, onClose: () => setShowAbout(false) }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-6 sm:space-y-8 py-2 sm:py-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center gap-3 sm:gap-6 p-4 sm:p-6 rounded-2xl sm:rounded-3xl border", style: { background: "rgba(241, 245, 249, 0.6)", borderColor: "rgba(203, 213, 225, 0.4)" } }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "w-14 h-14 sm:w-20 sm:h-20 rounded-xl sm:rounded-2xl flex items-center justify-center text-2xl sm:text-3xl font-black text-white shadow-lg shrink-0", style: { background: "linear-gradient(to bottom right, #22c55e, #4ade80)" } }, "S2"), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "text-lg sm:text-2xl font-black tracking-tight", style: { color: "#22c55e" } }, scriptName || "Project SA2"), /* @__PURE__ */ React10__default.default.createElement("p", { className: "text-[10px] sm:text-xs font-bold tracking-wider sm:tracking-widest mt-1 uppercase", style: { color: "rgba(100, 116, 139, 0.6)" } }, "Visual Novel Experience"))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4 px-1 sm:px-2" }, /* @__PURE__ */ React10__default.default.createElement("p", { className: "font-medium leading-relaxed text-sm sm:text-base", style: { color: "#475569" } }, "\u91C7\u7528 sa2kit \u5F15\u64CE\u6784\u5EFA\u7684\u65B0\u4E00\u4EE3\u5B9E\u65F6 3D \u89C6\u89C9\u5C0F\u8BF4\u3002\u7ED3\u5408\u4E86 MMD \u5B9E\u65F6\u6E32\u67D3\u6280\u672F\u4E0E\u4EA4\u4E92\u5F0F\u5267\u60C5\u5206\u652F\u7CFB\u7EDF\uFF0C\u81F4\u529B\u4E8E\u6253\u9020\u6781\u81F4\u7684\u6C89\u6D78\u5F0F\u53D9\u4E8B\u4F53\u9A8C\u3002")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "grid grid-cols-2 gap-3 sm:gap-4 pt-4 sm:pt-6 border-t", style: { borderColor: "rgba(203, 213, 225, 0.3)" } }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[9px] sm:text-[10px] font-bold tracking-wider sm:tracking-widest", style: { color: "rgba(100, 116, 139, 0.5)" } }, "DEVELOPER"), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs font-bold", style: { color: "#64748b" } }, "SA2KIT TEAM")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col gap-1 text-right" }, /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[9px] sm:text-[10px] font-bold tracking-wider sm:tracking-widest", style: { color: "rgba(100, 116, 139, 0.5)" } }, "ENGINE"), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs font-bold", style: { color: "#64748b" } }, "THREE.JS / REACT"))))),
4597
+ /* @__PURE__ */ React10__default.default.createElement(VNModal, { title: aboutText, show: showAbout, onClose: () => setShowAbout(false) }, customAboutContent ? /* @__PURE__ */ React10__default.default.createElement("div", { className: "py-2 sm:py-4" }, customAboutContent) : /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-6 sm:space-y-8 py-2 sm:py-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center gap-3 sm:gap-6 p-4 sm:p-6 rounded-2xl sm:rounded-3xl border", style: { background: "rgba(241, 245, 249, 0.6)", borderColor: "rgba(203, 213, 225, 0.4)" } }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "w-14 h-14 sm:w-20 sm:h-20 rounded-xl sm:rounded-2xl flex items-center justify-center text-2xl sm:text-3xl font-black text-white shadow-lg shrink-0", style: { background: "linear-gradient(to bottom right, #22c55e, #4ade80)" } }, "S2"), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "text-lg sm:text-2xl font-black tracking-tight", style: { color: "#22c55e" } }, scriptName || "Project SA2"), /* @__PURE__ */ React10__default.default.createElement("p", { className: "text-[10px] sm:text-xs font-bold tracking-wider sm:tracking-widest mt-1 uppercase", style: { color: "rgba(100, 116, 139, 0.6)" } }, "Visual Novel Experience"))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4 px-1 sm:px-2" }, /* @__PURE__ */ React10__default.default.createElement("p", { className: "font-medium leading-relaxed text-sm sm:text-base", style: { color: "#475569" } }, "\u91C7\u7528 sa2kit \u5F15\u64CE\u6784\u5EFA\u7684\u65B0\u4E00\u4EE3\u5B9E\u65F6 3D \u89C6\u89C9\u5C0F\u8BF4\u3002\u7ED3\u5408\u4E86 MMD \u5B9E\u65F6\u6E32\u67D3\u6280\u672F\u4E0E\u4EA4\u4E92\u5F0F\u5267\u60C5\u5206\u652F\u7CFB\u7EDF\uFF0C\u81F4\u529B\u4E8E\u6253\u9020\u6781\u81F4\u7684\u6C89\u6D78\u5F0F\u53D9\u4E8B\u4F53\u9A8C\u3002")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "grid grid-cols-2 gap-3 sm:gap-4 pt-4 sm:pt-6 border-t", style: { borderColor: "rgba(203, 213, 225, 0.3)" } }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col gap-1" }, /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[9px] sm:text-[10px] font-bold tracking-wider sm:tracking-widest", style: { color: "rgba(100, 116, 139, 0.5)" } }, "DEVELOPER"), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs font-bold", style: { color: "#64748b" } }, "SA2KIT TEAM")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col gap-1 text-right" }, /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[9px] sm:text-[10px] font-bold tracking-wider sm:tracking-widest", style: { color: "rgba(100, 116, 139, 0.5)" } }, "ENGINE"), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs font-bold", style: { color: "#64748b" } }, "THREE.JS / REACT"))))),
4564
4598
  /* @__PURE__ */ React10__default.default.createElement("style", null, `
4565
4599
  @keyframes floatParticle {
4566
4600
  from { transform: translateY(0) translateX(0); opacity: 0; }
@@ -4644,7 +4678,9 @@ var LoadingOverlay = ({
4644
4678
  settingsText = "\u6E38\u620F\u8BBE\u7F6E",
4645
4679
  aboutText = "\u5173\u4E8E\u4F5C\u54C1",
4646
4680
  onStart,
4647
- className = ""
4681
+ className = "",
4682
+ customSettingsContent,
4683
+ customAboutContent
4648
4684
  }) => {
4649
4685
  return /* @__PURE__ */ React10__default.default.createElement(React10__default.default.Fragment, null, /* @__PURE__ */ React10__default.default.createElement(
4650
4686
  LoadingScreen,
@@ -4662,7 +4698,9 @@ var LoadingOverlay = ({
4662
4698
  settingsText,
4663
4699
  aboutText,
4664
4700
  onStart,
4665
- className
4701
+ className,
4702
+ customSettingsContent,
4703
+ customAboutContent
4666
4704
  }
4667
4705
  ));
4668
4706
  };
@@ -5069,6 +5107,8 @@ var MMDVisualNovel = React10.forwardRef(
5069
5107
  showHistoryButton = true,
5070
5108
  showLightingDebugPanel = false,
5071
5109
  lightingDebugInitialParams,
5110
+ customSettingsContent,
5111
+ customAboutContent,
5072
5112
  className,
5073
5113
  style
5074
5114
  }, ref) => {
@@ -5467,7 +5507,9 @@ var MMDVisualNovel = React10.forwardRef(
5467
5507
  startText,
5468
5508
  settingsText,
5469
5509
  aboutText,
5470
- onStart: handleStart
5510
+ onStart: handleStart,
5511
+ customSettingsContent,
5512
+ customAboutContent
5471
5513
  }
5472
5514
  ),
5473
5515
  (() => {
@@ -5588,6 +5630,224 @@ var MMDVisualNovel = React10.forwardRef(
5588
5630
  }
5589
5631
  );
5590
5632
  MMDVisualNovel.displayName = "MMDVisualNovel";
5633
+ var ModelSelectorSettings = ({
5634
+ characterModels,
5635
+ stageModels,
5636
+ selectedCharacterId,
5637
+ selectedStageId,
5638
+ onCharacterChange,
5639
+ onStageChange,
5640
+ characterLabel = "CHARACTER MODEL",
5641
+ stageLabel = "STAGE MODEL"
5642
+ }) => {
5643
+ return /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-6 sm:space-y-8" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-center text-xs sm:text-sm font-bold tracking-wider sm:tracking-widest", style: { color: "#64748b" } }, /* @__PURE__ */ React10__default.default.createElement("span", null, characterLabel), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[10px] sm:text-xs opacity-60" }, characterModels.find((m) => m.id === selectedCharacterId)?.name || "\u672A\u9009\u62E9")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React10__default.default.createElement(
5644
+ "select",
5645
+ {
5646
+ value: selectedCharacterId,
5647
+ onChange: (e) => onCharacterChange(e.target.value),
5648
+ className: "w-full h-12 sm:h-14 px-4 sm:px-6 rounded-xl sm:rounded-2xl border appearance-none cursor-pointer font-medium text-sm sm:text-base transition-all focus:outline-none focus:ring-2 focus:ring-green-500/30 touch-manipulation",
5649
+ style: {
5650
+ background: "linear-gradient(135deg, rgba(248, 250, 252, 0.98), rgba(226, 232, 240, 0.95))",
5651
+ borderColor: "rgba(203, 213, 225, 0.6)",
5652
+ color: "#475569",
5653
+ boxShadow: "0 2px 8px rgba(100, 116, 139, 0.1)"
5654
+ }
5655
+ },
5656
+ characterModels.map((model) => /* @__PURE__ */ React10__default.default.createElement("option", { key: model.id, value: model.id }, model.name))
5657
+ ), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute right-4 sm:right-6 top-1/2 -translate-y-1/2 pointer-events-none" }, /* @__PURE__ */ React10__default.default.createElement(
5658
+ "svg",
5659
+ {
5660
+ className: "w-4 h-4 sm:w-5 sm:h-5",
5661
+ fill: "none",
5662
+ stroke: "currentColor",
5663
+ viewBox: "0 0 24 24",
5664
+ style: { color: "#64748b" }
5665
+ },
5666
+ /* @__PURE__ */ React10__default.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
5667
+ ))), characterModels.find((m) => m.id === selectedCharacterId)?.thumbnail && /* @__PURE__ */ React10__default.default.createElement("div", { className: "mt-2 flex justify-center" }, /* @__PURE__ */ React10__default.default.createElement(
5668
+ "img",
5669
+ {
5670
+ src: characterModels.find((m) => m.id === selectedCharacterId)?.thumbnail,
5671
+ alt: "Character preview",
5672
+ className: "h-20 sm:h-24 rounded-lg border object-cover",
5673
+ style: { borderColor: "rgba(203, 213, 225, 0.4)" }
5674
+ }
5675
+ ))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-3 sm:space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-center text-xs sm:text-sm font-bold tracking-wider sm:tracking-widest", style: { color: "#64748b" } }, /* @__PURE__ */ React10__default.default.createElement("span", null, stageLabel), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[10px] sm:text-xs opacity-60" }, stageModels.find((m) => m.id === selectedStageId)?.name || "\u672A\u9009\u62E9")), /* @__PURE__ */ React10__default.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React10__default.default.createElement(
5676
+ "select",
5677
+ {
5678
+ value: selectedStageId,
5679
+ onChange: (e) => onStageChange(e.target.value),
5680
+ className: "w-full h-12 sm:h-14 px-4 sm:px-6 rounded-xl sm:rounded-2xl border appearance-none cursor-pointer font-medium text-sm sm:text-base transition-all focus:outline-none focus:ring-2 focus:ring-green-500/30 touch-manipulation",
5681
+ style: {
5682
+ background: "linear-gradient(135deg, rgba(248, 250, 252, 0.98), rgba(226, 232, 240, 0.95))",
5683
+ borderColor: "rgba(203, 213, 225, 0.6)",
5684
+ color: "#475569",
5685
+ boxShadow: "0 2px 8px rgba(100, 116, 139, 0.1)"
5686
+ }
5687
+ },
5688
+ stageModels.map((model) => /* @__PURE__ */ React10__default.default.createElement("option", { key: model.id, value: model.id }, model.name))
5689
+ ), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute right-4 sm:right-6 top-1/2 -translate-y-1/2 pointer-events-none" }, /* @__PURE__ */ React10__default.default.createElement(
5690
+ "svg",
5691
+ {
5692
+ className: "w-4 h-4 sm:w-5 sm:h-5",
5693
+ fill: "none",
5694
+ stroke: "currentColor",
5695
+ viewBox: "0 0 24 24",
5696
+ style: { color: "#64748b" }
5697
+ },
5698
+ /* @__PURE__ */ React10__default.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
5699
+ ))), stageModels.find((m) => m.id === selectedStageId)?.thumbnail && /* @__PURE__ */ React10__default.default.createElement("div", { className: "mt-2 flex justify-center" }, /* @__PURE__ */ React10__default.default.createElement(
5700
+ "img",
5701
+ {
5702
+ src: stageModels.find((m) => m.id === selectedStageId)?.thumbnail,
5703
+ alt: "Stage preview",
5704
+ className: "h-20 sm:h-24 rounded-lg border object-cover",
5705
+ style: { borderColor: "rgba(203, 213, 225, 0.4)" }
5706
+ }
5707
+ ))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "pt-3 sm:pt-4 flex items-center justify-center gap-2 opacity-50 italic text-[10px] sm:text-xs border-t", style: { borderColor: "rgba(203, 213, 225, 0.3)" } }, /* @__PURE__ */ React10__default.default.createElement("svg", { className: "w-3.5 h-3.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" }, /* @__PURE__ */ React10__default.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })), /* @__PURE__ */ React10__default.default.createElement("span", null, "\u9009\u62E9\u7684\u6A21\u578B\u5C06\u5E94\u7528\u5230\u6240\u6709\u573A\u666F")));
5708
+ };
5709
+ ModelSelectorSettings.displayName = "ModelSelectorSettings";
5710
+
5711
+ // src/mmd/visual-novel/MMDVisualNovelWithSelector.tsx
5712
+ var MMDVisualNovelWithSelector = React10.forwardRef((props, ref) => {
5713
+ const {
5714
+ script,
5715
+ modelSelector,
5716
+ onModelSelectionChange,
5717
+ ...restProps
5718
+ } = props;
5719
+ const {
5720
+ characterModels,
5721
+ stageModels,
5722
+ defaultCharacterId,
5723
+ defaultStageId,
5724
+ characterLabel,
5725
+ stageLabel
5726
+ } = modelSelector;
5727
+ const visualNovelRef = React10.useRef(null);
5728
+ const [selectedCharacterId, setSelectedCharacterId] = React10.useState(
5729
+ defaultCharacterId || characterModels[0]?.id || ""
5730
+ );
5731
+ const [selectedStageId, setSelectedStageId] = React10.useState(
5732
+ defaultStageId || stageModels[0]?.id || ""
5733
+ );
5734
+ const selectedCharacterPath = React10.useMemo(() => {
5735
+ const model = characterModels.find((m) => m.id === selectedCharacterId);
5736
+ return model?.path || characterModels[0]?.path || "";
5737
+ }, [characterModels, selectedCharacterId]);
5738
+ const selectedStagePath = React10.useMemo(() => {
5739
+ const model = stageModels.find((m) => m.id === selectedStageId);
5740
+ return model?.path || stageModels[0]?.path || "";
5741
+ }, [stageModels, selectedStageId]);
5742
+ const modifiedScript = React10.useMemo(() => {
5743
+ return {
5744
+ ...script,
5745
+ nodes: script.nodes.map((node) => ({
5746
+ ...node,
5747
+ resources: {
5748
+ ...node.resources,
5749
+ // 覆盖人物模型路径
5750
+ modelPath: selectedCharacterPath,
5751
+ // 覆盖场景模型路径
5752
+ stageModelPath: selectedStagePath
5753
+ }
5754
+ }))
5755
+ };
5756
+ }, [script, selectedCharacterPath, selectedStagePath]);
5757
+ const handleCharacterChange = React10.useCallback((id) => {
5758
+ setSelectedCharacterId(id);
5759
+ onModelSelectionChange?.(id, selectedStageId);
5760
+ }, [selectedStageId, onModelSelectionChange]);
5761
+ const handleStageChange = React10.useCallback((id) => {
5762
+ setSelectedStageId(id);
5763
+ onModelSelectionChange?.(selectedCharacterId, id);
5764
+ }, [selectedCharacterId, onModelSelectionChange]);
5765
+ const customSettingsContent = React10.useMemo(() => /* @__PURE__ */ React10__default.default.createElement(
5766
+ ModelSelectorSettings,
5767
+ {
5768
+ characterModels,
5769
+ stageModels,
5770
+ selectedCharacterId,
5771
+ selectedStageId,
5772
+ onCharacterChange: handleCharacterChange,
5773
+ onStageChange: handleStageChange,
5774
+ characterLabel,
5775
+ stageLabel
5776
+ }
5777
+ ), [
5778
+ characterModels,
5779
+ stageModels,
5780
+ selectedCharacterId,
5781
+ selectedStageId,
5782
+ handleCharacterChange,
5783
+ handleStageChange,
5784
+ characterLabel,
5785
+ stageLabel
5786
+ ]);
5787
+ React10.useImperativeHandle(ref, () => ({
5788
+ // 继承 MMDVisualNovelRef 的所有方法
5789
+ goToNode: (nodeIndex, force) => {
5790
+ visualNovelRef.current?.goToNode(nodeIndex, force);
5791
+ },
5792
+ goToDialogue: (dialogueIndex) => {
5793
+ visualNovelRef.current?.goToDialogue(dialogueIndex);
5794
+ },
5795
+ getCurrentNodeIndex: () => {
5796
+ return visualNovelRef.current?.getCurrentNodeIndex() ?? 0;
5797
+ },
5798
+ getCurrentDialogueIndex: () => {
5799
+ return visualNovelRef.current?.getCurrentDialogueIndex() ?? 0;
5800
+ },
5801
+ getHistory: () => {
5802
+ return visualNovelRef.current?.getHistory() ?? [];
5803
+ },
5804
+ getVariables: () => {
5805
+ return visualNovelRef.current?.getVariables() ?? {};
5806
+ },
5807
+ setVariable: (key, value) => {
5808
+ visualNovelRef.current?.setVariable(key, value);
5809
+ },
5810
+ setAutoMode: (enabled) => {
5811
+ visualNovelRef.current?.setAutoMode(enabled);
5812
+ },
5813
+ skipTyping: () => {
5814
+ visualNovelRef.current?.skipTyping();
5815
+ },
5816
+ triggerEffect: (effect) => {
5817
+ visualNovelRef.current?.triggerEffect?.(effect);
5818
+ },
5819
+ // 新增的模型选择方法
5820
+ getSelectedCharacterId: () => selectedCharacterId,
5821
+ getSelectedStageId: () => selectedStageId,
5822
+ setCharacterModel: (id) => {
5823
+ if (characterModels.some((m) => m.id === id)) {
5824
+ handleCharacterChange(id);
5825
+ }
5826
+ },
5827
+ setStageModel: (id) => {
5828
+ if (stageModels.some((m) => m.id === id)) {
5829
+ handleStageChange(id);
5830
+ }
5831
+ }
5832
+ }), [
5833
+ selectedCharacterId,
5834
+ selectedStageId,
5835
+ characterModels,
5836
+ stageModels,
5837
+ handleCharacterChange,
5838
+ handleStageChange
5839
+ ]);
5840
+ return /* @__PURE__ */ React10__default.default.createElement(
5841
+ MMDVisualNovel,
5842
+ {
5843
+ ref: visualNovelRef,
5844
+ script: modifiedScript,
5845
+ customSettingsContent,
5846
+ ...restProps
5847
+ }
5848
+ );
5849
+ });
5850
+ MMDVisualNovelWithSelector.displayName = "MMDVisualNovelWithSelector";
5591
5851
  var MusicControls = ({
5592
5852
  isPlaying,
5593
5853
  currentTime,
@@ -5799,7 +6059,7 @@ var MMDMusicPlayer = React10.forwardRef(
5799
6059
  const [isUIVisible, setIsUIVisible] = React10.useState(true);
5800
6060
  const [isCameraManual, setIsCameraManual] = React10.useState(false);
5801
6061
  const [searchKeyword, setSearchKeyword] = React10.useState("");
5802
- const { search, searchResult, isSearching, getSongUrl } = chunkUUM5BIOU_js.useMusic();
6062
+ const { search, searchResult, isSearching, getSongUrl } = chunkE7RGBAYJ_js.useMusic();
5803
6063
  React10.useEffect(() => {
5804
6064
  if (mikuMode && tracks.length === 0) {
5805
6065
  search({ keyword: "", miku: true });
@@ -6076,41 +6336,129 @@ var MMDMusicPlayer = React10.forwardRef(
6076
6336
  }
6077
6337
  );
6078
6338
  MMDMusicPlayer.displayName = "MMDMusicPlayer";
6339
+ function Select({
6340
+ label,
6341
+ options,
6342
+ value,
6343
+ onChange,
6344
+ placeholder = "\u8BF7\u9009\u62E9...",
6345
+ allowEmpty = false,
6346
+ emptyLabel = "\u65E0"
6347
+ }) {
6348
+ const selectedOption = options.find((opt) => opt.id === value);
6349
+ const showPlaceholder = !selectedOption && !allowEmpty && value !== "";
6350
+ return /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs font-medium text-white/50 ml-1 uppercase tracking-wider" }, label), /* @__PURE__ */ React10__default.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React10__default.default.createElement(
6351
+ "select",
6352
+ {
6353
+ value,
6354
+ onChange: (e) => onChange(e.target.value),
6355
+ className: "w-full appearance-none bg-white/5 border border-white/10 rounded-xl px-4 py-3 pr-10 text-sm text-white focus:outline-none focus:border-cyan-500/50 transition-colors cursor-pointer hover:bg-white/10"
6356
+ },
6357
+ showPlaceholder && /* @__PURE__ */ React10__default.default.createElement("option", { value: "", disabled: true, className: "bg-gray-900 text-white/50" }, placeholder),
6358
+ allowEmpty && /* @__PURE__ */ React10__default.default.createElement("option", { value: "", className: "bg-gray-900 text-white/60" }, emptyLabel),
6359
+ options.map((option) => /* @__PURE__ */ React10__default.default.createElement(
6360
+ "option",
6361
+ {
6362
+ key: option.id,
6363
+ value: option.id,
6364
+ className: "bg-gray-900 text-white"
6365
+ },
6366
+ option.name
6367
+ ))
6368
+ ), /* @__PURE__ */ React10__default.default.createElement(lucideReact.ChevronDown, { className: "absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-white/40 pointer-events-none" })));
6369
+ }
6079
6370
  var MMDARPlayer = React10.forwardRef((props, ref) => {
6080
6371
  const {
6081
- resources,
6082
6372
  stage = {},
6083
6373
  mobileOptimization,
6084
6374
  cameraConfig = { facingMode: "user" },
6085
6375
  mirrored,
6086
6376
  showSettings = true,
6377
+ modelPresets,
6378
+ motionPresets,
6379
+ audioPresets = [],
6380
+ defaultModelId,
6381
+ defaultMotionId,
6382
+ defaultAudioId,
6383
+ initialModelVisible = false,
6384
+ placementText = "TOUCH!",
6087
6385
  autoPlay = true,
6088
6386
  loop = true,
6089
6387
  onCameraReady,
6090
6388
  onCameraError,
6091
6389
  onResourcesChange,
6390
+ onModelPlaced,
6092
6391
  onLoad,
6093
6392
  onError,
6094
6393
  className,
6095
6394
  style
6096
6395
  } = props;
6396
+ const initialModelId = defaultModelId || modelPresets[0]?.id || "";
6397
+ const initialMotionId = defaultMotionId || motionPresets[0]?.id || "";
6398
+ const initialAudioId = defaultAudioId || audioPresets[0]?.id || "";
6097
6399
  const videoRef = React10.useRef(null);
6098
6400
  const playerRef = React10.useRef(null);
6099
6401
  const streamRef = React10.useRef(null);
6402
+ const containerRef = React10.useRef(null);
6100
6403
  const [isCameraStarted, setIsCameraStarted] = React10.useState(false);
6101
6404
  const [cameraError, setCameraError] = React10.useState(null);
6102
6405
  const [facingMode, setFacingMode] = React10.useState(cameraConfig.facingMode || "user");
6103
- const [isLoading, setIsLoading] = React10.useState(true);
6406
+ const [isLoading, setIsLoading] = React10.useState(false);
6104
6407
  const [isSettingsOpen, setIsSettingsOpen] = React10.useState(false);
6105
- const [currentResources, setCurrentResources] = React10.useState(resources);
6106
- const [tempResources, setTempResources] = React10.useState(resources);
6107
- React10.useEffect(() => {
6108
- if (!isSettingsOpen) {
6109
- setCurrentResources(resources);
6110
- setTempResources(resources);
6111
- }
6112
- }, [resources, isSettingsOpen]);
6408
+ const [selectedModelId, setSelectedModelId] = React10.useState(initialModelId);
6409
+ const [selectedMotionId, setSelectedMotionId] = React10.useState(initialMotionId);
6410
+ const [selectedAudioId, setSelectedAudioId] = React10.useState(initialAudioId);
6411
+ const [isModelPlaced, setIsModelPlaced] = React10.useState(initialModelVisible);
6412
+ const [placementAnimation, setPlacementAnimation] = React10.useState(false);
6413
+ const currentResources = React10.useMemo(() => {
6414
+ const model = modelPresets.find((m) => m.id === selectedModelId);
6415
+ const motion = motionPresets.find((m) => m.id === selectedMotionId);
6416
+ const audio = audioPresets.find((a) => a.id === selectedAudioId);
6417
+ return {
6418
+ modelPath: model?.modelPath || modelPresets[0]?.modelPath || "",
6419
+ motionPath: motion?.motionPath || motionPresets[0]?.motionPath || "",
6420
+ audioPath: audio?.audioPath
6421
+ };
6422
+ }, [selectedModelId, selectedMotionId, selectedAudioId, modelPresets, motionPresets, audioPresets]);
6113
6423
  const shouldMirror = mirrored !== void 0 ? mirrored : facingMode === "user";
6424
+ const placeModel = React10.useCallback(() => {
6425
+ if (isModelPlaced) return;
6426
+ setPlacementAnimation(true);
6427
+ setIsLoading(true);
6428
+ setTimeout(() => {
6429
+ setIsModelPlaced(true);
6430
+ setPlacementAnimation(false);
6431
+ onModelPlaced?.();
6432
+ }, 300);
6433
+ }, [isModelPlaced, onModelPlaced]);
6434
+ const removeModel = React10.useCallback(() => {
6435
+ setIsModelPlaced(false);
6436
+ setIsLoading(false);
6437
+ }, []);
6438
+ const switchModel = React10.useCallback((newResources) => {
6439
+ const matchedModel = modelPresets.find((m) => m.modelPath === newResources.modelPath);
6440
+ const matchedMotion = motionPresets.find((m) => m.motionPath === newResources.motionPath);
6441
+ const matchedAudio = audioPresets.find((a) => a.audioPath === newResources.audioPath);
6442
+ if (matchedModel) setSelectedModelId(matchedModel.id);
6443
+ if (matchedMotion) setSelectedMotionId(matchedMotion.id);
6444
+ if (matchedAudio) setSelectedAudioId(matchedAudio.id);
6445
+ onResourcesChange?.(newResources);
6446
+ if (isModelPlaced) {
6447
+ setIsLoading(true);
6448
+ }
6449
+ }, [isModelPlaced, onResourcesChange, modelPresets, motionPresets, audioPresets]);
6450
+ const applySettings = React10.useCallback(() => {
6451
+ onResourcesChange?.(currentResources);
6452
+ setIsSettingsOpen(false);
6453
+ if (isModelPlaced) {
6454
+ setIsLoading(true);
6455
+ }
6456
+ }, [currentResources, isModelPlaced, onResourcesChange]);
6457
+ const resetPosition = React10.useCallback(() => {
6458
+ setIsModelPlaced(false);
6459
+ setIsLoading(false);
6460
+ setIsSettingsOpen(false);
6461
+ }, []);
6114
6462
  const startCamera = React10.useCallback(async (mode = facingMode) => {
6115
6463
  try {
6116
6464
  setCameraError(null);
@@ -6171,22 +6519,27 @@ var MMDARPlayer = React10.forwardRef((props, ref) => {
6171
6519
  if (shouldMirror) {
6172
6520
  ctx.setTransform(1, 0, 0, 1, 0, 0);
6173
6521
  }
6174
- const mmdBase64 = playerRef.current.snapshot();
6175
- const mmdImg = new Image();
6176
- mmdImg.src = mmdBase64;
6177
- await new Promise((resolve) => {
6178
- mmdImg.onload = () => {
6179
- ctx.drawImage(mmdImg, 0, 0, canvas.width, canvas.height);
6180
- resolve(null);
6181
- };
6182
- });
6522
+ if (isModelPlaced) {
6523
+ const mmdBase64 = playerRef.current.snapshot();
6524
+ const mmdImg = new Image();
6525
+ mmdImg.src = mmdBase64;
6526
+ await new Promise((resolve) => {
6527
+ mmdImg.onload = () => {
6528
+ ctx.drawImage(mmdImg, 0, 0, canvas.width, canvas.height);
6529
+ resolve(null);
6530
+ };
6531
+ });
6532
+ }
6183
6533
  return canvas.toDataURL("image/png");
6184
- }, [shouldMirror]);
6534
+ }, [shouldMirror, isModelPlaced]);
6185
6535
  React10.useImperativeHandle(ref, () => ({
6186
6536
  startCamera,
6187
6537
  stopCamera,
6188
6538
  switchCamera,
6189
- snapshot
6539
+ snapshot,
6540
+ placeModel,
6541
+ removeModel,
6542
+ switchModel
6190
6543
  }));
6191
6544
  React10.useEffect(() => {
6192
6545
  if (autoPlay) {
@@ -6194,9 +6547,13 @@ var MMDARPlayer = React10.forwardRef((props, ref) => {
6194
6547
  }
6195
6548
  return () => stopCamera();
6196
6549
  }, [autoPlay, startCamera, stopCamera]);
6550
+ React10.useEffect(() => {
6551
+ onResourcesChange?.(currentResources);
6552
+ }, [currentResources, onResourcesChange]);
6197
6553
  return /* @__PURE__ */ React10__default.default.createElement(
6198
6554
  "div",
6199
6555
  {
6556
+ ref: containerRef,
6200
6557
  className: `relative w-full h-full bg-black overflow-hidden ${className}`,
6201
6558
  style
6202
6559
  },
@@ -6211,26 +6568,25 @@ var MMDARPlayer = React10.forwardRef((props, ref) => {
6211
6568
  style: { zIndex: 0 }
6212
6569
  }
6213
6570
  ),
6214
- /* @__PURE__ */ React10__default.default.createElement(
6571
+ isModelPlaced && /* @__PURE__ */ React10__default.default.createElement(
6215
6572
  "div",
6216
6573
  {
6217
- className: "absolute inset-0 w-full h-full",
6574
+ className: `absolute inset-0 w-full h-full transition-all duration-500 ${placementAnimation ? "scale-110 opacity-0" : "scale-100 opacity-100"}`,
6218
6575
  style: { zIndex: 1 }
6219
6576
  },
6220
6577
  /* @__PURE__ */ React10__default.default.createElement(
6221
6578
  MMDPlayerBase,
6222
6579
  {
6580
+ key: `${selectedModelId}-${selectedMotionId}-${selectedAudioId}`,
6223
6581
  ref: playerRef,
6224
6582
  resources: currentResources,
6225
6583
  stage: {
6226
6584
  ...stage,
6227
6585
  backgroundColor: "transparent",
6228
- // 强制透明背景
6229
6586
  cameraPosition: stage.cameraPosition || { x: 0, y: 15, z: 40 }
6230
- // 针对 AR 场景稍调高相机
6231
6587
  },
6232
6588
  mobileOptimization,
6233
- autoPlay,
6589
+ autoPlay: true,
6234
6590
  loop,
6235
6591
  onLoad: () => {
6236
6592
  setIsLoading(false);
@@ -6240,6 +6596,30 @@ var MMDARPlayer = React10.forwardRef((props, ref) => {
6240
6596
  }
6241
6597
  )
6242
6598
  ),
6599
+ !isModelPlaced && isCameraStarted && /* @__PURE__ */ React10__default.default.createElement(
6600
+ "div",
6601
+ {
6602
+ className: "absolute inset-0 z-5 flex items-center justify-center",
6603
+ onClick: placeModel
6604
+ },
6605
+ /* @__PURE__ */ React10__default.default.createElement(
6606
+ "button",
6607
+ {
6608
+ onClick: placeModel,
6609
+ className: `
6610
+ relative group cursor-pointer
6611
+ transition-all duration-300 ease-out
6612
+ hover:scale-110 active:scale-95
6613
+ ${placementAnimation ? "scale-150 opacity-0" : "scale-100 opacity-100"}
6614
+ `
6615
+ },
6616
+ /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 -m-4 rounded-2xl bg-cyan-400/20 animate-ping" }),
6617
+ /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 -m-2 rounded-xl bg-cyan-400/30 animate-pulse" }),
6618
+ /* @__PURE__ */ React10__default.default.createElement("div", { className: "relative bg-gradient-to-br from-cyan-400 via-blue-500 to-purple-600 p-1 rounded-2xl shadow-2xl shadow-cyan-500/50" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "bg-black/80 backdrop-blur-xl px-8 py-6 rounded-xl flex flex-col items-center gap-3" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Sparkles, { className: "w-10 h-10 text-cyan-400 animate-pulse" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 w-10 h-10 bg-cyan-400/30 blur-xl" })), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-2xl font-black text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-purple-400 tracking-widest" }, placementText), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs text-white/50 font-medium" }, "\u70B9\u51FB\u53EC\u5524 Miku \u2728"))),
6619
+ /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute -top-2 -right-2 w-4 h-4 bg-yellow-400 rounded-full animate-bounce shadow-lg shadow-yellow-400/50" }),
6620
+ /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute -bottom-1 -left-1 w-3 h-3 bg-pink-400 rounded-full animate-bounce delay-100 shadow-lg shadow-pink-400/50" })
6621
+ )
6622
+ ),
6243
6623
  /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 z-10 pointer-events-none flex flex-col justify-between p-6" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-start pointer-events-auto" }, cameraError ? /* @__PURE__ */ React10__default.default.createElement("div", { className: "bg-red-500/80 backdrop-blur-md text-white px-4 py-2 rounded-full flex items-center gap-2 text-sm" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.AlertCircle, { className: "w-4 h-4" }), cameraError, /* @__PURE__ */ React10__default.default.createElement(
6244
6624
  "button",
6245
6625
  {
@@ -6247,12 +6627,12 @@ var MMDARPlayer = React10.forwardRef((props, ref) => {
6247
6627
  className: "ml-2 underline"
6248
6628
  },
6249
6629
  "\u91CD\u8BD5"
6250
- )) : /* @__PURE__ */ React10__default.default.createElement("div", { className: "bg-black/40 backdrop-blur-md text-white px-4 py-2 rounded-full flex items-center gap-2 text-sm" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Camera, { className: "w-4 h-4 text-green-400" }), isCameraStarted ? "\u5B9E\u666F AR \u6A21\u5F0F\u5DF2\u5F00\u542F" : "\u7B49\u5F85\u6444\u50CF\u5934..."), /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col gap-2" }, showSettings && /* @__PURE__ */ React10__default.default.createElement(
6630
+ )) : /* @__PURE__ */ React10__default.default.createElement("div", { className: "bg-black/40 backdrop-blur-md text-white px-4 py-2 rounded-full flex items-center gap-2 text-sm" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Camera, { className: "w-4 h-4 text-green-400" }), isCameraStarted ? isModelPlaced ? "\u5B9E\u666F AR \u6A21\u5F0F" : "\u70B9\u51FB\u653E\u7F6E\u6A21\u578B" : "\u7B49\u5F85\u6444\u50CF\u5934..."), /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col gap-2" }, showSettings && /* @__PURE__ */ React10__default.default.createElement(
6251
6631
  "button",
6252
6632
  {
6253
6633
  onClick: () => setIsSettingsOpen(!isSettingsOpen),
6254
- className: `p-3 backdrop-blur-md rounded-full text-white transition-all active:scale-95 pointer-events-auto ${isSettingsOpen ? "bg-blue-500" : "bg-white/10 hover:bg-white/20"}`,
6255
- title: "\u8BBE\u7F6E\u6A21\u578B\u4E0E\u52A8\u4F5C"
6634
+ className: `p-3 backdrop-blur-md rounded-full text-white transition-all active:scale-95 pointer-events-auto ${isSettingsOpen ? "bg-cyan-500" : "bg-white/10 hover:bg-white/20"}`,
6635
+ title: "\u8BBE\u7F6E"
6256
6636
  },
6257
6637
  /* @__PURE__ */ React10__default.default.createElement(lucideReact.Settings, { className: "w-5 h-5" })
6258
6638
  ), /* @__PURE__ */ React10__default.default.createElement(
@@ -6271,45 +6651,59 @@ var MMDARPlayer = React10.forwardRef((props, ref) => {
6271
6651
  title: isCameraStarted ? "\u5173\u95ED\u6444\u50CF\u5934" : "\u5F00\u542F\u6444\u50CF\u5934"
6272
6652
  },
6273
6653
  isCameraStarted ? /* @__PURE__ */ React10__default.default.createElement(lucideReact.CameraOff, { className: "w-5 h-5" }) : /* @__PURE__ */ React10__default.default.createElement(lucideReact.Camera, { className: "w-5 h-5" })
6274
- ))), isSettingsOpen && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-20 right-6 w-80 bg-black/80 backdrop-blur-xl border border-white/10 rounded-2xl p-6 pointer-events-auto shadow-2xl animate-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center justify-between mb-6" }, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "text-white font-bold flex items-center gap-2" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Settings, { className: "w-4 h-4" }), "\u8D44\u6E90\u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement(
6654
+ ))), isSettingsOpen && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-20 right-6 w-72 bg-black/90 backdrop-blur-xl border border-white/10 rounded-2xl p-5 pointer-events-auto shadow-2xl animate-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center justify-between mb-5" }, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "text-white font-bold flex items-center gap-2" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Settings, { className: "w-4 h-4 text-cyan-400" }), "AR \u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement(
6275
6655
  "button",
6276
6656
  {
6277
6657
  onClick: () => setIsSettingsOpen(false),
6278
- className: "p-1 hover:bg-white/10 rounded-full transition-colors text-white/60"
6658
+ className: "p-1.5 hover:bg-white/10 rounded-full transition-colors text-white/60"
6279
6659
  },
6280
6660
  /* @__PURE__ */ React10__default.default.createElement(lucideReact.X, { className: "w-4 h-4" })
6281
- )), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs font-medium text-white/50 mb-1.5 ml-1 uppercase tracking-wider" }, "\u6A21\u578B\u8DEF\u5F84 (.pmx)"), /* @__PURE__ */ React10__default.default.createElement(
6282
- "input",
6661
+ )), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React10__default.default.createElement(
6662
+ Select,
6283
6663
  {
6284
- type: "text",
6285
- value: tempResources.modelPath,
6286
- onChange: (e) => setTempResources({ ...tempResources, modelPath: e.target.value }),
6287
- placeholder: "\u8BF7\u8F93\u5165\u6A21\u578B URL...",
6288
- className: "w-full bg-white/5 border border-white/10 rounded-xl px-4 py-2.5 text-sm text-white placeholder:text-white/10 focus:outline-none focus:border-blue-500/50 transition-colors"
6664
+ label: "\u9009\u62E9\u6A21\u578B",
6665
+ options: modelPresets,
6666
+ value: selectedModelId,
6667
+ onChange: setSelectedModelId,
6668
+ placeholder: "\u8BF7\u9009\u62E9\u6A21\u578B..."
6289
6669
  }
6290
- )), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs font-medium text-white/50 mb-1.5 ml-1 uppercase tracking-wider" }, "\u52A8\u4F5C\u8DEF\u5F84 (.vmd)"), /* @__PURE__ */ React10__default.default.createElement(
6291
- "input",
6670
+ ), /* @__PURE__ */ React10__default.default.createElement(
6671
+ Select,
6292
6672
  {
6293
- type: "text",
6294
- value: tempResources.motionPath || "",
6295
- onChange: (e) => setTempResources({ ...tempResources, motionPath: e.target.value }),
6296
- placeholder: "\u8BF7\u8F93\u5165\u52A8\u4F5C URL...",
6297
- className: "w-full bg-white/5 border border-white/10 rounded-xl px-4 py-2.5 text-sm text-white placeholder:text-white/10 focus:outline-none focus:border-blue-500/50 transition-colors"
6298
- }
6299
- )), /* @__PURE__ */ React10__default.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ React10__default.default.createElement(
6673
+ label: "\u9009\u62E9\u52A8\u4F5C",
6674
+ options: motionPresets,
6675
+ value: selectedMotionId,
6676
+ onChange: setSelectedMotionId,
6677
+ placeholder: "\u8BF7\u9009\u62E9\u52A8\u4F5C..."
6678
+ }
6679
+ ), audioPresets.length > 0 && /* @__PURE__ */ React10__default.default.createElement(
6680
+ Select,
6681
+ {
6682
+ label: "\u9009\u62E9\u97F3\u4E50",
6683
+ options: audioPresets,
6684
+ value: selectedAudioId,
6685
+ onChange: setSelectedAudioId,
6686
+ placeholder: "\u8BF7\u9009\u62E9\u97F3\u4E50...",
6687
+ allowEmpty: true,
6688
+ emptyLabel: "\u{1F507} \u4E0D\u64AD\u653E\u97F3\u4E50"
6689
+ }
6690
+ ), /* @__PURE__ */ React10__default.default.createElement("div", { className: "pt-3 space-y-2" }, isModelPlaced && /* @__PURE__ */ React10__default.default.createElement(
6300
6691
  "button",
6301
6692
  {
6302
- onClick: () => {
6303
- setCurrentResources(tempResources);
6304
- onResourcesChange?.(tempResources);
6305
- setIsSettingsOpen(false);
6306
- setIsLoading(true);
6307
- },
6308
- className: "w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 rounded-xl flex items-center justify-center gap-2 transition-all active:scale-95 shadow-lg shadow-blue-500/20"
6693
+ onClick: applySettings,
6694
+ className: "w-full bg-cyan-500 hover:bg-cyan-600 text-white font-bold py-3 rounded-xl flex items-center justify-center gap-2 transition-all active:scale-95 shadow-lg shadow-cyan-500/20"
6309
6695
  },
6310
- /* @__PURE__ */ React10__default.default.createElement(lucideReact.Check, { className: "w-4 h-4" }),
6696
+ /* @__PURE__ */ React10__default.default.createElement(lucideReact.Sparkles, { className: "w-4 h-4" }),
6311
6697
  "\u5E94\u7528\u66F4\u6539"
6312
- )))), isLoading && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col items-center gap-3" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "w-12 h-12 border-4 border-blue-500/30 border-t-blue-500 rounded-full animate-spin" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-white text-sm font-medium bg-black/40 px-3 py-1 rounded-full backdrop-blur-sm" }, "\u6B63\u5728\u52A0\u8F7D Miku \u8D44\u6E90..."))))
6698
+ ), /* @__PURE__ */ React10__default.default.createElement(
6699
+ "button",
6700
+ {
6701
+ onClick: resetPosition,
6702
+ className: `w-full ${isModelPlaced ? "bg-white/5 hover:bg-white/10 text-white/70" : "bg-cyan-500 hover:bg-cyan-600 text-white shadow-lg shadow-cyan-500/20"} font-medium py-3 rounded-xl flex items-center justify-center gap-2 transition-all active:scale-95 border border-white/10`
6703
+ },
6704
+ /* @__PURE__ */ React10__default.default.createElement(lucideReact.RotateCcw, { className: "w-4 h-4" }),
6705
+ isModelPlaced ? "\u91CD\u7F6E\u4F4D\u7F6E" : "\u5F00\u59CB\u653E\u7F6E"
6706
+ )))), isLoading && isModelPlaced && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col items-center gap-3" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "w-12 h-12 border-4 border-cyan-500/30 border-t-cyan-500 rounded-full animate-spin" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-white text-sm font-medium bg-black/40 px-3 py-1 rounded-full backdrop-blur-sm" }, "\u6B63\u5728\u53EC\u5524 Miku..."))))
6313
6707
  );
6314
6708
  });
6315
6709
  MMDARPlayer.displayName = "MMDARPlayer";
@@ -8428,6 +8822,8 @@ exports.MMDPlayerEnhancedDebugInfo = MMDPlayerEnhancedDebugInfo;
8428
8822
  exports.MMDPlaylist = MMDPlaylist;
8429
8823
  exports.MMDPlaylistDebugInfo = MMDPlaylistDebugInfo;
8430
8824
  exports.MMDVisualNovel = MMDVisualNovel;
8825
+ exports.MMDVisualNovelWithSelector = MMDVisualNovelWithSelector;
8826
+ exports.ModelSelectorSettings = ModelSelectorSettings;
8431
8827
  exports.MultiFXAdapter = MultiFXAdapter;
8432
8828
  exports.MusicControls = MusicControls;
8433
8829
  exports.PMXEditor = PMXEditor2;