sa2kit 1.6.60 → 1.6.62

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 (297) hide show
  1. package/dist/UniversalFileService-C3WQAFOV.js +15 -0
  2. package/dist/{UniversalFileService-J6ET6KZK.js.map → UniversalFileService-C3WQAFOV.js.map} +1 -1
  3. package/dist/UniversalFileService-O3IEROBN.mjs +6 -0
  4. package/dist/{UniversalFileService-336GFY6N.mjs.map → UniversalFileService-O3IEROBN.mjs.map} +1 -1
  5. package/dist/ai/llm/index.d.mts +70 -0
  6. package/dist/ai/llm/index.d.ts +70 -0
  7. package/dist/ai/llm/index.js +54 -0
  8. package/dist/ai/llm/index.js.map +1 -0
  9. package/dist/ai/llm/index.mjs +5 -0
  10. package/dist/ai/llm/index.mjs.map +1 -0
  11. package/dist/ai/llm/ui/electron/index.d.mts +5 -0
  12. package/dist/ai/llm/ui/electron/index.d.ts +5 -0
  13. package/dist/ai/llm/ui/electron/index.js +21 -0
  14. package/dist/ai/llm/ui/electron/index.js.map +1 -0
  15. package/dist/ai/llm/ui/electron/index.mjs +8 -0
  16. package/dist/ai/llm/ui/electron/index.mjs.map +1 -0
  17. package/dist/ai/llm/ui/miniapp/index.d.mts +9 -0
  18. package/dist/ai/llm/ui/miniapp/index.d.ts +9 -0
  19. package/dist/ai/llm/ui/miniapp/index.js +107 -0
  20. package/dist/ai/llm/ui/miniapp/index.js.map +1 -0
  21. package/dist/ai/llm/ui/miniapp/index.mjs +101 -0
  22. package/dist/ai/llm/ui/miniapp/index.mjs.map +1 -0
  23. package/dist/ai/llm/ui/rn/index.d.mts +9 -0
  24. package/dist/ai/llm/ui/rn/index.d.ts +9 -0
  25. package/dist/ai/llm/ui/rn/index.js +249 -0
  26. package/dist/ai/llm/ui/rn/index.js.map +1 -0
  27. package/dist/ai/llm/ui/rn/index.mjs +243 -0
  28. package/dist/ai/llm/ui/rn/index.mjs.map +1 -0
  29. package/dist/ai/llm/ui/web/index.d.mts +15 -0
  30. package/dist/ai/llm/ui/web/index.d.ts +15 -0
  31. package/dist/ai/llm/ui/web/index.js +21 -0
  32. package/dist/ai/llm/ui/web/index.js.map +1 -0
  33. package/dist/ai/llm/ui/web/index.mjs +8 -0
  34. package/dist/ai/llm/ui/web/index.mjs.map +1 -0
  35. package/dist/ar/index.d.mts +7 -0
  36. package/dist/ar/index.d.ts +7 -0
  37. package/dist/ar/index.js +17 -0
  38. package/dist/ar/index.js.map +1 -0
  39. package/dist/ar/index.mjs +4 -0
  40. package/dist/ar/index.mjs.map +1 -0
  41. package/dist/auth/index.js +22 -22
  42. package/dist/auth/index.mjs +2 -2
  43. package/dist/auth/legacy/db/index.d.mts +5 -0
  44. package/dist/auth/legacy/db/index.d.ts +5 -0
  45. package/dist/auth/legacy/db/index.js +34 -0
  46. package/dist/auth/legacy/db/index.js.map +1 -0
  47. package/dist/auth/legacy/db/index.mjs +5 -0
  48. package/dist/auth/legacy/db/index.mjs.map +1 -0
  49. package/dist/auth/legacy/index.d.mts +51 -0
  50. package/dist/auth/legacy/index.d.ts +51 -0
  51. package/dist/auth/legacy/index.js +146 -0
  52. package/dist/auth/legacy/index.js.map +1 -0
  53. package/dist/auth/legacy/index.mjs +13 -0
  54. package/dist/auth/legacy/index.mjs.map +1 -0
  55. package/dist/auth/legacy/logic/index.d.mts +9 -0
  56. package/dist/auth/legacy/logic/index.d.ts +9 -0
  57. package/dist/auth/legacy/logic/index.js +18 -0
  58. package/dist/auth/legacy/logic/index.js.map +1 -0
  59. package/dist/auth/legacy/logic/index.mjs +5 -0
  60. package/dist/auth/legacy/logic/index.mjs.map +1 -0
  61. package/dist/auth/legacy/routes/index.d.mts +50 -0
  62. package/dist/auth/legacy/routes/index.d.ts +50 -0
  63. package/dist/auth/legacy/routes/index.js +34 -0
  64. package/dist/auth/legacy/routes/index.js.map +1 -0
  65. package/dist/auth/legacy/routes/index.mjs +5 -0
  66. package/dist/auth/legacy/routes/index.mjs.map +1 -0
  67. package/dist/auth/legacy/schema/index.d.mts +401 -0
  68. package/dist/auth/legacy/schema/index.d.ts +401 -0
  69. package/dist/auth/legacy/schema/index.js +29 -0
  70. package/dist/auth/legacy/schema/index.js.map +1 -0
  71. package/dist/auth/legacy/schema/index.mjs +4 -0
  72. package/dist/auth/legacy/schema/index.mjs.map +1 -0
  73. package/dist/auth/legacy/server/index.d.mts +15 -0
  74. package/dist/auth/legacy/server/index.d.ts +15 -0
  75. package/dist/auth/legacy/server/index.js +65 -0
  76. package/dist/auth/legacy/server/index.js.map +1 -0
  77. package/dist/auth/legacy/server/index.mjs +8 -0
  78. package/dist/auth/legacy/server/index.mjs.map +1 -0
  79. package/dist/auth/legacy/services/index.d.mts +40 -0
  80. package/dist/auth/legacy/services/index.d.ts +40 -0
  81. package/dist/auth/legacy/services/index.js +14 -0
  82. package/dist/auth/legacy/services/index.js.map +1 -0
  83. package/dist/auth/legacy/services/index.mjs +5 -0
  84. package/dist/auth/legacy/services/index.mjs.map +1 -0
  85. package/dist/auth/legacy/ui/miniapp/index.d.mts +10 -0
  86. package/dist/auth/legacy/ui/miniapp/index.d.ts +10 -0
  87. package/dist/auth/legacy/ui/miniapp/index.js +23 -0
  88. package/dist/auth/legacy/ui/miniapp/index.js.map +1 -0
  89. package/dist/auth/legacy/ui/miniapp/index.mjs +6 -0
  90. package/dist/auth/legacy/ui/miniapp/index.mjs.map +1 -0
  91. package/dist/auth/legacy/ui/web/index.d.mts +22 -0
  92. package/dist/auth/legacy/ui/web/index.d.ts +22 -0
  93. package/dist/auth/legacy/ui/web/index.js +31 -0
  94. package/dist/auth/legacy/ui/web/index.js.map +1 -0
  95. package/dist/auth/legacy/ui/web/index.mjs +6 -0
  96. package/dist/auth/legacy/ui/web/index.mjs.map +1 -0
  97. package/dist/calendar/index.d.mts +390 -237
  98. package/dist/calendar/index.d.ts +390 -237
  99. package/dist/calendar/index.js +3825 -3785
  100. package/dist/calendar/index.js.map +1 -1
  101. package/dist/calendar/index.mjs +3730 -3696
  102. package/dist/calendar/index.mjs.map +1 -1
  103. package/dist/calendar/routes/index.js +30 -327
  104. package/dist/calendar/routes/index.js.map +1 -1
  105. package/dist/calendar/routes/index.mjs +1 -323
  106. package/dist/calendar/routes/index.mjs.map +1 -1
  107. package/dist/calendar/server.d.mts +6 -0
  108. package/dist/calendar/server.d.ts +6 -0
  109. package/dist/calendar/server.js +41 -13
  110. package/dist/calendar/server.js.map +1 -1
  111. package/dist/calendar/server.mjs +2 -2
  112. package/dist/calendar/server.mjs.map +1 -1
  113. package/dist/chunk-24F7KUED.js +263 -0
  114. package/dist/chunk-24F7KUED.js.map +1 -0
  115. package/dist/{chunk-YMS6BPXS.js → chunk-27IUMDDK.js} +3 -3
  116. package/dist/{chunk-YMS6BPXS.js.map → chunk-27IUMDDK.js.map} +1 -1
  117. package/dist/chunk-37M6NZIF.js +279 -0
  118. package/dist/chunk-37M6NZIF.js.map +1 -0
  119. package/dist/chunk-3JMUNOUT.js +144 -0
  120. package/dist/chunk-3JMUNOUT.js.map +1 -0
  121. package/dist/chunk-3PFCOTJP.mjs +256 -0
  122. package/dist/chunk-3PFCOTJP.mjs.map +1 -0
  123. package/dist/{chunk-NZZZUMMX.mjs → chunk-57MVE5LL.mjs} +3 -3
  124. package/dist/{chunk-NZZZUMMX.mjs.map → chunk-57MVE5LL.mjs.map} +1 -1
  125. package/dist/{chunk-622Y6LTH.mjs → chunk-5BLZEVWK.mjs} +196 -468
  126. package/dist/chunk-5BLZEVWK.mjs.map +1 -0
  127. package/dist/{chunk-YN4MJFIG.js → chunk-5LCGOCKG.js} +5 -5
  128. package/dist/{chunk-YN4MJFIG.js.map → chunk-5LCGOCKG.js.map} +1 -1
  129. package/dist/chunk-6XUQ2B4K.js +219 -0
  130. package/dist/chunk-6XUQ2B4K.js.map +1 -0
  131. package/dist/{chunk-NCOXT7SK.js → chunk-77UEPWVQ.js} +4 -4
  132. package/dist/{chunk-NCOXT7SK.js.map → chunk-77UEPWVQ.js.map} +1 -1
  133. package/dist/chunk-CFM56MGO.mjs +35 -0
  134. package/dist/chunk-CFM56MGO.mjs.map +1 -0
  135. package/dist/chunk-CPSFYP34.mjs +140 -0
  136. package/dist/chunk-CPSFYP34.mjs.map +1 -0
  137. package/dist/chunk-D22QBOCM.mjs +336 -0
  138. package/dist/chunk-D22QBOCM.mjs.map +1 -0
  139. package/dist/chunk-DA4QV64P.mjs +35 -0
  140. package/dist/chunk-DA4QV64P.mjs.map +1 -0
  141. package/dist/chunk-EKDLZND6.js +275 -0
  142. package/dist/chunk-EKDLZND6.js.map +1 -0
  143. package/dist/chunk-EKQPFZXQ.js +12 -0
  144. package/dist/chunk-EKQPFZXQ.js.map +1 -0
  145. package/dist/chunk-ERAAB5VG.js +324 -0
  146. package/dist/chunk-ERAAB5VG.js.map +1 -0
  147. package/dist/chunk-ESLY72VI.mjs +175 -0
  148. package/dist/chunk-ESLY72VI.mjs.map +1 -0
  149. package/dist/chunk-FGQGWW73.js +38 -0
  150. package/dist/chunk-FGQGWW73.js.map +1 -0
  151. package/dist/chunk-FXQOXLDE.js +120 -0
  152. package/dist/chunk-FXQOXLDE.js.map +1 -0
  153. package/dist/chunk-FZELCJR7.mjs +19 -0
  154. package/dist/chunk-FZELCJR7.mjs.map +1 -0
  155. package/dist/{chunk-HHVDOIPV.js → chunk-H3P2PGZL.js} +3 -3
  156. package/dist/{chunk-HHVDOIPV.js.map → chunk-H3P2PGZL.js.map} +1 -1
  157. package/dist/chunk-HBQMN5QM.mjs +10 -0
  158. package/dist/chunk-HBQMN5QM.mjs.map +1 -0
  159. package/dist/chunk-ITRIXMXF.mjs +862 -0
  160. package/dist/chunk-ITRIXMXF.mjs.map +1 -0
  161. package/dist/chunk-IUWSCUDC.js +4 -0
  162. package/dist/chunk-IUWSCUDC.js.map +1 -0
  163. package/dist/chunk-JCKCKRC2.js +50 -0
  164. package/dist/chunk-JCKCKRC2.js.map +1 -0
  165. package/dist/chunk-L7GQNY54.mjs +286 -0
  166. package/dist/chunk-L7GQNY54.mjs.map +1 -0
  167. package/dist/{chunk-ZRWED7Q6.js → chunk-LDVJ7URJ.js} +235 -520
  168. package/dist/chunk-LDVJ7URJ.js.map +1 -0
  169. package/dist/{chunk-CYTXGBP2.js → chunk-MLP74E3O.js} +573 -1607
  170. package/dist/chunk-MLP74E3O.js.map +1 -0
  171. package/dist/chunk-NAX4TUT7.js +182 -0
  172. package/dist/chunk-NAX4TUT7.js.map +1 -0
  173. package/dist/chunk-NW4EN4YI.mjs +213 -0
  174. package/dist/chunk-NW4EN4YI.mjs.map +1 -0
  175. package/dist/chunk-P3QMT3AY.mjs +44 -0
  176. package/dist/chunk-P3QMT3AY.mjs.map +1 -0
  177. package/dist/chunk-PJ4KYAQZ.mjs +631 -0
  178. package/dist/chunk-PJ4KYAQZ.mjs.map +1 -0
  179. package/dist/chunk-PLSEAREM.js +345 -0
  180. package/dist/chunk-PLSEAREM.js.map +1 -0
  181. package/dist/{chunk-EGJPS7OL.mjs → chunk-QZU4UJZG.mjs} +3 -3
  182. package/dist/{chunk-EGJPS7OL.mjs.map → chunk-QZU4UJZG.mjs.map} +1 -1
  183. package/dist/chunk-RJVR33ME.mjs +3 -0
  184. package/dist/chunk-RJVR33ME.mjs.map +1 -0
  185. package/dist/chunk-SYBHDB2D.js +650 -0
  186. package/dist/chunk-SYBHDB2D.js.map +1 -0
  187. package/dist/chunk-TVKVM7JT.js +21 -0
  188. package/dist/chunk-TVKVM7JT.js.map +1 -0
  189. package/dist/{chunk-PONZPO3U.mjs → chunk-UTB72ZJ7.mjs} +414 -1448
  190. package/dist/chunk-UTB72ZJ7.mjs.map +1 -0
  191. package/dist/chunk-V7EVKD5G.mjs +116 -0
  192. package/dist/chunk-V7EVKD5G.mjs.map +1 -0
  193. package/dist/chunk-VGPR3KLR.js +872 -0
  194. package/dist/chunk-VGPR3KLR.js.map +1 -0
  195. package/dist/chunk-VS7WATQD.js +255 -0
  196. package/dist/chunk-VS7WATQD.js.map +1 -0
  197. package/dist/chunk-VSP7XJT5.mjs +272 -0
  198. package/dist/chunk-VSP7XJT5.mjs.map +1 -0
  199. package/dist/{chunk-CSDIPQQO.mjs → chunk-VTKAIOP5.mjs} +5 -5
  200. package/dist/{chunk-CSDIPQQO.mjs.map → chunk-VTKAIOP5.mjs.map} +1 -1
  201. package/dist/chunk-VULJUXTF.mjs +267 -0
  202. package/dist/chunk-VULJUXTF.mjs.map +1 -0
  203. package/dist/chunk-XAHM6B3V.js +44 -0
  204. package/dist/chunk-XAHM6B3V.js.map +1 -0
  205. package/dist/chunk-YSF5YISM.mjs +248 -0
  206. package/dist/chunk-YSF5YISM.mjs.map +1 -0
  207. package/dist/{chunk-OFYBMMWT.mjs → chunk-YYJEVAJI.mjs} +3 -3
  208. package/dist/{chunk-OFYBMMWT.mjs.map → chunk-YYJEVAJI.mjs.map} +1 -1
  209. package/dist/components/index.d.mts +1 -0
  210. package/dist/components/index.d.ts +1 -0
  211. package/dist/components/index.js +182 -181
  212. package/dist/components/index.mjs +4 -3
  213. package/dist/index-DNKZ7-R_.d.mts +184 -0
  214. package/dist/index-DNKZ7-R_.d.ts +184 -0
  215. package/dist/index.d.mts +4 -1
  216. package/dist/index.d.ts +4 -1
  217. package/dist/index.js +285 -229
  218. package/dist/index.js.map +1 -1
  219. package/dist/index.mjs +15 -10
  220. package/dist/index.mjs.map +1 -1
  221. package/dist/mikuFusionGame/index.js +3 -3
  222. package/dist/mikuFusionGame/index.mjs +2 -2
  223. package/dist/mmd/index.d.mts +67 -9
  224. package/dist/mmd/index.d.ts +67 -9
  225. package/dist/mmd/index.js +969 -625
  226. package/dist/mmd/index.js.map +1 -1
  227. package/dist/mmd/index.mjs +969 -628
  228. package/dist/mmd/index.mjs.map +1 -1
  229. package/dist/portfolio/index.js +10 -9
  230. package/dist/portfolio/index.mjs +5 -4
  231. package/dist/qqbot/index.d.mts +2 -0
  232. package/dist/qqbot/index.d.ts +2 -0
  233. package/dist/qqbot/index.js +21 -0
  234. package/dist/qqbot/index.js.map +1 -0
  235. package/dist/qqbot/index.mjs +4 -0
  236. package/dist/qqbot/index.mjs.map +1 -0
  237. package/dist/qqbot/server/index.d.mts +91 -0
  238. package/dist/qqbot/server/index.d.ts +91 -0
  239. package/dist/qqbot/server/index.js +21 -0
  240. package/dist/qqbot/server/index.js.map +1 -0
  241. package/dist/qqbot/server/index.mjs +4 -0
  242. package/dist/qqbot/server/index.mjs.map +1 -0
  243. package/dist/qqbot/ui/web/index.d.mts +10 -0
  244. package/dist/qqbot/ui/web/index.d.ts +10 -0
  245. package/dist/qqbot/ui/web/index.js +105 -0
  246. package/dist/qqbot/ui/web/index.js.map +1 -0
  247. package/dist/qqbot/ui/web/index.mjs +99 -0
  248. package/dist/qqbot/ui/web/index.mjs.map +1 -0
  249. package/dist/screenReceiver/index.d.mts +78 -0
  250. package/dist/screenReceiver/index.d.ts +78 -0
  251. package/dist/screenReceiver/index.js +17 -0
  252. package/dist/screenReceiver/index.js.map +1 -0
  253. package/dist/screenReceiver/index.mjs +4 -0
  254. package/dist/screenReceiver/index.mjs.map +1 -0
  255. package/dist/screenReceiver/server/index.d.mts +36 -0
  256. package/dist/screenReceiver/server/index.d.ts +36 -0
  257. package/dist/screenReceiver/server/index.js +160 -0
  258. package/dist/screenReceiver/server/index.js.map +1 -0
  259. package/dist/screenReceiver/server/index.mjs +157 -0
  260. package/dist/screenReceiver/server/index.mjs.map +1 -0
  261. package/dist/showmasterpiece/db/index.js +42 -42
  262. package/dist/showmasterpiece/db/index.mjs +1 -1
  263. package/dist/showmasterpiece/index.js +52 -41
  264. package/dist/showmasterpiece/index.js.map +1 -1
  265. package/dist/showmasterpiece/index.mjs +15 -4
  266. package/dist/showmasterpiece/index.mjs.map +1 -1
  267. package/dist/showmasterpiece/server/index.js +42 -42
  268. package/dist/showmasterpiece/server/index.mjs +1 -1
  269. package/dist/showmasterpiece/ui/miniapp/index.d.mts +2 -0
  270. package/dist/showmasterpiece/ui/miniapp/index.d.ts +2 -0
  271. package/dist/showmasterpiece/ui/miniapp/index.js +83 -55
  272. package/dist/showmasterpiece/ui/miniapp/index.js.map +1 -1
  273. package/dist/showmasterpiece/ui/miniapp/index.mjs +83 -55
  274. package/dist/showmasterpiece/ui/miniapp/index.mjs.map +1 -1
  275. package/dist/showmasterpiece/ui/web/index.js +43 -32
  276. package/dist/showmasterpiece/ui/web/index.mjs +15 -4
  277. package/dist/testYourself/index.js +13 -13
  278. package/dist/testYourself/index.mjs +2 -2
  279. package/dist/types-B-hOccQw.d.mts +122 -0
  280. package/dist/types-B8rGXc4e.d.mts +38 -0
  281. package/dist/types-Cg89HGz2.d.ts +38 -0
  282. package/dist/types-CvKvpyN8.d.mts +48 -0
  283. package/dist/types-CvKvpyN8.d.ts +48 -0
  284. package/dist/types-Dy6x2gJW.d.ts +122 -0
  285. package/dist/universalFile/server/index.js +11 -11
  286. package/dist/universalFile/server/index.mjs +4 -4
  287. package/package.json +101 -1
  288. package/dist/UniversalFileService-336GFY6N.mjs +0 -6
  289. package/dist/UniversalFileService-J6ET6KZK.js +0 -15
  290. package/dist/chunk-622Y6LTH.mjs.map +0 -1
  291. package/dist/chunk-CYTXGBP2.js.map +0 -1
  292. package/dist/chunk-GVVS4IMM.mjs +0 -302
  293. package/dist/chunk-GVVS4IMM.mjs.map +0 -1
  294. package/dist/chunk-PONZPO3U.mjs.map +0 -1
  295. package/dist/chunk-WC5QFO3T.js +0 -314
  296. package/dist/chunk-WC5QFO3T.js.map +0 -1
  297. package/dist/chunk-ZRWED7Q6.js.map +0 -1
package/dist/mmd/index.js CHANGED
@@ -3,14 +3,15 @@
3
3
  var chunkUIFFDRTE_js = require('../chunk-UIFFDRTE.js');
4
4
  var chunkTDCDEBGP_js = require('../chunk-TDCDEBGP.js');
5
5
  require('../chunk-WA67GZSZ.js');
6
+ var chunkFGQGWW73_js = require('../chunk-FGQGWW73.js');
6
7
  require('../chunk-Z6ZWNWWR.js');
7
8
  var React10 = require('react');
8
9
  var clsx = require('clsx');
9
10
  var THREE2 = require('three');
10
11
  var threeStdlib = require('three-stdlib');
11
12
  var lucideReact = require('lucide-react');
13
+ var JSZip = require('jszip');
12
14
  var reactDom = require('react-dom');
13
- var Script = require('next/script');
14
15
 
15
16
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
17
 
@@ -34,7 +35,7 @@ function _interopNamespace(e) {
34
35
 
35
36
  var React10__default = /*#__PURE__*/_interopDefault(React10);
36
37
  var THREE2__namespace = /*#__PURE__*/_interopNamespace(THREE2);
37
- var Script__default = /*#__PURE__*/_interopDefault(Script);
38
+ var JSZip__default = /*#__PURE__*/_interopDefault(JSZip);
38
39
 
39
40
  // src/mmd/pmx/editor/PMXEditor.ts
40
41
  var PMXEditor = class {
@@ -3438,6 +3439,188 @@ var MMDLightingDebugPanel = ({
3438
3439
  ));
3439
3440
  };
3440
3441
  MMDLightingDebugPanel.displayName = "MMDLightingDebugPanel";
3442
+ var MMD_UPLOAD_CONFIGS = {
3443
+ model: {
3444
+ moduleId: "mmd-models",
3445
+ acceptedTypes: [".zip"],
3446
+ maxFileSize: 150,
3447
+ description: "MMD model package (ZIP)",
3448
+ hint: "Include PMX/PMD and textures in the ZIP with original folder structure."
3449
+ },
3450
+ motion: {
3451
+ moduleId: "mmd-motions",
3452
+ acceptedTypes: [".vmd"],
3453
+ maxFileSize: 20,
3454
+ description: "MMD motion file"
3455
+ },
3456
+ camera: {
3457
+ moduleId: "mmd-cameras",
3458
+ acceptedTypes: [".vmd"],
3459
+ maxFileSize: 10,
3460
+ description: "MMD camera motion"
3461
+ },
3462
+ audio: {
3463
+ moduleId: "mmd-audios",
3464
+ acceptedTypes: [".mp3", ".wav", ".ogg", ".m4a"],
3465
+ maxFileSize: 20,
3466
+ description: "Audio track"
3467
+ },
3468
+ stage: {
3469
+ moduleId: "mmd-stages",
3470
+ acceptedTypes: [".zip"],
3471
+ maxFileSize: 200,
3472
+ description: "Stage package (ZIP)",
3473
+ hint: "Include stage model and textures in the ZIP with original folder structure."
3474
+ },
3475
+ thumbnail: {
3476
+ moduleId: "mmd-thumbnails",
3477
+ acceptedTypes: [".jpg", ".jpeg", ".png", ".webp"],
3478
+ maxFileSize: 5,
3479
+ description: "Thumbnail image"
3480
+ }
3481
+ };
3482
+ var formatMegabytes = (size) => `${(size / 1024 / 1024).toFixed(2)} MB`;
3483
+ var MMDUploadPanel = ({
3484
+ resourceType,
3485
+ fileService,
3486
+ userId,
3487
+ permission = "public",
3488
+ label,
3489
+ description,
3490
+ hint,
3491
+ acceptedTypes,
3492
+ maxFileSizeMB,
3493
+ validateZip = true,
3494
+ disabled = false,
3495
+ className,
3496
+ style,
3497
+ onUploaded,
3498
+ onError,
3499
+ onProgress
3500
+ }) => {
3501
+ const inputId = React10.useId();
3502
+ const [uploading, setUploading] = React10.useState(false);
3503
+ const [progress, setProgress] = React10.useState(null);
3504
+ const [error, setError] = React10.useState(null);
3505
+ const [uploadedFile, setUploadedFile] = React10.useState(null);
3506
+ const [uploadedUrl, setUploadedUrl] = React10.useState(null);
3507
+ const [dragOver, setDragOver] = React10.useState(false);
3508
+ const config = MMD_UPLOAD_CONFIGS[resourceType];
3509
+ const mergedAcceptedTypes = acceptedTypes ?? config.acceptedTypes;
3510
+ const maxSize = maxFileSizeMB ?? config.maxFileSize;
3511
+ const hintText = hint ?? config.hint;
3512
+ const titleText = label ?? config.description;
3513
+ const descriptionText = description ?? `Max ${maxSize} MB`;
3514
+ const acceptAttr = React10.useMemo(() => mergedAcceptedTypes.join(","), [mergedAcceptedTypes]);
3515
+ const validateZipContents = async (file) => {
3516
+ if (!validateZip || !(resourceType === "model" || resourceType === "stage")) return;
3517
+ const buffer = await file.arrayBuffer();
3518
+ const zip = await JSZip__default.default.loadAsync(buffer);
3519
+ const entries = Object.keys(zip.files);
3520
+ if (!entries.length) {
3521
+ throw new Error("ZIP is empty.");
3522
+ }
3523
+ const hasModel = entries.some((name) => /\.[pP][mM][xX]$/.test(name)) || resourceType === "stage" && entries.some((name) => /\.[pP][mM][dD]$/.test(name));
3524
+ const hasAssets = entries.some(
3525
+ (name) => /\.(png|jpg|jpeg|bmp|tga|dds|spa|sph)$/i.test(name)
3526
+ );
3527
+ if (!hasModel) {
3528
+ throw new Error("ZIP does not contain a PMX/PMD model file.");
3529
+ }
3530
+ if (!hasAssets) {
3531
+ throw new Error("ZIP does not include texture assets.");
3532
+ }
3533
+ };
3534
+ const handleUpload = async (file) => {
3535
+ if (disabled || uploading) return;
3536
+ setError(null);
3537
+ setProgress(null);
3538
+ if (file.size > maxSize * 1024 * 1024) {
3539
+ setError(`File size exceeds ${maxSize} MB.`);
3540
+ return;
3541
+ }
3542
+ try {
3543
+ setUploading(true);
3544
+ await validateZipContents(file);
3545
+ const fileInfo = {
3546
+ file,
3547
+ moduleId: config.moduleId,
3548
+ businessId: userId,
3549
+ permission
3550
+ };
3551
+ const metadata = await fileService.uploadFile(fileInfo, (progressEvent) => {
3552
+ setProgress(progressEvent);
3553
+ onProgress?.(progressEvent);
3554
+ });
3555
+ let url;
3556
+ if (fileService.getFileUrl) {
3557
+ url = await fileService.getFileUrl(metadata.id);
3558
+ setUploadedUrl(url ?? null);
3559
+ } else {
3560
+ setUploadedUrl(null);
3561
+ }
3562
+ setUploadedFile(metadata);
3563
+ setUploading(false);
3564
+ onUploaded?.({ file: metadata, url });
3565
+ } catch (err) {
3566
+ const message = err instanceof Error ? err.message : "Upload failed.";
3567
+ setError(message);
3568
+ setUploading(false);
3569
+ onError?.(err instanceof Error ? err : new Error(message));
3570
+ }
3571
+ };
3572
+ const handleFileInput = (event) => {
3573
+ const file = event.target.files?.[0];
3574
+ if (file) {
3575
+ handleUpload(file);
3576
+ }
3577
+ };
3578
+ const handleDrop = (event) => {
3579
+ event.preventDefault();
3580
+ setDragOver(false);
3581
+ const file = event.dataTransfer.files?.[0];
3582
+ if (file) {
3583
+ handleUpload(file);
3584
+ }
3585
+ };
3586
+ return /* @__PURE__ */ React10__default.default.createElement("div", { className: clsx.clsx("space-y-4", className), style }, /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-sm font-semibold text-gray-900" }, titleText), /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-xs text-gray-500" }, descriptionText), hintText && /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-xs text-amber-600 mt-1" }, hintText)), /* @__PURE__ */ React10__default.default.createElement(
3587
+ "div",
3588
+ {
3589
+ className: clsx.clsx(
3590
+ "rounded-lg border-2 border-dashed px-4 py-6 text-center transition-colors",
3591
+ dragOver ? "border-blue-500 bg-blue-50" : "border-gray-300",
3592
+ disabled ? "opacity-50 pointer-events-none" : "cursor-pointer"
3593
+ ),
3594
+ onDragOver: (event) => {
3595
+ event.preventDefault();
3596
+ setDragOver(true);
3597
+ },
3598
+ onDragLeave: () => setDragOver(false),
3599
+ onDrop: handleDrop
3600
+ },
3601
+ /* @__PURE__ */ React10__default.default.createElement(
3602
+ "input",
3603
+ {
3604
+ id: inputId,
3605
+ type: "file",
3606
+ accept: acceptAttr,
3607
+ className: "hidden",
3608
+ onChange: handleFileInput,
3609
+ disabled: disabled || uploading
3610
+ }
3611
+ ),
3612
+ /* @__PURE__ */ React10__default.default.createElement("label", { htmlFor: inputId, className: "flex flex-col items-center gap-2" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Upload, { className: "h-6 w-6 text-gray-500" }), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-sm text-gray-600" }, "Click to select or drag file here"), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs text-gray-400" }, mergedAcceptedTypes.join(", ")))
3613
+ ), uploading && /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center gap-2 text-sm text-blue-600" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }), "Uploading", progress ? ` ${progress.progress}%` : "..."), progress && /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-xs text-gray-500" }, formatMegabytes(progress.uploadedBytes), " / ", formatMegabytes(progress.totalBytes)), error && /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-sm text-red-600" }, error), uploadedFile && /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center justify-between rounded-lg border border-green-200 bg-green-50 px-3 py-2 text-sm text-green-700" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.CheckCircle2, { className: "h-4 w-4" }), /* @__PURE__ */ React10__default.default.createElement("span", { className: "truncate" }, uploadedFile.originalName)), uploadedUrl && /* @__PURE__ */ React10__default.default.createElement(
3614
+ "a",
3615
+ {
3616
+ href: uploadedUrl,
3617
+ target: "_blank",
3618
+ rel: "noreferrer",
3619
+ className: "text-green-700 underline"
3620
+ },
3621
+ "Open"
3622
+ )));
3623
+ };
3441
3624
  function diagnoseMaterialsMMD(scene, renderer) {
3442
3625
  const report = {
3443
3626
  totalMaterials: 0,
@@ -5089,6 +5272,8 @@ var MMDVisualNovel = React10.forwardRef(
5089
5272
  onScriptComplete,
5090
5273
  onError,
5091
5274
  showDebugInfo = false,
5275
+ debug = false,
5276
+ onTransitionStateChange,
5092
5277
  showSkipButton = true,
5093
5278
  showAutoButton = true,
5094
5279
  showHistoryButton = true,
@@ -5128,6 +5313,26 @@ var MMDVisualNovel = React10.forwardRef(
5128
5313
  const cheerParticlesRef = React10.useRef(null);
5129
5314
  const currentNode = nodes[currentNodeIndex];
5130
5315
  const currentDialogue = currentNode?.dialogues[currentDialogueIndex] || null;
5316
+ const log = React10.useCallback((...args) => {
5317
+ if (!debug) return;
5318
+ console.log("[MMDVisualNovel]", ...args);
5319
+ }, [debug]);
5320
+ React10.useEffect(() => {
5321
+ if (!onTransitionStateChange) return;
5322
+ if (!isStarted) {
5323
+ onTransitionStateChange("idle");
5324
+ return;
5325
+ }
5326
+ if (isTransitioning) {
5327
+ onTransitionStateChange("transitioning");
5328
+ return;
5329
+ }
5330
+ if (isLoading || !isAnimationPlaying) {
5331
+ onTransitionStateChange("loading");
5332
+ return;
5333
+ }
5334
+ onTransitionStateChange("ready");
5335
+ }, [isStarted, isTransitioning, isLoading, isAnimationPlaying, onTransitionStateChange]);
5131
5336
  const addToHistory = React10.useCallback((dialogue, nodeIndex, dialogueIndex) => {
5132
5337
  setHistory((prev) => [
5133
5338
  ...prev,
@@ -5159,11 +5364,11 @@ var MMDVisualNovel = React10.forwardRef(
5159
5364
  if (!node) return;
5160
5365
  const currentResources = nodes[currentNodeIndex]?.resources;
5161
5366
  if (!force && currentResources?.motionPath && !isVmdFinishedRef.current) {
5162
- console.log("[MMDVisualNovel] VMD not finished, showing confirmation");
5367
+ log("VMD not finished, showing confirmation");
5163
5368
  setPendingNodeIndex(nodeIndex);
5164
5369
  return;
5165
5370
  }
5166
- console.log("[MMDVisualNovel] Transitioning to node " + nodeIndex);
5371
+ log("Transitioning to node", nodeIndex);
5167
5372
  setIsTransitioning(true);
5168
5373
  setIsLoading(true);
5169
5374
  setIsAnimationPlaying(false);
@@ -5185,7 +5390,7 @@ var MMDVisualNovel = React10.forwardRef(
5185
5390
  }
5186
5391
  setTimeout(() => {
5187
5392
  setIsTransitioning(false);
5188
- console.log("[MMDVisualNovel] Transition to node " + nodeIndex + " completed, waiting for model load");
5393
+ log("Transition to node completed, waiting for model load", nodeIndex);
5189
5394
  }, 100);
5190
5395
  }, 300);
5191
5396
  },
@@ -5199,7 +5404,7 @@ var MMDVisualNovel = React10.forwardRef(
5199
5404
  const val = variables[key];
5200
5405
  if (val !== void 0 && map[val] !== void 0) {
5201
5406
  nextNodeIndex = map[val];
5202
- console.log("[MMDVisualNovel] Branching: " + key + "=" + val + " -> node " + nextNodeIndex);
5407
+ log("Branching", { key, val, nextNodeIndex });
5203
5408
  } else {
5204
5409
  nextNodeIndex = defaultIndex;
5205
5410
  }
@@ -5207,7 +5412,7 @@ var MMDVisualNovel = React10.forwardRef(
5207
5412
  if (nextNodeIndex < nodes.length && nextNodeIndex >= 0) {
5208
5413
  goToNode(nextNodeIndex);
5209
5414
  } else if (loop) {
5210
- console.log("[MMDVisualNovel] \u5230\u8FBE\u6700\u540E\u4E00\u4E2A\u8282\u70B9\uFF0C\u663E\u793A\u5FAA\u73AF\u786E\u8BA4\u5BF9\u8BDD\u6846");
5415
+ log("Reached final node, showing loop confirmation");
5211
5416
  setShowLoopConfirm(true);
5212
5417
  } else {
5213
5418
  onScriptComplete?.();
@@ -5299,7 +5504,7 @@ var MMDVisualNovel = React10.forwardRef(
5299
5504
  if (nextNodeIndex < nodes.length) {
5300
5505
  goToNode(nextNodeIndex);
5301
5506
  } else if (loop) {
5302
- console.log("[MMDVisualNovel] \u5FEB\u8FDB\u5230\u6700\u540E\uFF0C\u663E\u793A\u5FAA\u73AF\u786E\u8BA4\u5BF9\u8BDD\u6846");
5507
+ log("Skip reached final node, showing loop confirmation");
5303
5508
  setShowLoopConfirm(true);
5304
5509
  } else {
5305
5510
  onScriptComplete?.();
@@ -5326,16 +5531,16 @@ var MMDVisualNovel = React10.forwardRef(
5326
5531
  setIsLoading(true);
5327
5532
  setIsAnimationPlaying(false);
5328
5533
  typingCompleteRef.current = false;
5329
- console.log("[MMDVisualNovel] \u56DE\u5230\u5F00\u59CB\u9875\u9762");
5534
+ log("Back to start screen");
5330
5535
  }, [initialNodeIndex, initialDialogueIndex]);
5331
5536
  const handleCheer = React10.useCallback(() => {
5332
- console.log("[MMDVisualNovel] \u89E6\u53D1\u5E94\u63F4\u6548\u679C");
5537
+ log("Trigger cheer effect");
5333
5538
  cheerParticlesRef.current?.trigger();
5334
5539
  }, []);
5335
5540
  const handleRestartLoop = React10.useCallback(() => {
5336
5541
  setShowLoopConfirm(false);
5337
5542
  goToNode(0, true);
5338
- console.log("[MMDVisualNovel] \u91CD\u65B0\u5F00\u59CB\u5FAA\u73AF");
5543
+ log("Restart loop");
5339
5544
  }, [goToNode]);
5340
5545
  React10.useImperativeHandle(
5341
5546
  ref,
@@ -5404,17 +5609,17 @@ var MMDVisualNovel = React10.forwardRef(
5404
5609
  loop: currentNode.loopAnimation === true,
5405
5610
  mobileOptimization,
5406
5611
  onLoad: () => {
5407
- console.log("[MMDVisualNovel] MMDPlayerBase onLoad called");
5612
+ log("MMDPlayerBase onLoad");
5408
5613
  setIsLoading(false);
5409
5614
  if (isStartedRef.current) {
5410
- console.log("[MMDVisualNovel] Game already started, triggering play");
5615
+ log("Game already started, triggering play");
5411
5616
  setTimeout(() => {
5412
5617
  playerRef.current?.play();
5413
5618
  }, 100);
5414
5619
  }
5415
5620
  },
5416
5621
  onPlay: () => {
5417
- console.log("[MMDVisualNovel] MMDPlayerBase onPlay called");
5622
+ log("MMDPlayerBase onPlay");
5418
5623
  setIsAnimationPlaying(true);
5419
5624
  },
5420
5625
  onTimeUpdate: (time) => {
@@ -5423,7 +5628,7 @@ var MMDVisualNovel = React10.forwardRef(
5423
5628
  const isLooped = time < lastAnimationTimeRef.current && lastAnimationTimeRef.current > 0;
5424
5629
  if (isNearEnd || isLooped) {
5425
5630
  if (!isVmdFinishedRef.current) {
5426
- console.log("[MMDVisualNovel] VMD finished/looped, marking as finished");
5631
+ log("VMD finished/looped, marking as finished");
5427
5632
  isVmdFinishedRef.current = true;
5428
5633
  setIsVmdFinished(true);
5429
5634
  }
@@ -5431,7 +5636,7 @@ var MMDVisualNovel = React10.forwardRef(
5431
5636
  lastAnimationTimeRef.current = time;
5432
5637
  },
5433
5638
  onEnded: () => {
5434
- console.log("[MMDVisualNovel] VMD ended, marking as finished");
5639
+ log("VMD ended, marking as finished");
5435
5640
  isVmdFinishedRef.current = true;
5436
5641
  setIsVmdFinished(true);
5437
5642
  },
@@ -5477,17 +5682,7 @@ var MMDVisualNovel = React10.forwardRef(
5477
5682
  /* @__PURE__ */ React10__default.default.createElement(
5478
5683
  LoadingOverlay,
5479
5684
  {
5480
- isLoading: (() => {
5481
- const shouldShowLoading = (isLoading || isTransitioning || !isAnimationPlaying) && isStarted;
5482
- console.log("[MMDVisualNovel] LoadingOverlay conditions:", {
5483
- isLoading,
5484
- isTransitioning,
5485
- isAnimationPlaying,
5486
- isStarted,
5487
- shouldShowLoading
5488
- });
5489
- return shouldShowLoading;
5490
- })(),
5685
+ isLoading: (isLoading || isTransitioning || !isAnimationPlaying) && isStarted,
5491
5686
  showStartScreen: !isStarted,
5492
5687
  scriptName: script.name,
5493
5688
  loadingText: "\u6B63\u5728\u51C6\u5907\u573A\u666F\u4E2D...",
@@ -5499,44 +5694,31 @@ var MMDVisualNovel = React10.forwardRef(
5499
5694
  customAboutContent
5500
5695
  }
5501
5696
  ),
5502
- (() => {
5503
- const shouldShow = isStarted && isAnimationPlaying && currentDialogue && !showHistory && !showChoices && !showLoopConfirm;
5504
- console.log("[MMDVisualNovel] DialogueBox render condition:", {
5505
- isStarted,
5506
- isAnimationPlaying,
5507
- hasDialogue: !!currentDialogue,
5508
- showHistory,
5509
- showChoices,
5510
- showLoopConfirm,
5511
- shouldShow,
5512
- dialogue: currentDialogue
5513
- });
5514
- return shouldShow ? /* @__PURE__ */ React10__default.default.createElement(
5515
- DialogueBox,
5516
- {
5517
- dialogue: currentDialogue,
5518
- theme: dialogueTheme,
5519
- isTyping,
5520
- isAutoMode,
5521
- onClick: handleDialogueClick,
5522
- onSkipTyping: () => {
5523
- typingCompleteRef.current = true;
5524
- },
5525
- onToggleAuto: toggleAutoMode,
5526
- onOpenHistory: () => setShowHistory(true),
5527
- onSkip: handleSkip,
5528
- onResetCamera: () => {
5529
- playerRef.current?.resetCamera();
5530
- setIsCameraManual(false);
5531
- },
5532
- isCameraManual,
5533
- showControls: true,
5534
- showSkipButton,
5535
- showAutoButton,
5536
- showHistoryButton
5537
- }
5538
- ) : null;
5539
- })(),
5697
+ isStarted && isAnimationPlaying && currentDialogue && !showHistory && !showChoices && !showLoopConfirm ? /* @__PURE__ */ React10__default.default.createElement(
5698
+ DialogueBox,
5699
+ {
5700
+ dialogue: currentDialogue,
5701
+ theme: dialogueTheme,
5702
+ isTyping,
5703
+ isAutoMode,
5704
+ onClick: handleDialogueClick,
5705
+ onSkipTyping: () => {
5706
+ typingCompleteRef.current = true;
5707
+ },
5708
+ onToggleAuto: toggleAutoMode,
5709
+ onOpenHistory: () => setShowHistory(true),
5710
+ onSkip: handleSkip,
5711
+ onResetCamera: () => {
5712
+ playerRef.current?.resetCamera();
5713
+ setIsCameraManual(false);
5714
+ },
5715
+ isCameraManual,
5716
+ showControls: true,
5717
+ showSkipButton,
5718
+ showAutoButton,
5719
+ showHistoryButton
5720
+ }
5721
+ ) : null,
5540
5722
  pendingNodeIndex !== null && /* @__PURE__ */ React10__default.default.createElement(
5541
5723
  SkipConfirmDialog,
5542
5724
  {
@@ -5559,7 +5741,7 @@ var MMDVisualNovel = React10.forwardRef(
5559
5741
  if (choice.setVariable) {
5560
5742
  const { key, value } = choice.setVariable;
5561
5743
  setVariables((prev) => ({ ...prev, [key]: value }));
5562
- console.log("[MMDVisualNovel] Variable set: " + key + " = " + value);
5744
+ log("Variable set", { key, value });
5563
5745
  }
5564
5746
  choice.onSelect?.();
5565
5747
  if (choice.effect) {
@@ -5701,6 +5883,7 @@ var MMDVisualNovelWithSelector = React10.forwardRef((props, ref) => {
5701
5883
  script,
5702
5884
  modelSelector,
5703
5885
  onModelSelectionChange,
5886
+ resourceMappingMode = "resource-map",
5704
5887
  ...restProps
5705
5888
  } = props;
5706
5889
  const {
@@ -5727,20 +5910,39 @@ var MMDVisualNovelWithSelector = React10.forwardRef((props, ref) => {
5727
5910
  return model?.path || stageModels[0]?.path || "";
5728
5911
  }, [stageModels, selectedStageId]);
5729
5912
  const modifiedScript = React10.useMemo(() => {
5913
+ if (resourceMappingMode === "full-clone") {
5914
+ return {
5915
+ ...script,
5916
+ nodes: script.nodes.map((node) => ({
5917
+ ...node,
5918
+ resources: {
5919
+ ...node.resources,
5920
+ modelPath: selectedCharacterPath,
5921
+ stageModelPath: selectedStagePath
5922
+ }
5923
+ }))
5924
+ };
5925
+ }
5730
5926
  return {
5731
5927
  ...script,
5732
- nodes: script.nodes.map((node) => ({
5733
- ...node,
5734
- resources: {
5735
- ...node.resources,
5736
- // 覆盖人物模型路径
5737
- modelPath: selectedCharacterPath,
5738
- // 覆盖场景模型路径
5739
- stageModelPath: selectedStagePath
5740
- }
5741
- }))
5928
+ nodes: script.nodes.map((node) => {
5929
+ const nextModelPath = selectedCharacterPath;
5930
+ const nextStagePath = selectedStagePath;
5931
+ const resources = node.resources;
5932
+ if (resources.modelPath === nextModelPath && resources.stageModelPath === nextStagePath) {
5933
+ return node;
5934
+ }
5935
+ return {
5936
+ ...node,
5937
+ resources: {
5938
+ ...resources,
5939
+ modelPath: nextModelPath,
5940
+ stageModelPath: nextStagePath
5941
+ }
5942
+ };
5943
+ })
5742
5944
  };
5743
- }, [script, selectedCharacterPath, selectedStagePath]);
5945
+ }, [script, selectedCharacterPath, selectedStagePath, resourceMappingMode]);
5744
5946
  const handleCharacterChange = React10.useCallback((id) => {
5745
5947
  setSelectedCharacterId(id);
5746
5948
  onModelSelectionChange?.(id, selectedStageId);
@@ -6323,594 +6525,733 @@ var MMDMusicPlayer = React10.forwardRef(
6323
6525
  }
6324
6526
  );
6325
6527
  MMDMusicPlayer.displayName = "MMDMusicPlayer";
6326
- if (typeof window !== "undefined") {
6327
- window.THREE = THREE2__namespace;
6528
+
6529
+ // src/mmd/ar/types.ts
6530
+ var ARMode = /* @__PURE__ */ ((ARMode2) => {
6531
+ ARMode2["Overlay"] = "overlay";
6532
+ ARMode2["WorldFixed"] = "world-fixed";
6533
+ return ARMode2;
6534
+ })(ARMode || {});
6535
+
6536
+ // src/mmd/ar/MMDARApp.tsx
6537
+ var DEFAULT_MODEL_SCALE = 0.1;
6538
+ function disposeMesh(object) {
6539
+ object.traverse((child) => {
6540
+ if (child instanceof THREE2__namespace.Mesh || child instanceof THREE2__namespace.SkinnedMesh) {
6541
+ if (child.geometry) {
6542
+ child.geometry.dispose();
6543
+ }
6544
+ const materials = Array.isArray(child.material) ? child.material : [child.material];
6545
+ materials.forEach((material) => {
6546
+ if (material instanceof THREE2__namespace.Material) {
6547
+ Object.values(material).forEach((value) => {
6548
+ if (value instanceof THREE2__namespace.Texture) {
6549
+ value.dispose();
6550
+ }
6551
+ });
6552
+ material.dispose();
6553
+ }
6554
+ });
6555
+ }
6556
+ });
6328
6557
  }
6329
- var MMDARPlayer = React10.forwardRef(({
6330
- width = 800,
6331
- height = 600,
6332
- onReady,
6333
- onError
6334
- }, ref) => {
6558
+ var MMDARApp = React10.forwardRef((props, ref) => {
6559
+ const {
6560
+ stage,
6561
+ mobileOptimization,
6562
+ cameraConfig,
6563
+ cameraParametersUrl,
6564
+ markerConfig,
6565
+ mirrored = false,
6566
+ showSettings,
6567
+ modelPresets,
6568
+ motionPresets,
6569
+ audioPresets,
6570
+ defaultModelId,
6571
+ defaultMotionId,
6572
+ defaultAudioId,
6573
+ modelScale,
6574
+ modelOffset,
6575
+ initialModelVisible = false,
6576
+ placementText = "Place Model",
6577
+ arMode,
6578
+ defaultARMode,
6579
+ autoPlay = true,
6580
+ loop = true,
6581
+ onCameraReady,
6582
+ onCameraError,
6583
+ onResourcesChange,
6584
+ onModelPlaced,
6585
+ onARModeChange,
6586
+ onLoad,
6587
+ onError,
6588
+ className,
6589
+ style
6590
+ } = props;
6335
6591
  const containerRef = React10.useRef(null);
6592
+ const videoContainerRef = React10.useRef(null);
6336
6593
  const canvasRef = React10.useRef(null);
6337
- const sceneRef = React10.useRef();
6338
- const cameraRef = React10.useRef();
6339
- const rendererRef = React10.useRef();
6340
- const arToolkitSourceRef = React10.useRef();
6341
- const arToolkitContextRef = React10.useRef();
6342
- const markerRootRef = React10.useRef();
6343
- const markerControlsRef = React10.useRef();
6344
- const modelRootRef = React10.useRef();
6345
- const modelRef = React10.useRef();
6346
- const [state, setState] = React10.useState({
6347
- isLoading: true,
6348
- cameraReady: false,
6349
- arReady: false,
6350
- error: null,
6351
- showSettings: false,
6352
- modelPlaced: false,
6353
- markerDetected: false,
6354
- selectedModel: "sphere",
6355
- selectedMotion: "idle",
6356
- selectedAudio: "none",
6357
- cameraFacing: "environment",
6358
- markerType: "barcode",
6359
- showWireframe: false,
6360
- lightingEnabled: true,
6361
- quality: "medium"
6362
- });
6363
- const gyroDataRef = React10.useRef({ alpha: 0, beta: 0, gamma: 0 });
6364
- const initializeThreeJS = React10.useCallback(() => {
6365
- try {
6366
- const scene = new THREE2__namespace.Scene();
6367
- sceneRef.current = scene;
6368
- const camera = new THREE2__namespace.Camera();
6369
- cameraRef.current = camera;
6370
- scene.add(camera);
6371
- const renderer = new THREE2__namespace.WebGLRenderer({
6372
- canvas: canvasRef.current,
6373
- antialias: true,
6374
- alpha: true
6375
- });
6376
- renderer.setSize(width, height);
6377
- renderer.setClearColor(0, 0);
6378
- rendererRef.current = renderer;
6379
- console.log("Three.js initialized successfully");
6380
- return true;
6381
- } catch (error) {
6382
- console.error("Failed to initialize Three.js:", error);
6383
- setState((prev) => ({ ...prev, error: "Three.js \u521D\u59CB\u5316\u5931\u8D25" }));
6384
- return false;
6594
+ const sceneRef = React10.useRef(null);
6595
+ const cameraRef = React10.useRef(null);
6596
+ const rendererRef = React10.useRef(null);
6597
+ const arToolkitSourceRef = React10.useRef(null);
6598
+ const arToolkitContextRef = React10.useRef(null);
6599
+ const markerRootRef = React10.useRef(null);
6600
+ const markerControlsRef = React10.useRef(null);
6601
+ const modelRootRef = React10.useRef(null);
6602
+ const mmdHelperRef = React10.useRef(null);
6603
+ const mmdMeshRef = React10.useRef(null);
6604
+ const animationFrameRef = React10.useRef(null);
6605
+ const markerDetectedRef = React10.useRef(false);
6606
+ const audioRef = React10.useRef(null);
6607
+ const autoPlayRef = React10.useRef(autoPlay);
6608
+ const [isLoading, setIsLoading] = React10.useState(true);
6609
+ const [cameraReady, setCameraReady] = React10.useState(false);
6610
+ const [arReady, setArReady] = React10.useState(false);
6611
+ const [error, setError] = React10.useState(null);
6612
+ const [markerDetected, setMarkerDetected] = React10.useState(false);
6613
+ const [modelPlaced, setModelPlaced] = React10.useState(initialModelVisible);
6614
+ const [settingsVisible, setSettingsVisible] = React10.useState(showSettings ?? false);
6615
+ const [internalARMode, setInternalARMode] = React10.useState(
6616
+ defaultARMode ?? arMode ?? "overlay" /* Overlay */
6617
+ );
6618
+ const [cameraFacing, setCameraFacing] = React10.useState(
6619
+ cameraConfig?.facingMode ?? "environment"
6620
+ );
6621
+ const [selectedModelId, setSelectedModelId] = React10.useState(
6622
+ defaultModelId ?? modelPresets[0]?.id ?? ""
6623
+ );
6624
+ const [selectedMotionId, setSelectedMotionId] = React10.useState(
6625
+ defaultMotionId ?? motionPresets[0]?.id ?? ""
6626
+ );
6627
+ const [selectedAudioId, setSelectedAudioId] = React10.useState(
6628
+ defaultAudioId ?? audioPresets?.[0]?.id ?? ""
6629
+ );
6630
+ const [overrideResources, setOverrideResources] = React10.useState(null);
6631
+ const resolvedARMode = arMode ?? internalARMode;
6632
+ const resolvedMarkerConfig = React10.useMemo(() => {
6633
+ return {
6634
+ type: markerConfig?.type ?? "pattern",
6635
+ patternUrl: markerConfig?.patternUrl ?? chunkFGQGWW73_js.DEFAULT_AR_ASSETS.patternUrl,
6636
+ barcodeValue: markerConfig?.barcodeValue ?? 0,
6637
+ changeMatrixMode: markerConfig?.changeMatrixMode ?? "modelViewMatrix"
6638
+ };
6639
+ }, [markerConfig]);
6640
+ const resolvedResources = React10.useMemo(() => {
6641
+ if (overrideResources) {
6642
+ return overrideResources;
6385
6643
  }
6386
- }, [width, height]);
6387
- const requestCameraPermission = React10.useCallback(async () => {
6388
- try {
6389
- console.log("Checking camera support...");
6390
- if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
6391
- throw new Error("\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u6444\u50CF\u5934\u8BBF\u95EE");
6644
+ const modelPreset = modelPresets.find((preset) => preset.id === selectedModelId);
6645
+ if (!modelPreset) {
6646
+ return null;
6647
+ }
6648
+ const motionPreset = motionPresets.find((preset) => preset.id === selectedMotionId);
6649
+ const audioPreset = audioPresets?.find((preset) => preset.id === selectedAudioId);
6650
+ return {
6651
+ modelPath: modelPreset.modelPath,
6652
+ motionPath: motionPreset?.motionPath,
6653
+ audioPath: audioPreset?.audioPath
6654
+ };
6655
+ }, [
6656
+ overrideResources,
6657
+ modelPresets,
6658
+ motionPresets,
6659
+ audioPresets,
6660
+ selectedModelId,
6661
+ selectedMotionId,
6662
+ selectedAudioId
6663
+ ]);
6664
+ const resolveModelScale = React10.useCallback(() => {
6665
+ if (!modelScale) {
6666
+ return new THREE2__namespace.Vector3(DEFAULT_MODEL_SCALE, DEFAULT_MODEL_SCALE, DEFAULT_MODEL_SCALE);
6667
+ }
6668
+ if (typeof modelScale === "number") {
6669
+ return new THREE2__namespace.Vector3(modelScale, modelScale, modelScale);
6670
+ }
6671
+ return new THREE2__namespace.Vector3(modelScale.x, modelScale.y, modelScale.z);
6672
+ }, [modelScale]);
6673
+ const applyModelTransform = React10.useCallback(
6674
+ (mesh) => {
6675
+ const scale = resolveModelScale();
6676
+ mesh.scale.copy(scale);
6677
+ if (modelOffset) {
6678
+ mesh.position.set(modelOffset.x, modelOffset.y, modelOffset.z);
6679
+ return;
6392
6680
  }
6393
- console.log("Camera API supported, checking permissions...");
6394
- if (navigator.permissions) {
6395
- try {
6396
- console.log("Querying camera permission status...");
6397
- const permissionPromise = navigator.permissions.query({ name: "camera" });
6398
- const timeoutPromise2 = new Promise((_, reject) => {
6399
- setTimeout(() => reject(new Error("Permission query timeout")), 5e3);
6400
- });
6401
- const permissionStatus = await Promise.race([permissionPromise, timeoutPromise2]);
6402
- console.log("Permission status:", permissionStatus.state);
6403
- if (permissionStatus.state === "denied") {
6404
- throw new Error("\u6444\u50CF\u5934\u6743\u9650\u5DF2\u88AB\u62D2\u7EDD\uFF0C\u8BF7\u5728\u6D4F\u89C8\u5668\u8BBE\u7F6E\u4E2D\u5141\u8BB8\u8BBF\u95EE\u6444\u50CF\u5934");
6405
- }
6406
- } catch (permissionError) {
6407
- console.warn("Permission query failed or timed out, proceeding with getUserMedia:", permissionError);
6408
- }
6681
+ const box = new THREE2__namespace.Box3().setFromObject(mesh);
6682
+ if (Number.isFinite(box.min.y)) {
6683
+ mesh.position.y += -box.min.y;
6409
6684
  }
6410
- console.log("Requesting camera access...");
6411
- const cameraPromise = navigator.mediaDevices.getUserMedia({
6412
- video: {
6413
- width: { ideal: width },
6414
- height: { ideal: height },
6415
- facingMode: "environment"
6416
- // 优先使用后置摄像头
6685
+ },
6686
+ [modelOffset, resolveModelScale]
6687
+ );
6688
+ const updateModelPlacement = React10.useCallback(
6689
+ (visible) => {
6690
+ if (!modelRootRef.current) return;
6691
+ modelRootRef.current.visible = visible;
6692
+ setModelPlaced(visible);
6693
+ },
6694
+ []
6695
+ );
6696
+ const attachModelRoot = React10.useCallback(
6697
+ (mode) => {
6698
+ if (!modelRootRef.current || !sceneRef.current || !cameraRef.current) return;
6699
+ if (mode === "overlay" /* Overlay */) {
6700
+ if (modelRootRef.current.parent !== cameraRef.current) {
6701
+ modelRootRef.current.parent?.remove(modelRootRef.current);
6702
+ cameraRef.current.add(modelRootRef.current);
6703
+ }
6704
+ modelRootRef.current.position.set(0, -1, -3);
6705
+ modelRootRef.current.quaternion.identity();
6706
+ updateModelPlacement(true);
6707
+ } else {
6708
+ if (modelRootRef.current.parent !== sceneRef.current) {
6709
+ modelRootRef.current.parent?.remove(modelRootRef.current);
6710
+ sceneRef.current.add(modelRootRef.current);
6417
6711
  }
6418
- });
6419
- const timeoutPromise = new Promise((_, reject) => {
6420
- setTimeout(() => reject(new Error("Camera access timeout - \u8BF7\u68C0\u67E5\u6444\u50CF\u5934\u6743\u9650")), 1e4);
6421
- });
6422
- const testStream = await Promise.race([cameraPromise, timeoutPromise]);
6423
- console.log("Camera access granted, stopping test stream...");
6424
- testStream.getTracks().forEach((track) => track.stop());
6425
- console.log("Camera permission granted successfully");
6426
- return true;
6427
- } catch (error) {
6428
- console.error("Camera permission denied:", error);
6429
- const errorMessage = error instanceof Error ? error.message : "\u65E0\u6CD5\u8BBF\u95EE\u6444\u50CF\u5934";
6430
- setState((prev) => ({ ...prev, error: errorMessage, isLoading: false }));
6431
- onError?.(errorMessage);
6432
- return false;
6433
- }
6434
- }, [width, height, onError]);
6435
- const createModel = React10.useCallback((modelType) => {
6436
- let geometry;
6437
- let material;
6438
- let mesh;
6439
- switch (modelType) {
6440
- case "sphere":
6441
- geometry = new THREE2__namespace.SphereGeometry(0.5, 32, 32);
6442
- material = new THREE2__namespace.MeshPhongMaterial({
6443
- color: 16738740,
6444
- shininess: 100,
6445
- specular: 1118481
6446
- });
6447
- mesh = new THREE2__namespace.Mesh(geometry, material);
6448
- break;
6449
- case "cube":
6450
- geometry = new THREE2__namespace.BoxGeometry(0.8, 0.8, 0.8);
6451
- material = new THREE2__namespace.MeshPhongMaterial({
6452
- color: 65407,
6453
- shininess: 100,
6454
- specular: 1118481
6455
- });
6456
- mesh = new THREE2__namespace.Mesh(geometry, material);
6457
- break;
6458
- case "torus":
6459
- geometry = new THREE2__namespace.TorusGeometry(0.4, 0.2, 16, 100);
6460
- material = new THREE2__namespace.MeshPhongMaterial({
6461
- color: 16753920,
6462
- shininess: 100,
6463
- specular: 1118481
6464
- });
6465
- mesh = new THREE2__namespace.Mesh(geometry, material);
6466
- break;
6467
- default:
6468
- geometry = new THREE2__namespace.SphereGeometry(0.5, 32, 32);
6469
- material = new THREE2__namespace.MeshPhongMaterial({
6470
- color: 16738740,
6471
- shininess: 100,
6472
- specular: 1118481
6473
- });
6474
- mesh = new THREE2__namespace.Mesh(geometry, material);
6712
+ updateModelPlacement(initialModelVisible);
6713
+ }
6714
+ },
6715
+ [initialModelVisible, updateModelPlacement]
6716
+ );
6717
+ const stopCameraStream = React10.useCallback(() => {
6718
+ const source = arToolkitSourceRef.current;
6719
+ if (!source?.domElement) return;
6720
+ const stream = source.domElement.srcObject;
6721
+ if (stream) {
6722
+ stream.getTracks().forEach((track) => track.stop());
6475
6723
  }
6476
- mesh.rotation.x = Math.PI / 4;
6477
- mesh.rotation.y = Math.PI / 4;
6478
- return mesh;
6479
6724
  }, []);
6480
- const placeModel = React10.useCallback(() => {
6481
- if (!markerRootRef.current || !modelRootRef.current || !sceneRef.current) {
6482
- console.error("Cannot place model: missing required references");
6725
+ const cleanupAR = React10.useCallback(() => {
6726
+ stopCameraStream();
6727
+ if (markerRootRef.current && sceneRef.current) {
6728
+ sceneRef.current.remove(markerRootRef.current);
6729
+ markerRootRef.current.clear();
6730
+ }
6731
+ markerRootRef.current = null;
6732
+ markerControlsRef.current = null;
6733
+ const videoContainer = videoContainerRef.current;
6734
+ const videoElement = arToolkitSourceRef.current?.domElement;
6735
+ if (videoContainer && videoElement && videoElement.parentElement === videoContainer) {
6736
+ videoContainer.removeChild(videoElement);
6737
+ }
6738
+ arToolkitSourceRef.current?.dispose?.();
6739
+ arToolkitSourceRef.current = null;
6740
+ arToolkitContextRef.current = null;
6741
+ markerDetectedRef.current = false;
6742
+ setMarkerDetected(false);
6743
+ setCameraReady(false);
6744
+ setArReady(false);
6745
+ }, [stopCameraStream]);
6746
+ const setupRenderer = React10.useCallback(() => {
6747
+ if (rendererRef.current) return;
6748
+ if (!canvasRef.current) return;
6749
+ const renderer = new THREE2__namespace.WebGLRenderer({
6750
+ canvas: canvasRef.current,
6751
+ antialias: true,
6752
+ alpha: true
6753
+ });
6754
+ renderer.setClearColor(0, 0);
6755
+ renderer.setPixelRatio(mobileOptimization?.pixelRatio ?? window.devicePixelRatio ?? 1);
6756
+ rendererRef.current = renderer;
6757
+ const scene = new THREE2__namespace.Scene();
6758
+ sceneRef.current = scene;
6759
+ const camera = new THREE2__namespace.Camera();
6760
+ cameraRef.current = camera;
6761
+ scene.add(camera);
6762
+ const modelRoot = new THREE2__namespace.Group();
6763
+ modelRoot.visible = initialModelVisible;
6764
+ modelRootRef.current = modelRoot;
6765
+ scene.add(modelRoot);
6766
+ const ambientLight = new THREE2__namespace.AmbientLight(
6767
+ 16777215,
6768
+ stage?.ambientLightIntensity ?? 0.8
6769
+ );
6770
+ scene.add(ambientLight);
6771
+ const directionalLight = new THREE2__namespace.DirectionalLight(
6772
+ 16777215,
6773
+ stage?.directionalLightIntensity ?? 0.6
6774
+ );
6775
+ directionalLight.position.set(1, 1, 1);
6776
+ scene.add(directionalLight);
6777
+ attachModelRoot(resolvedARMode);
6778
+ }, [
6779
+ attachModelRoot,
6780
+ initialModelVisible,
6781
+ mobileOptimization?.pixelRatio,
6782
+ resolvedARMode,
6783
+ stage?.ambientLightIntensity,
6784
+ stage?.directionalLightIntensity
6785
+ ]);
6786
+ const resize = React10.useCallback(() => {
6787
+ if (!containerRef.current || !rendererRef.current) return;
6788
+ const width = containerRef.current.clientWidth;
6789
+ const height = containerRef.current.clientHeight;
6790
+ if (width === 0 || height === 0) return;
6791
+ rendererRef.current.setSize(width, height);
6792
+ const source = arToolkitSourceRef.current;
6793
+ if (source?.onResizeElement && source?.copyElementSizeTo) {
6794
+ source.onResizeElement();
6795
+ source.copyElementSizeTo(rendererRef.current.domElement);
6796
+ if (arToolkitContextRef.current?.arController?.canvas) {
6797
+ source.copyElementSizeTo(arToolkitContextRef.current.arController.canvas);
6798
+ }
6799
+ }
6800
+ }, []);
6801
+ const startRenderLoop = React10.useCallback(() => {
6802
+ if (animationFrameRef.current) return;
6803
+ if (!rendererRef.current || !sceneRef.current || !cameraRef.current) return;
6804
+ const renderer = rendererRef.current;
6805
+ const scene = sceneRef.current;
6806
+ const camera = cameraRef.current;
6807
+ const clock = new THREE2__namespace.Clock();
6808
+ const render = () => {
6809
+ animationFrameRef.current = requestAnimationFrame(render);
6810
+ if (arToolkitSourceRef.current?.ready) {
6811
+ arToolkitContextRef.current?.update(arToolkitSourceRef.current.domElement);
6812
+ if (markerRootRef.current) {
6813
+ const isVisible = markerRootRef.current.visible;
6814
+ if (isVisible !== markerDetectedRef.current) {
6815
+ markerDetectedRef.current = isVisible;
6816
+ setMarkerDetected(isVisible);
6817
+ }
6818
+ }
6819
+ }
6820
+ if (mmdHelperRef.current && autoPlayRef.current) {
6821
+ const delta = clock.getDelta();
6822
+ mmdHelperRef.current.update(delta);
6823
+ }
6824
+ renderer.render(scene, camera);
6825
+ };
6826
+ render();
6827
+ }, []);
6828
+ const setupAR = React10.useCallback(async (facingOverride) => {
6829
+ if (!sceneRef.current || !cameraRef.current) return;
6830
+ const THREEx = await chunkFGQGWW73_js.loadARJS({ three: THREE2__namespace });
6831
+ const facingMode = facingOverride ?? cameraFacing;
6832
+ const sourceWidth = typeof cameraConfig?.width === "number" ? cameraConfig.width : cameraConfig?.width?.ideal;
6833
+ const sourceHeight = typeof cameraConfig?.height === "number" ? cameraConfig.height : cameraConfig?.height?.ideal;
6834
+ const arToolkitSource = new THREEx.ArToolkitSource({
6835
+ sourceType: "webcam",
6836
+ sourceWidth: sourceWidth ?? 1280,
6837
+ sourceHeight: sourceHeight ?? 720,
6838
+ facingMode
6839
+ });
6840
+ arToolkitSourceRef.current = arToolkitSource;
6841
+ const arToolkitContext = new THREEx.ArToolkitContext({
6842
+ cameraParametersUrl: cameraParametersUrl ?? chunkFGQGWW73_js.DEFAULT_AR_ASSETS.cameraParametersUrl,
6843
+ detectionMode: "mono",
6844
+ maxDetectionRate: 30
6845
+ });
6846
+ arToolkitContextRef.current = arToolkitContext;
6847
+ const markerRoot = new THREE2__namespace.Group();
6848
+ markerRootRef.current = markerRoot;
6849
+ sceneRef.current.add(markerRoot);
6850
+ markerControlsRef.current = new THREEx.ArMarkerControls(
6851
+ arToolkitContext,
6852
+ markerRoot,
6853
+ resolvedMarkerConfig
6854
+ );
6855
+ arToolkitContext.init(() => {
6856
+ if (!cameraRef.current) return;
6857
+ cameraRef.current.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
6858
+ setArReady(true);
6859
+ });
6860
+ arToolkitSource.init(() => {
6861
+ const videoElement = arToolkitSource.domElement;
6862
+ if (videoContainerRef.current && videoElement.parentElement !== videoContainerRef.current) {
6863
+ videoContainerRef.current.appendChild(videoElement);
6864
+ }
6865
+ videoElement.setAttribute("playsinline", "true");
6866
+ videoElement.style.position = "absolute";
6867
+ videoElement.style.inset = "0";
6868
+ videoElement.style.width = "100%";
6869
+ videoElement.style.height = "100%";
6870
+ videoElement.style.objectFit = "cover";
6871
+ videoElement.style.zIndex = "0";
6872
+ if (mirrored) {
6873
+ videoElement.style.transform = "scaleX(-1)";
6874
+ }
6875
+ setCameraReady(true);
6876
+ const stream = videoElement.srcObject;
6877
+ if (stream) {
6878
+ onCameraReady?.(stream);
6879
+ }
6880
+ resize();
6881
+ });
6882
+ }, [
6883
+ cameraConfig?.height,
6884
+ cameraConfig?.width,
6885
+ cameraFacing,
6886
+ cameraParametersUrl,
6887
+ mirrored,
6888
+ onCameraReady,
6889
+ resize,
6890
+ resolvedMarkerConfig
6891
+ ]);
6892
+ const loadMMDResources = React10.useCallback(async () => {
6893
+ if (!resolvedResources || !sceneRef.current || !modelRootRef.current) {
6483
6894
  return;
6484
6895
  }
6896
+ setIsLoading(true);
6897
+ setError(null);
6898
+ if (mmdMeshRef.current) {
6899
+ if (mmdHelperRef.current) {
6900
+ mmdHelperRef.current.remove(mmdMeshRef.current);
6901
+ }
6902
+ modelRootRef.current.remove(mmdMeshRef.current);
6903
+ disposeMesh(mmdMeshRef.current);
6904
+ mmdMeshRef.current = null;
6905
+ }
6906
+ if (!mmdHelperRef.current) {
6907
+ mmdHelperRef.current = new threeStdlib.MMDAnimationHelper({ afterglow: 2 });
6908
+ }
6909
+ const loader = new threeStdlib.MMDLoader();
6910
+ const loadModel = () => new Promise((resolve, reject) => {
6911
+ if (resolvedResources.motionPath) {
6912
+ loader.loadWithAnimation(
6913
+ resolvedResources.modelPath,
6914
+ resolvedResources.motionPath,
6915
+ (mmd) => resolve({ mesh: mmd.mesh, animation: mmd.animation }),
6916
+ void 0,
6917
+ (err) => reject(err)
6918
+ );
6919
+ } else {
6920
+ loader.load(
6921
+ resolvedResources.modelPath,
6922
+ (mesh) => resolve({ mesh }),
6923
+ void 0,
6924
+ (err) => reject(err)
6925
+ );
6926
+ }
6927
+ });
6485
6928
  try {
6486
- if (modelRef.current) {
6487
- modelRootRef.current.remove(modelRef.current);
6488
- }
6489
- const model = createModel(state.selectedModel);
6490
- modelRef.current = model;
6491
- modelRootRef.current.position.copy(markerRootRef.current.position);
6492
- modelRootRef.current.quaternion.copy(markerRootRef.current.quaternion);
6493
- modelRootRef.current.add(model);
6494
- modelRootRef.current.visible = true;
6495
- setState((prev) => ({ ...prev, modelPlaced: true }));
6496
- console.log("Model placed successfully at marker position");
6497
- } catch (error) {
6498
- console.error("Failed to place model:", error);
6499
- setState((prev) => ({ ...prev, error: "\u653E\u7F6E\u6A21\u578B\u5931\u8D25" }));
6929
+ const { mesh, animation } = await loadModel();
6930
+ configureMaterialsForMMD(mesh, {
6931
+ enableGradientMap: true,
6932
+ shininess: 30,
6933
+ specularColor: 8947848
6934
+ });
6935
+ applyModelTransform(mesh);
6936
+ mesh.castShadow = true;
6937
+ mesh.receiveShadow = stage?.modelReceiveShadow ?? true;
6938
+ mmdMeshRef.current = mesh;
6939
+ modelRootRef.current.add(mesh);
6940
+ if (animation) {
6941
+ mmdHelperRef.current.add(mesh, {
6942
+ animation,
6943
+ physics: false
6944
+ });
6945
+ }
6946
+ setIsLoading(false);
6947
+ onResourcesChange?.(resolvedResources);
6948
+ onLoad?.();
6949
+ } catch (err) {
6950
+ const message = err instanceof Error ? err.message : "Failed to load MMD resources";
6951
+ setError(message);
6952
+ setIsLoading(false);
6953
+ onError?.(err instanceof Error ? err : new Error(message));
6954
+ }
6955
+ }, [applyModelTransform, onError, onLoad, onResourcesChange, resolvedResources, stage?.modelReceiveShadow]);
6956
+ const updateAudio = React10.useCallback(() => {
6957
+ if (!resolvedResources?.audioPath) {
6958
+ if (audioRef.current) {
6959
+ audioRef.current.pause();
6960
+ audioRef.current.src = "";
6961
+ audioRef.current = null;
6962
+ }
6963
+ return;
6500
6964
  }
6501
- }, [state.selectedModel, createModel]);
6502
- const handleARSettingChange = React10.useCallback((setting, value) => {
6503
- setState((prev) => ({ ...prev, [setting]: value }));
6504
- if (setting === "cameraFacing" || setting === "markerType" || setting === "quality") {
6505
- setTimeout(() => {
6506
- alert("\u6B64\u8BBE\u7F6E\u53D8\u66F4\u9700\u8981\u91CD\u65B0\u542F\u52A8 AR \u7CFB\u7EDF\u3002\u8BF7\u5237\u65B0\u9875\u9762\u4EE5\u5E94\u7528\u65B0\u8BBE\u7F6E\u3002");
6507
- }, 100);
6965
+ if (audioRef.current) {
6966
+ audioRef.current.pause();
6967
+ audioRef.current.src = "";
6508
6968
  }
6509
- }, []);
6510
- const takePhoto = React10.useCallback(() => {
6511
- if (!rendererRef.current || !sceneRef.current || !cameraRef.current) {
6512
- console.error("Cannot take photo: missing required references");
6969
+ const audio = new Audio(resolvedResources.audioPath);
6970
+ audio.loop = loop;
6971
+ audioRef.current = audio;
6972
+ if (autoPlay || modelPlaced) {
6973
+ audio.play().catch(() => void 0);
6974
+ }
6975
+ }, [autoPlay, loop, modelPlaced, resolvedResources?.audioPath]);
6976
+ const placeModel = React10.useCallback(() => {
6977
+ if (!modelRootRef.current) return;
6978
+ if (resolvedARMode === "overlay" /* Overlay */) {
6979
+ updateModelPlacement(true);
6980
+ onModelPlaced?.();
6513
6981
  return;
6514
6982
  }
6515
- try {
6983
+ if (!markerRootRef.current) return;
6984
+ modelRootRef.current.position.copy(markerRootRef.current.position);
6985
+ modelRootRef.current.quaternion.copy(markerRootRef.current.quaternion);
6986
+ updateModelPlacement(true);
6987
+ onModelPlaced?.();
6988
+ }, [onModelPlaced, resolvedARMode, updateModelPlacement]);
6989
+ const removeModel = React10.useCallback(() => {
6990
+ updateModelPlacement(false);
6991
+ }, [updateModelPlacement]);
6992
+ React10.useImperativeHandle(ref, () => ({
6993
+ startCamera: async () => {
6994
+ cleanupAR();
6995
+ await setupAR();
6996
+ },
6997
+ stopCamera: () => {
6998
+ cleanupAR();
6999
+ },
7000
+ switchCamera: async () => {
7001
+ const next = cameraFacing === "environment" ? "user" : "environment";
7002
+ setCameraFacing(next);
7003
+ cleanupAR();
7004
+ await setupAR(next);
7005
+ },
7006
+ snapshot: async () => {
7007
+ if (!rendererRef.current) return "";
6516
7008
  const canvas = document.createElement("canvas");
6517
7009
  const context = canvas.getContext("2d");
6518
- if (!context) {
6519
- throw new Error("Cannot create canvas context");
6520
- }
7010
+ if (!context) return "";
7011
+ const width = rendererRef.current.domElement.width;
7012
+ const height = rendererRef.current.domElement.height;
6521
7013
  canvas.width = width;
6522
7014
  canvas.height = height;
6523
- rendererRef.current.render(sceneRef.current, cameraRef.current);
6524
- const rendererCanvas = rendererRef.current.domElement;
6525
- context.drawImage(rendererCanvas, 0, 0, width, height);
6526
- if (arToolkitSourceRef.current && arToolkitSourceRef.current.domElement) {
6527
- const videoElement = arToolkitSourceRef.current.domElement;
6528
- context.globalCompositeOperation = "source-over";
7015
+ const videoElement = arToolkitSourceRef.current?.domElement;
7016
+ if (videoElement) {
6529
7017
  context.drawImage(videoElement, 0, 0, width, height);
6530
7018
  }
6531
- canvas.toBlob((blob) => {
6532
- if (blob) {
6533
- const url = URL.createObjectURL(blob);
6534
- const a = document.createElement("a");
6535
- a.href = url;
6536
- a.download = "ar-photo-" + Date.now() + ".png";
6537
- document.body.appendChild(a);
6538
- a.click();
6539
- document.body.removeChild(a);
6540
- URL.revokeObjectURL(url);
6541
- console.log("Photo saved successfully");
6542
- }
6543
- }, "image/png");
6544
- } catch (error) {
6545
- console.error("Failed to take photo:", error);
6546
- setState((prev) => ({ ...prev, error: "\u62CD\u7167\u5931\u8D25" }));
6547
- }
6548
- }, [width, height]);
6549
- const initializeAR = React10.useCallback(async () => {
6550
- try {
6551
- console.log("Starting AR initialization...");
6552
- if (!window.__arjs_ready) {
6553
- console.log("Waiting for AR.js initialization...");
6554
- await new Promise((resolve, reject) => {
6555
- const check = setInterval(() => {
6556
- if (window.__arjs_ready) {
6557
- clearInterval(check);
6558
- console.log("AR.js initialization complete!");
6559
- resolve();
6560
- }
6561
- }, 50);
6562
- setTimeout(() => {
6563
- clearInterval(check);
6564
- reject(new Error("AR.js initialization timeout"));
6565
- }, 15e3);
6566
- });
7019
+ context.drawImage(rendererRef.current.domElement, 0, 0, width, height);
7020
+ return canvas.toDataURL("image/png");
7021
+ },
7022
+ placeModel,
7023
+ removeModel,
7024
+ switchModel: (resources) => {
7025
+ setOverrideResources(resources);
7026
+ },
7027
+ setARMode: (mode) => {
7028
+ if (!arMode) {
7029
+ setInternalARMode(mode);
6567
7030
  }
6568
- console.log("Getting THREEx...");
6569
- const THREEx = window.THREEx;
6570
- if (!THREEx) {
6571
- console.error("THREEx not found, available window properties:", Object.keys(window).filter((key) => key.toLowerCase().includes("ar") || key.toLowerCase().includes("three")));
6572
- throw new Error("THREEx not found after AR.js loaded");
6573
- }
6574
- console.log("THREEx loaded successfully:", Object.keys(THREEx));
6575
- console.log("THREEx loaded, requesting camera permission...");
6576
- const hasPermission = await requestCameraPermission();
6577
- if (!hasPermission) {
6578
- console.log("Camera permission denied");
6579
- return false;
6580
- }
6581
- console.log("Camera permission granted, initializing AR Toolkit Source...");
6582
- const arToolkitSource = new THREEx.ArToolkitSource({
6583
- sourceType: "webcam",
6584
- sourceWidth: width,
6585
- sourceHeight: height,
6586
- // 使用用户选择的摄像头朝向
6587
- ...state.cameraFacing && { facingMode: state.cameraFacing }
6588
- });
6589
- arToolkitSourceRef.current = arToolkitSource;
6590
- const arToolkitContext = new THREEx.ArToolkitContext({
6591
- cameraParametersUrl: "data/camera_para.dat",
6592
- // 使用内建相机参数
6593
- detectionMode: "mono",
6594
- // 根据质量设置调整检测参数
6595
- ...state.quality && {
6596
- maxDetectionRate: state.quality === "high" ? 60 : state.quality === "medium" ? 30 : 15
6597
- }
6598
- });
6599
- arToolkitContextRef.current = arToolkitContext;
6600
- arToolkitContext.init(() => {
6601
- cameraRef.current.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
6602
- const markerRoot = new THREE2__namespace.Group();
6603
- sceneRef.current.add(markerRoot);
6604
- markerRootRef.current = markerRoot;
6605
- const markerGeometry = new THREE2__namespace.BoxGeometry(1, 1, 0.1);
6606
- const markerMaterial = new THREE2__namespace.MeshBasicMaterial({
6607
- color: 65280,
6608
- transparent: true,
6609
- opacity: 0.7,
6610
- wireframe: state.showWireframe
6611
- // 根据设置显示线框
6612
- });
6613
- const markerMesh = new THREE2__namespace.Mesh(markerGeometry, markerMaterial);
6614
- markerMesh.position.set(0, 0, 0);
6615
- markerRoot.add(markerMesh);
6616
- if (!state.showWireframe) {
6617
- const edges = new THREE2__namespace.EdgesGeometry(markerGeometry);
6618
- const lineMaterial = new THREE2__namespace.LineBasicMaterial({ color: 16777215 });
6619
- const wireframe = new THREE2__namespace.LineSegments(edges, lineMaterial);
6620
- markerRoot.add(wireframe);
6621
- }
6622
- const markerControls = new THREEx.ArMarkerControls(arToolkitContext, markerRoot, {
6623
- type: state.markerType,
6624
- ...state.markerType === "barcode" ? { barcodeValue: 0 } : { patternUrl: "data/patt.hiro" }
6625
- });
6626
- markerControlsRef.current = markerControls;
6627
- if (state.lightingEnabled) {
6628
- const ambientLight = new THREE2__namespace.AmbientLight(4210752, 0.6);
6629
- sceneRef.current.add(ambientLight);
6630
- const directionalLight = new THREE2__namespace.DirectionalLight(16777215, 0.8);
6631
- directionalLight.position.set(1, 1, 1);
6632
- sceneRef.current.add(directionalLight);
6633
- }
6634
- const modelRoot = new THREE2__namespace.Group();
6635
- modelRoot.visible = false;
6636
- sceneRef.current.add(modelRoot);
6637
- modelRootRef.current = modelRoot;
6638
- setState((prev) => ({
6639
- ...prev,
6640
- arReady: true,
6641
- isLoading: false
6642
- }));
6643
- onReady?.();
6644
- console.log("AR.js and marker system initialized successfully");
6645
- });
6646
- arToolkitSource.init(() => {
6647
- arToolkitSource.domElement.style.display = "none";
6648
- setState((prev) => ({ ...prev, cameraReady: true }));
6649
- console.log("Camera initialized successfully");
6650
- });
6651
- return true;
6652
- } catch (error) {
6653
- console.error("Failed to initialize AR.js:", error);
6654
- const errorMessage = error instanceof Error ? error.message : "AR.js \u521D\u59CB\u5316\u5931\u8D25";
6655
- setState((prev) => ({
6656
- ...prev,
6657
- error: errorMessage,
6658
- isLoading: false
6659
- }));
6660
- onError?.(errorMessage);
6661
- return false;
6662
- }
6663
- }, [width, height, requestCameraPermission, onReady, onError]);
6664
- const render = React10.useCallback(() => {
6665
- if (!rendererRef.current || !sceneRef.current || !cameraRef.current) return;
6666
- requestAnimationFrame(render);
6667
- if (arToolkitSourceRef.current && arToolkitSourceRef.current.ready) {
6668
- arToolkitContextRef.current.update(arToolkitSourceRef.current.domElement);
6669
- if (markerRootRef.current && markerRootRef.current.visible !== state.markerDetected) {
6670
- setState((prev) => ({ ...prev, markerDetected: markerRootRef.current.visible }));
7031
+ attachModelRoot(mode);
7032
+ onARModeChange?.(mode);
7033
+ },
7034
+ getARMode: () => resolvedARMode
7035
+ }));
7036
+ React10.useEffect(() => {
7037
+ autoPlayRef.current = autoPlay || modelPlaced;
7038
+ }, [autoPlay, modelPlaced]);
7039
+ React10.useEffect(() => {
7040
+ if (showSettings !== void 0) {
7041
+ setSettingsVisible(showSettings);
7042
+ }
7043
+ }, [showSettings]);
7044
+ React10.useEffect(() => {
7045
+ if (cameraConfig?.facingMode) {
7046
+ if (cameraConfig.facingMode !== cameraFacing) {
7047
+ setCameraFacing(cameraConfig.facingMode);
7048
+ cleanupAR();
7049
+ setupAR(cameraConfig.facingMode).catch(() => void 0);
6671
7050
  }
6672
7051
  }
6673
- if (modelRef.current && state.modelPlaced) {
6674
- modelRef.current.rotation.y += 0.01;
7052
+ }, [cameraConfig?.facingMode, cameraFacing, cleanupAR, setupAR]);
7053
+ React10.useEffect(() => {
7054
+ if (!modelPresets.find((preset) => preset.id === selectedModelId)) {
7055
+ setSelectedModelId(modelPresets[0]?.id ?? "");
6675
7056
  }
6676
- rendererRef.current.render(sceneRef.current, cameraRef.current);
6677
- }, [state.markerDetected]);
7057
+ }, [modelPresets, selectedModelId]);
6678
7058
  React10.useEffect(() => {
6679
- const initialize = async () => {
6680
- try {
6681
- setState((prev) => ({ ...prev, isLoading: true, error: null }));
6682
- if (!initializeThreeJS()) return;
6683
- await initializeAR();
6684
- if (window.DeviceOrientationEvent) {
6685
- const handleOrientation = (event) => {
6686
- gyroDataRef.current = {
6687
- alpha: event.alpha || 0,
6688
- beta: event.beta || 0,
6689
- gamma: event.gamma || 0
6690
- };
6691
- if (state.modelPlaced && modelRef.current) {
6692
- }
6693
- };
6694
- window.addEventListener("deviceorientation", handleOrientation);
6695
- const cleanupGyro = () => {
6696
- window.removeEventListener("deviceorientation", handleOrientation);
6697
- };
6698
- window.__gyroCleanup = cleanupGyro;
6699
- }
6700
- render();
6701
- } catch (error) {
6702
- console.error("Initialization failed:", error);
6703
- setState((prev) => ({
6704
- ...prev,
6705
- error: "\u7EC4\u4EF6\u521D\u59CB\u5316\u5931\u8D25",
6706
- isLoading: false
6707
- }));
6708
- onError?.("\u7EC4\u4EF6\u521D\u59CB\u5316\u5931\u8D25");
6709
- }
6710
- };
6711
- initialize();
7059
+ if (!motionPresets.find((preset) => preset.id === selectedMotionId)) {
7060
+ setSelectedMotionId(motionPresets[0]?.id ?? "");
7061
+ }
7062
+ }, [motionPresets, selectedMotionId]);
7063
+ React10.useEffect(() => {
7064
+ if (audioPresets && !audioPresets.find((preset) => preset.id === selectedAudioId)) {
7065
+ setSelectedAudioId(audioPresets[0]?.id ?? "");
7066
+ }
7067
+ }, [audioPresets, selectedAudioId]);
7068
+ React10.useEffect(() => {
7069
+ if (typeof window === "undefined") return;
7070
+ if (!rendererRef.current) {
7071
+ setupRenderer();
7072
+ }
7073
+ if (!arToolkitSourceRef.current) {
7074
+ setupAR().then(() => {
7075
+ startRenderLoop();
7076
+ }).catch((err) => {
7077
+ const message = err instanceof Error ? err.message : "Failed to initialize AR";
7078
+ setError(message);
7079
+ setIsLoading(false);
7080
+ onCameraError?.(err instanceof Error ? err : new Error(message));
7081
+ });
7082
+ } else {
7083
+ startRenderLoop();
7084
+ }
7085
+ const resizeObserver = new ResizeObserver(resize);
7086
+ if (containerRef.current) {
7087
+ resizeObserver.observe(containerRef.current);
7088
+ }
6712
7089
  return () => {
7090
+ resizeObserver.disconnect();
7091
+ cleanupAR();
7092
+ if (animationFrameRef.current) {
7093
+ cancelAnimationFrame(animationFrameRef.current);
7094
+ animationFrameRef.current = null;
7095
+ }
6713
7096
  if (rendererRef.current) {
6714
7097
  rendererRef.current.dispose();
7098
+ rendererRef.current = null;
6715
7099
  }
6716
- if (arToolkitSourceRef.current) {
6717
- if (arToolkitSourceRef.current.domElement?.srcObject) {
6718
- const stream = arToolkitSourceRef.current.domElement.srcObject;
6719
- stream.getTracks().forEach((track) => track.stop());
6720
- }
6721
- arToolkitSourceRef.current.domElement?.remove();
7100
+ if (sceneRef.current && modelRootRef.current) {
7101
+ sceneRef.current.remove(modelRootRef.current);
6722
7102
  }
6723
- if (window.__gyroCleanup) {
6724
- window.__gyroCleanup();
7103
+ if (mmdMeshRef.current) {
7104
+ if (mmdHelperRef.current) {
7105
+ mmdHelperRef.current.remove(mmdMeshRef.current);
7106
+ }
7107
+ disposeMesh(mmdMeshRef.current);
7108
+ mmdMeshRef.current = null;
6725
7109
  }
7110
+ mmdHelperRef.current = null;
7111
+ audioRef.current?.pause();
7112
+ audioRef.current = null;
6726
7113
  };
6727
- }, [initializeThreeJS, initializeAR, render, onError]);
6728
- return /* @__PURE__ */ React10__default.default.createElement("div", { ref: containerRef, className: "relative w-full h-full bg-gray-900 overflow-hidden" }, /* @__PURE__ */ React10__default.default.createElement(
6729
- Script__default.default,
6730
- {
6731
- src: "https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js",
6732
- strategy: "afterInteractive",
6733
- onLoad: () => {
6734
- console.log("AR.js script loaded, checking THREEx...");
6735
- const checkTHREEx = () => {
6736
- if (window.THREEx) {
6737
- console.log("THREEx found! Properties:", Object.keys(window.THREEx));
6738
- window.__arjs_ready = true;
6739
- console.log("AR.js and THREEx ready!");
6740
- } else {
6741
- console.log("THREEx not ready yet, checking window object:", Object.keys(window).filter((key) => key.includes("THREEx") || key.includes("AR")));
6742
- setTimeout(checkTHREEx, 100);
6743
- }
6744
- };
6745
- checkTHREEx();
6746
- },
6747
- onError: (error) => {
6748
- console.error("Failed to load AR.js:", error);
6749
- setState((prev) => ({
6750
- ...prev,
6751
- error: "AR.js \u52A0\u8F7D\u5931\u8D25",
6752
- isLoading: false
6753
- }));
6754
- }
6755
- }
6756
- ), /* @__PURE__ */ React10__default.default.createElement(
6757
- "canvas",
6758
- {
6759
- ref: canvasRef,
6760
- className: "absolute inset-0 w-full h-full",
6761
- style: { display: state.arReady ? "block" : "none" }
6762
- }
6763
- ), state.isLoading && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center bg-gray-900 text-white" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-white mx-auto mb-4" }), /* @__PURE__ */ React10__default.default.createElement("p", null, "\u6B63\u5728\u521D\u59CB\u5316 AR \u73AF\u5883..."))), state.error && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center bg-red-900 text-white" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-center max-w-md" }, /* @__PURE__ */ React10__default.default.createElement("h2", { className: "text-xl font-bold mb-4" }, "\u521D\u59CB\u5316\u5931\u8D25"), /* @__PURE__ */ React10__default.default.createElement("p", { className: "text-red-200 mb-4" }, state.error), /* @__PURE__ */ React10__default.default.createElement(
6764
- "button",
6765
- {
6766
- onClick: () => window.location.reload(),
6767
- className: "px-4 py-2 bg-red-600 hover:bg-red-700 rounded-lg transition-colors"
6768
- },
6769
- "\u91CD\u65B0\u52A0\u8F7D"
6770
- ))), state.arReady && !state.error && /* @__PURE__ */ React10__default.default.createElement(React10__default.default.Fragment, null, !state.modelPlaced && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 left-4 right-4 bg-black/70 text-white p-4 rounded-lg" }, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "font-bold mb-2" }, "AR \u653E\u7F6E\u8BF4\u660E"), /* @__PURE__ */ React10__default.default.createElement("p", { className: "text-sm text-gray-300" }, "1. \u5141\u8BB8\u6444\u50CF\u5934\u8BBF\u95EE\u6743\u9650", /* @__PURE__ */ React10__default.default.createElement("br", null), "2. \u51C6\u5907\u4E00\u4E2A\u6761\u7801\u6807\u8BB0 (\u503C: 0) \u6216 Hiro \u6807\u8BB0\u56FE\u6848", /* @__PURE__ */ React10__default.default.createElement("br", null), "3. \u5C06\u6444\u50CF\u5934\u5BF9\u51C6\u6807\u8BB0\uFF0C\u7EFF\u8272\u7ACB\u65B9\u4F53\u5C06\u51FA\u73B0\u5728\u6807\u8BB0\u4F4D\u7F6E", /* @__PURE__ */ React10__default.default.createElement("br", null), state.markerDetected ? /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-green-400 font-bold" }, "\u2713 \u6807\u8BB0\u5DF2\u68C0\u6D4B\u5230\uFF01") : /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-yellow-400" }, "\u7B49\u5F85\u6807\u8BB0\u68C0\u6D4B..."), /* @__PURE__ */ React10__default.default.createElement("br", null), '4. \u70B9\u51FB"\u653E\u7F6E\u6A21\u578B"\u6309\u94AE\u56FA\u5B9A\u6A21\u578B\u4F4D\u7F6E')), state.showSettings && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 right-4 bg-black/90 text-white p-4 rounded-lg min-w-80 max-w-sm max-h-96 overflow-y-auto" }, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "font-bold mb-4 text-lg" }, "\u2699\uFE0F \u8BBE\u7F6E\u9762\u677F"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-blue-300" }, "\u{1F4F7} \u6444\u50CF\u5934\u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u6444\u50CF\u5934\u671D\u5411"), /* @__PURE__ */ React10__default.default.createElement(
6771
- "select",
6772
- {
6773
- value: state.cameraFacing,
6774
- onChange: (e) => handleARSettingChange("cameraFacing", e.target.value),
6775
- className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
6776
- },
6777
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "environment" }, "\u540E\u7F6E\u6444\u50CF\u5934"),
6778
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "user" }, "\u524D\u7F6E\u6444\u50CF\u5934")
6779
- ))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-green-300" }, "\u{1F3AF} AR \u68C0\u6D4B\u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u6807\u8BB0\u7C7B\u578B"), /* @__PURE__ */ React10__default.default.createElement(
6780
- "select",
6781
- {
6782
- value: state.markerType,
6783
- onChange: (e) => handleARSettingChange("markerType", e.target.value),
6784
- className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
6785
- },
6786
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "barcode" }, "\u6761\u7801 (Barcode)"),
6787
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "pattern" }, "\u56FE\u6848 (Hiro)")
6788
- )), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u68C0\u6D4B\u8D28\u91CF"), /* @__PURE__ */ React10__default.default.createElement(
6789
- "select",
6790
- {
6791
- value: state.quality,
6792
- onChange: (e) => handleARSettingChange("quality", e.target.value),
6793
- className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
6794
- },
6795
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "low" }, "\u4F4E\u8D28\u91CF (15fps)"),
6796
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "medium" }, "\u4E2D\u7B49\u8D28\u91CF (30fps)"),
6797
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "high" }, "\u9AD8\u8D28\u91CF (60fps)")
6798
- )))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-purple-300" }, "\u{1F441}\uFE0F \u89C6\u89C9\u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement("label", { className: "flex items-center" }, /* @__PURE__ */ React10__default.default.createElement(
6799
- "input",
6800
- {
6801
- type: "checkbox",
6802
- checked: state.showWireframe,
6803
- onChange: (e) => setState((prev) => ({ ...prev, showWireframe: e.target.checked })),
6804
- className: "mr-2"
6805
- }
6806
- ), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-sm" }, "\u663E\u793A\u7EBF\u6846")), /* @__PURE__ */ React10__default.default.createElement("label", { className: "flex items-center" }, /* @__PURE__ */ React10__default.default.createElement(
6807
- "input",
6808
- {
6809
- type: "checkbox",
6810
- checked: state.lightingEnabled,
6811
- onChange: (e) => setState((prev) => ({ ...prev, lightingEnabled: e.target.checked })),
6812
- className: "mr-2"
6813
- }
6814
- ), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-sm" }, "\u542F\u7528\u5149\u7167")))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-orange-300" }, "\u{1F3AD} \u6A21\u578B\u4E0E\u52A8\u753B"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u6A21\u578B\u9009\u62E9"), /* @__PURE__ */ React10__default.default.createElement(
6815
- "select",
6816
- {
6817
- value: state.selectedModel,
6818
- onChange: (e) => setState((prev) => ({ ...prev, selectedModel: e.target.value })),
6819
- className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
6820
- },
6821
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "sphere" }, "\u{1F310} \u7403\u4F53"),
6822
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "cube" }, "\u2B1C \u7ACB\u65B9\u4F53"),
6823
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "torus" }, "\u2B55 \u5706\u73AF")
6824
- )), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u52A8\u4F5C\u9009\u62E9"), /* @__PURE__ */ React10__default.default.createElement(
6825
- "select",
6826
- {
6827
- value: state.selectedMotion,
6828
- onChange: (e) => setState((prev) => ({ ...prev, selectedMotion: e.target.value })),
6829
- className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
6830
- },
6831
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "idle" }, "\u{1F9D8} \u5F85\u673A"),
6832
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "dance" }, "\u{1F483} \u821E\u8E48"),
6833
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "wave" }, "\u{1F44B} \u6325\u624B")
6834
- )), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u97F3\u4E50\u9009\u62E9"), /* @__PURE__ */ React10__default.default.createElement(
6835
- "select",
7114
+ }, [cleanupAR, onCameraError, resize, setupAR, setupRenderer, startRenderLoop]);
7115
+ React10.useEffect(() => {
7116
+ attachModelRoot(resolvedARMode);
7117
+ }, [attachModelRoot, resolvedARMode]);
7118
+ React10.useEffect(() => {
7119
+ if (resolvedResources) {
7120
+ loadMMDResources();
7121
+ updateAudio();
7122
+ } else if (modelPresets.length === 0) {
7123
+ const message = "No model presets configured.";
7124
+ setError(message);
7125
+ setIsLoading(false);
7126
+ onError?.(new Error(message));
7127
+ }
7128
+ }, [loadMMDResources, modelPresets.length, onError, resolvedResources, updateAudio]);
7129
+ const mirroredStyle = mirrored ? { transform: "scaleX(-1)" } : void 0;
7130
+ return /* @__PURE__ */ React10__default.default.createElement(
7131
+ "div",
6836
7132
  {
6837
- value: state.selectedAudio,
6838
- onChange: (e) => setState((prev) => ({ ...prev, selectedAudio: e.target.value })),
6839
- className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
7133
+ ref: containerRef,
7134
+ className: clsx.clsx("relative w-full h-full overflow-hidden bg-black", className),
7135
+ style
6840
7136
  },
6841
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "none" }, "\u{1F507} \u65E0\u97F3\u4E50"),
6842
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "bgm1" }, "\u{1F3B5} \u80CC\u666F\u97F3\u4E50 1"),
6843
- /* @__PURE__ */ React10__default.default.createElement("option", { value: "bgm2" }, "\u{1F3B6} \u80CC\u666F\u97F3\u4E50 2")
6844
- )))), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-red-300" }, "\u{1F3AE} \u63A7\u5236\u64CD\u4F5C"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement(
6845
- "button",
6846
- {
6847
- onClick: () => {
6848
- if (modelRootRef.current) {
6849
- modelRootRef.current.visible = false;
6850
- }
6851
- if (markerRootRef.current) {
6852
- markerRootRef.current.visible = true;
6853
- }
6854
- setState((prev) => ({ ...prev, modelPlaced: false, markerDetected: false }));
7137
+ /* @__PURE__ */ React10__default.default.createElement("div", { ref: videoContainerRef, className: "absolute inset-0", style: mirroredStyle }),
7138
+ /* @__PURE__ */ React10__default.default.createElement("canvas", { ref: canvasRef, className: "absolute inset-0 w-full h-full", style: mirroredStyle }),
7139
+ isLoading && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center bg-black/70 text-white z-20" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "h-10 w-10 animate-spin rounded-full border-b-2 border-white mx-auto mb-3" }), /* @__PURE__ */ React10__default.default.createElement("div", null, "Initializing AR..."))),
7140
+ error && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center bg-red-950/80 text-white z-20" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-center max-w-sm px-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-lg font-semibold mb-2" }, "AR Error"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-sm text-red-200" }, error))),
7141
+ arReady && !error && /* @__PURE__ */ React10__default.default.createElement(React10__default.default.Fragment, null, resolvedARMode !== "overlay" /* Overlay */ && !modelPlaced && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 left-4 right-4 bg-black/70 text-white p-3 rounded-lg text-sm z-10" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "font-semibold mb-1" }, "Marker Placement"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-gray-200" }, 'Align the marker in view, then tap "', placementText, '" to place the model.'), /* @__PURE__ */ React10__default.default.createElement("div", { className: "mt-2" }, markerDetected ? /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-green-400" }, "Marker detected") : /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-yellow-400" }, "Waiting for marker..."))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 right-4 flex items-center space-x-2 z-10" }, /* @__PURE__ */ React10__default.default.createElement(
7142
+ "span",
7143
+ {
7144
+ className: clsx.clsx("h-2.5 w-2.5 rounded-full", cameraReady ? "bg-green-400" : "bg-red-400"),
7145
+ title: "Camera"
7146
+ }
7147
+ ), /* @__PURE__ */ React10__default.default.createElement(
7148
+ "span",
7149
+ {
7150
+ className: clsx.clsx("h-2.5 w-2.5 rounded-full", arReady ? "bg-green-400" : "bg-red-400"),
7151
+ title: "AR"
7152
+ }
7153
+ ), /* @__PURE__ */ React10__default.default.createElement(
7154
+ "span",
7155
+ {
7156
+ className: clsx.clsx("h-2.5 w-2.5 rounded-full", markerDetected ? "bg-blue-400" : "bg-gray-400"),
7157
+ title: "Marker"
7158
+ }
7159
+ )), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute bottom-4 left-4 right-4 flex justify-center gap-3 z-10" }, /* @__PURE__ */ React10__default.default.createElement(
7160
+ "button",
7161
+ {
7162
+ onClick: () => setSettingsVisible((prev) => !prev),
7163
+ className: "px-4 py-2 rounded-lg bg-gray-700 text-white hover:bg-gray-600"
6855
7164
  },
6856
- className: "w-full px-3 py-2 bg-blue-600 hover:bg-blue-700 rounded transition-colors text-sm"
6857
- },
6858
- "\u{1F504} \u91CD\u65B0\u8BBE\u7F6E\u6807\u8BB0\u70B9"
6859
- ), /* @__PURE__ */ React10__default.default.createElement(
6860
- "button",
6861
- {
6862
- onClick: () => {
6863
- if (modelRootRef.current) {
6864
- modelRootRef.current.clear();
6865
- modelRootRef.current.visible = false;
6866
- }
6867
- if (markerRootRef.current) {
6868
- markerRootRef.current.visible = true;
6869
- }
6870
- setState((prev) => ({
6871
- ...prev,
6872
- modelPlaced: false,
6873
- markerDetected: false,
6874
- selectedModel: "sphere",
6875
- selectedMotion: "idle",
6876
- selectedAudio: "none"
6877
- }));
7165
+ "Settings"
7166
+ ), resolvedARMode !== "overlay" /* Overlay */ && !modelPlaced && /* @__PURE__ */ React10__default.default.createElement(
7167
+ "button",
7168
+ {
7169
+ onClick: placeModel,
7170
+ disabled: !markerDetected,
7171
+ className: clsx.clsx(
7172
+ "px-5 py-2 rounded-lg text-white",
7173
+ markerDetected ? "bg-emerald-600 hover:bg-emerald-500" : "bg-gray-500"
7174
+ )
6878
7175
  },
6879
- className: "w-full px-3 py-2 bg-red-600 hover:bg-red-700 rounded transition-colors text-sm"
6880
- },
6881
- "\u{1F5D1}\uFE0F \u6E05\u9664\u6240\u6709"
6882
- ))))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute bottom-4 left-4 right-4 flex justify-center space-x-4" }, /* @__PURE__ */ React10__default.default.createElement(
6883
- "button",
6884
- {
6885
- onClick: () => setState((prev) => ({ ...prev, showSettings: !prev.showSettings })),
6886
- className: "px-4 py-2 bg-gray-700 hover:bg-gray-600 text-white rounded-lg transition-colors"
6887
- },
6888
- "\u2699\uFE0F \u8BBE\u7F6E"
6889
- ), !state.modelPlaced && /* @__PURE__ */ React10__default.default.createElement(
6890
- "button",
6891
- {
6892
- onClick: placeModel,
6893
- disabled: !state.markerDetected,
6894
- className: clsx.clsx("px-6 py-2 rounded-lg transition-colors", state.markerDetected ? "bg-green-600 hover:bg-green-700 text-white" : "bg-gray-500 text-gray-300 cursor-not-allowed")
6895
- },
6896
- "\u{1F4CD} \u653E\u7F6E\u6A21\u578B"
6897
- ), state.modelPlaced && /* @__PURE__ */ React10__default.default.createElement(
6898
- "button",
6899
- {
6900
- onClick: takePhoto,
6901
- className: "px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
6902
- },
6903
- "\u{1F4F8} \u62CD\u7167"
6904
- )), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 right-4 flex space-x-2" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: clsx.clsx("w-3 h-3 rounded-full", state.cameraReady ? "bg-green-400" : "bg-red-400"), title: "\u6444\u50CF\u5934" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: clsx.clsx("w-3 h-3 rounded-full", state.arReady ? "bg-green-400" : "bg-red-400"), title: "AR" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: clsx.clsx("w-3 h-3 rounded-full", window.DeviceOrientationEvent ? "bg-purple-400" : "bg-gray-400"), title: "\u9640\u87BA\u4EEA" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: clsx.clsx("w-3 h-3 rounded-full", state.markerDetected ? "bg-blue-400" : "bg-gray-400"), title: "\u6807\u8BB0\u68C0\u6D4B" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: clsx.clsx("w-3 h-3 rounded-full", state.modelPlaced && modelRootRef.current?.visible ? "bg-green-400" : "bg-yellow-400"), title: "\u6A21\u578B" }))));
7176
+ placementText
7177
+ ), modelPlaced && /* @__PURE__ */ React10__default.default.createElement(
7178
+ "button",
7179
+ {
7180
+ onClick: removeModel,
7181
+ className: "px-5 py-2 rounded-lg text-white bg-orange-600 hover:bg-orange-500"
7182
+ },
7183
+ "Reset"
7184
+ )), settingsVisible && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-16 right-4 bg-black/80 text-white p-4 rounded-lg w-64 space-y-3 z-10" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-sm font-semibold" }, "AR Settings"), /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs text-gray-300" }, "Model", /* @__PURE__ */ React10__default.default.createElement(
7185
+ "select",
7186
+ {
7187
+ value: selectedModelId,
7188
+ onChange: (event) => {
7189
+ setOverrideResources(null);
7190
+ setSelectedModelId(event.target.value);
7191
+ },
7192
+ className: "mt-1 w-full bg-gray-700 text-white text-sm rounded px-2 py-1"
7193
+ },
7194
+ modelPresets.map((preset) => /* @__PURE__ */ React10__default.default.createElement("option", { key: preset.id, value: preset.id }, preset.name))
7195
+ )), /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs text-gray-300" }, "Motion", /* @__PURE__ */ React10__default.default.createElement(
7196
+ "select",
7197
+ {
7198
+ value: selectedMotionId,
7199
+ onChange: (event) => {
7200
+ setOverrideResources(null);
7201
+ setSelectedMotionId(event.target.value);
7202
+ },
7203
+ className: "mt-1 w-full bg-gray-700 text-white text-sm rounded px-2 py-1"
7204
+ },
7205
+ motionPresets.map((preset) => /* @__PURE__ */ React10__default.default.createElement("option", { key: preset.id, value: preset.id }, preset.name))
7206
+ )), audioPresets && audioPresets.length > 0 && /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs text-gray-300" }, "Audio", /* @__PURE__ */ React10__default.default.createElement(
7207
+ "select",
7208
+ {
7209
+ value: selectedAudioId,
7210
+ onChange: (event) => {
7211
+ setOverrideResources(null);
7212
+ setSelectedAudioId(event.target.value);
7213
+ },
7214
+ className: "mt-1 w-full bg-gray-700 text-white text-sm rounded px-2 py-1"
7215
+ },
7216
+ audioPresets.map((preset) => /* @__PURE__ */ React10__default.default.createElement("option", { key: preset.id, value: preset.id }, preset.name))
7217
+ )), /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs text-gray-300" }, "AR Mode", /* @__PURE__ */ React10__default.default.createElement(
7218
+ "select",
7219
+ {
7220
+ value: resolvedARMode,
7221
+ onChange: (event) => {
7222
+ const next = event.target.value;
7223
+ if (!arMode) {
7224
+ setInternalARMode(next);
7225
+ }
7226
+ attachModelRoot(next);
7227
+ onARModeChange?.(next);
7228
+ },
7229
+ className: "mt-1 w-full bg-gray-700 text-white text-sm rounded px-2 py-1"
7230
+ },
7231
+ /* @__PURE__ */ React10__default.default.createElement("option", { value: "overlay" /* Overlay */ }, "Overlay"),
7232
+ /* @__PURE__ */ React10__default.default.createElement("option", { value: "world-fixed" /* WorldFixed */ }, "World Fixed")
7233
+ )), /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs text-gray-300" }, "Camera", /* @__PURE__ */ React10__default.default.createElement(
7234
+ "select",
7235
+ {
7236
+ value: cameraFacing,
7237
+ onChange: (event) => {
7238
+ const next = event.target.value;
7239
+ setCameraFacing(next);
7240
+ cleanupAR();
7241
+ setupAR(next).catch(() => void 0);
7242
+ },
7243
+ className: "mt-1 w-full bg-gray-700 text-white text-sm rounded px-2 py-1"
7244
+ },
7245
+ /* @__PURE__ */ React10__default.default.createElement("option", { value: "environment" }, "Back"),
7246
+ /* @__PURE__ */ React10__default.default.createElement("option", { value: "user" }, "Front")
7247
+ ))))
7248
+ );
6905
7249
  });
6906
- MMDARPlayer.displayName = "MMDARPlayer";
7250
+ MMDARApp.displayName = "MMDARApp";
6907
7251
 
6908
- // src/mmd/ar/types.ts
6909
- var ARMode = /* @__PURE__ */ ((ARMode2) => {
6910
- ARMode2["Overlay"] = "overlay";
6911
- ARMode2["WorldFixed"] = "world-fixed";
6912
- return ARMode2;
6913
- })(ARMode || {});
7252
+ // src/mmd/ar/MMDARPlayer.tsx
7253
+ var MMDARPlayer = MMDARApp;
7254
+ MMDARPlayer.displayName = "MMDARPlayer";
6914
7255
 
6915
7256
  // src/mmd/fx/HLSLToGLSLConverter.ts
6916
7257
  var HLSLToGLSLConverter = class {
@@ -9015,6 +9356,7 @@ exports.HistoryPanel = HistoryPanel;
9015
9356
  exports.LoadingOverlay = LoadingOverlay;
9016
9357
  exports.LoadingScreen = LoadingScreen;
9017
9358
  exports.LoopConfirmDialog = LoopConfirmDialog;
9359
+ exports.MMDARApp = MMDARApp;
9018
9360
  exports.MMDARPlayer = MMDARPlayer;
9019
9361
  exports.MMDLightingDebugPanel = MMDLightingDebugPanel;
9020
9362
  exports.MMDMusicPlayer = MMDMusicPlayer;
@@ -9023,8 +9365,10 @@ exports.MMDPlayerEnhanced = MMDPlayerEnhanced;
9023
9365
  exports.MMDPlayerEnhancedDebugInfo = MMDPlayerEnhancedDebugInfo;
9024
9366
  exports.MMDPlaylist = MMDPlaylist;
9025
9367
  exports.MMDPlaylistDebugInfo = MMDPlaylistDebugInfo;
9368
+ exports.MMDUploadPanel = MMDUploadPanel;
9026
9369
  exports.MMDVisualNovel = MMDVisualNovel;
9027
9370
  exports.MMDVisualNovelWithSelector = MMDVisualNovelWithSelector;
9371
+ exports.MMD_UPLOAD_CONFIGS = MMD_UPLOAD_CONFIGS;
9028
9372
  exports.ModelSelectorSettings = ModelSelectorSettings;
9029
9373
  exports.MultiFXAdapter = MultiFXAdapter;
9030
9374
  exports.MusicControls = MusicControls;