sa2kit 1.0.0 → 1.0.2

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 (99) hide show
  1. package/dist/UniversalFileService-CEZRJ87g.d.mts +727 -0
  2. package/dist/UniversalFileService-CEZRJ87g.d.ts +727 -0
  3. package/dist/api/index.d.mts +248 -0
  4. package/dist/api/index.d.ts +248 -0
  5. package/dist/api/index.js +294 -0
  6. package/dist/api/index.js.map +1 -0
  7. package/dist/api/index.mjs +290 -0
  8. package/dist/api/index.mjs.map +1 -0
  9. package/dist/auth/client/index.d.mts +52 -3
  10. package/dist/auth/client/index.d.ts +52 -3
  11. package/dist/auth/components/index.d.mts +149 -4
  12. package/dist/auth/components/index.d.ts +149 -4
  13. package/dist/auth/components/index.js +243 -9
  14. package/dist/auth/components/index.js.map +1 -1
  15. package/dist/auth/components/index.mjs +237 -4
  16. package/dist/auth/components/index.mjs.map +1 -1
  17. package/dist/auth/hooks/index.d.mts +31 -2
  18. package/dist/auth/hooks/index.d.ts +31 -2
  19. package/dist/auth/index.d.mts +5 -5
  20. package/dist/auth/index.d.ts +5 -5
  21. package/dist/auth/index.js +49 -17
  22. package/dist/auth/index.mjs +1 -1
  23. package/dist/auth/routes/index.d.mts +103 -5
  24. package/dist/auth/routes/index.d.ts +103 -5
  25. package/dist/auth/routes/index.js +37 -5
  26. package/dist/auth/routes/index.mjs +1 -1
  27. package/dist/chunk-42IJ7HEI.js +573 -0
  28. package/dist/chunk-42IJ7HEI.js.map +1 -0
  29. package/dist/chunk-7XLFSPDG.mjs +31 -0
  30. package/dist/chunk-7XLFSPDG.mjs.map +1 -0
  31. package/dist/chunk-GCVOKQZP.js +36 -0
  32. package/dist/chunk-GCVOKQZP.js.map +1 -0
  33. package/dist/chunk-IBLB7ARJ.mjs +560 -0
  34. package/dist/chunk-IBLB7ARJ.mjs.map +1 -0
  35. package/dist/{chunk-6FNUWAIV.js → chunk-LX4XX6W7.js} +54 -8
  36. package/dist/chunk-LX4XX6W7.js.map +1 -0
  37. package/dist/{chunk-HXFFYNIF.mjs → chunk-T5OZHYVM.mjs} +54 -8
  38. package/dist/chunk-T5OZHYVM.mjs.map +1 -0
  39. package/dist/config/server/index.d.mts +1533 -0
  40. package/dist/config/server/index.d.ts +1533 -0
  41. package/dist/config/server/index.js +1177 -0
  42. package/dist/config/server/index.js.map +1 -0
  43. package/dist/config/server/index.mjs +1138 -0
  44. package/dist/config/server/index.mjs.map +1 -0
  45. package/dist/i18n/index.d.mts +2 -1
  46. package/dist/i18n/index.d.ts +2 -1
  47. package/dist/i18n/index.js +125 -61
  48. package/dist/i18n/index.js.map +1 -1
  49. package/dist/i18n/index.mjs +126 -62
  50. package/dist/i18n/index.mjs.map +1 -1
  51. package/dist/index.js +6 -6
  52. package/dist/index.mjs +1 -1
  53. package/dist/mmd/index.d.mts +346 -0
  54. package/dist/mmd/index.d.ts +346 -0
  55. package/dist/mmd/index.js +1535 -0
  56. package/dist/mmd/index.js.map +1 -0
  57. package/dist/mmd/index.mjs +1503 -0
  58. package/dist/mmd/index.mjs.map +1 -0
  59. package/dist/storage/index.d.mts +1 -0
  60. package/dist/storage/index.d.ts +1 -0
  61. package/dist/storage/index.js +9 -9
  62. package/dist/storage/index.mjs +1 -1
  63. package/dist/{index-8VoHap_4.d.mts → types-CroexXnI.d.ts} +38 -44
  64. package/dist/{index-8VoHap_4.d.ts → types-DmsXCWvm.d.mts} +38 -44
  65. package/dist/{types-DAxQ1MeY.d.ts → types-Dt0oqeFM.d.mts} +1 -1
  66. package/dist/{types-DT8LVCvE.d.mts → types-zK6kDzDQ.d.ts} +1 -1
  67. package/dist/universalExport/index.js +17 -32
  68. package/dist/universalExport/index.js.map +1 -1
  69. package/dist/universalExport/index.mjs +2 -29
  70. package/dist/universalExport/index.mjs.map +1 -1
  71. package/dist/universalExport/server/index.d.mts +849 -8
  72. package/dist/universalExport/server/index.d.ts +849 -8
  73. package/dist/universalExport/server/index.js +1382 -2
  74. package/dist/universalExport/server/index.js.map +1 -1
  75. package/dist/universalExport/server/index.mjs +1355 -3
  76. package/dist/universalExport/server/index.mjs.map +1 -1
  77. package/dist/universalFile/index.d.mts +54 -3
  78. package/dist/universalFile/index.d.ts +54 -3
  79. package/dist/universalFile/index.js +272 -0
  80. package/dist/universalFile/index.js.map +1 -1
  81. package/dist/universalFile/index.mjs +267 -1
  82. package/dist/universalFile/index.mjs.map +1 -1
  83. package/dist/universalFile/server/index.d.mts +2541 -469
  84. package/dist/universalFile/server/index.d.ts +2541 -469
  85. package/dist/universalFile/server/index.js +830 -64
  86. package/dist/universalFile/server/index.js.map +1 -1
  87. package/dist/universalFile/server/index.mjs +803 -66
  88. package/dist/universalFile/server/index.mjs.map +1 -1
  89. package/package.json +47 -23
  90. package/dist/chunk-6FNUWAIV.js.map +0 -1
  91. package/dist/chunk-APY57REU.js +0 -300
  92. package/dist/chunk-APY57REU.js.map +0 -1
  93. package/dist/chunk-C64RY2OW.mjs +0 -295
  94. package/dist/chunk-C64RY2OW.mjs.map +0 -1
  95. package/dist/chunk-HXFFYNIF.mjs.map +0 -1
  96. package/dist/types-CoGG1rNV.d.mts +0 -258
  97. package/dist/types-CoGG1rNV.d.ts +0 -258
  98. package/dist/types-DW9qar-w.d.mts +0 -52
  99. package/dist/types-DW9qar-w.d.ts +0 -52
@@ -0,0 +1,1535 @@
1
+ 'use strict';
2
+
3
+ require('../chunk-DGUM43GV.js');
4
+ var React2 = require('react');
5
+ var THREE2 = require('three');
6
+ var threeStdlib = require('three-stdlib');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ function _interopNamespace(e) {
11
+ if (e && e.__esModule) return e;
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
22
+ });
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
27
+
28
+ var React2__default = /*#__PURE__*/_interopDefault(React2);
29
+ var THREE2__namespace = /*#__PURE__*/_interopNamespace(THREE2);
30
+
31
+ // src/mmd/utils/ammo-loader.ts
32
+ var ammoPromise = null;
33
+ var loadAmmo = (config) => {
34
+ const configKey = `${config.scriptPath}|${config.wasmBasePath}`;
35
+ const currentConfigKey = window.__AMMO_CONFIG_KEY__;
36
+ if (ammoPromise && currentConfigKey === configKey) {
37
+ return ammoPromise;
38
+ }
39
+ if (currentConfigKey && currentConfigKey !== configKey) {
40
+ ammoPromise = null;
41
+ window.Ammo = void 0;
42
+ }
43
+ ammoPromise = new Promise((resolve, reject) => {
44
+ if (typeof window === "undefined") {
45
+ resolve();
46
+ return;
47
+ }
48
+ if (window.Ammo && currentConfigKey === configKey) {
49
+ console.log("\u2705 [Ammo] \u5DF2\u52A0\u8F7D\uFF0C\u76F4\u63A5\u4F7F\u7528");
50
+ resolve();
51
+ return;
52
+ }
53
+ console.log("\u{1F4E6} [Ammo] \u5F00\u59CB\u52A0\u8F7D Ammo.js...");
54
+ console.log("\u{1F4C2} [Ammo] \u811A\u672C\u8DEF\u5F84:", config.scriptPath);
55
+ console.log("\u{1F4C2} [Ammo] WASM \u57FA\u7840\u8DEF\u5F84:", config.wasmBasePath);
56
+ window.__AMMO_CONFIG_KEY__ = configKey;
57
+ window.AMMO_PATH = config.wasmBasePath;
58
+ const script = document.createElement("script");
59
+ script.src = config.scriptPath;
60
+ script.async = true;
61
+ script.onload = () => {
62
+ console.log("\u2705 [Ammo] \u811A\u672C\u52A0\u8F7D\u5B8C\u6210\uFF0C\u7B49\u5F85\u521D\u59CB\u5316...");
63
+ const checkAmmo = () => {
64
+ if (typeof window.Ammo === "function") {
65
+ console.log("\u{1F504} [Ammo] \u5F00\u59CB\u521D\u59CB\u5316 WASM...");
66
+ window.Ammo({
67
+ locateFile: (path) => {
68
+ console.log("\u{1F4CD} [Ammo] \u5B9A\u4F4D\u6587\u4EF6:", path);
69
+ if (path.endsWith(".wasm")) {
70
+ return config.wasmBasePath + path;
71
+ }
72
+ return path;
73
+ }
74
+ }).then((AmmoLib) => {
75
+ console.log("\u2705 [Ammo] \u521D\u59CB\u5316\u5B8C\u6210\uFF01");
76
+ window.Ammo = AmmoLib;
77
+ resolve();
78
+ }).catch((err) => {
79
+ console.error("\u274C [Ammo] \u521D\u59CB\u5316\u5931\u8D25:", err);
80
+ reject(err);
81
+ });
82
+ } else {
83
+ if (window.Ammo) {
84
+ console.log("\u2705 [Ammo] \u5DF2\u521D\u59CB\u5316");
85
+ resolve();
86
+ } else {
87
+ console.log("\u23F3 [Ammo] \u7B49\u5F85\u521D\u59CB\u5316...");
88
+ setTimeout(checkAmmo, 100);
89
+ }
90
+ }
91
+ };
92
+ checkAmmo();
93
+ };
94
+ script.onerror = (e) => {
95
+ console.error("\u274C [Ammo] \u52A0\u8F7D\u5931\u8D25:", e);
96
+ reject(new Error(`Failed to load Ammo.js from ${config.scriptPath}. Please ensure the file exists.`));
97
+ ammoPromise = null;
98
+ window.__AMMO_CONFIG_KEY__ = void 0;
99
+ };
100
+ document.body.appendChild(script);
101
+ });
102
+ return ammoPromise;
103
+ };
104
+
105
+ // src/mmd/components/MMDPlayerBase.tsx
106
+ var MMDPlayerBase = ({
107
+ modelUrl,
108
+ vmdUrl,
109
+ cameraUrl,
110
+ audioUrl,
111
+ physics = true,
112
+ width = "100%",
113
+ height = "100%",
114
+ onLoad,
115
+ onProgress,
116
+ onError
117
+ }) => {
118
+ const containerRef = React2.useRef(null);
119
+ const [loading, setLoading] = React2.useState(true);
120
+ const [error, setError] = React2.useState(null);
121
+ React2.useEffect(() => {
122
+ if (!containerRef.current) return;
123
+ let scene;
124
+ let camera;
125
+ let renderer;
126
+ let effect;
127
+ let helper;
128
+ let clock;
129
+ let animationId;
130
+ const init = async () => {
131
+ try {
132
+ setLoading(true);
133
+ setError(null);
134
+ if (physics) {
135
+ await loadAmmo({
136
+ scriptPath: "/mikutalking/libs/ammo.wasm.js",
137
+ wasmBasePath: "/mikutalking/libs/"
138
+ });
139
+ }
140
+ const container = containerRef.current;
141
+ const w = container.clientWidth;
142
+ const h = container.clientHeight;
143
+ scene = new THREE2__namespace.Scene();
144
+ scene.background = new THREE2__namespace.Color(16777215);
145
+ camera = new THREE2__namespace.PerspectiveCamera(45, w / h, 1, 2e3);
146
+ camera.position.z = 30;
147
+ const ambient = new THREE2__namespace.AmbientLight(6710886);
148
+ scene.add(ambient);
149
+ const directionalLight = new THREE2__namespace.DirectionalLight(8943462);
150
+ directionalLight.position.set(-1, 1, 1).normalize();
151
+ scene.add(directionalLight);
152
+ renderer = new THREE2__namespace.WebGLRenderer({ antialias: true });
153
+ renderer.setPixelRatio(window.devicePixelRatio);
154
+ renderer.setSize(w, h);
155
+ container.appendChild(renderer.domElement);
156
+ effect = new threeStdlib.OutlineEffect(renderer);
157
+ helper = new threeStdlib.MMDAnimationHelper({
158
+ afterglow: 2
159
+ });
160
+ const loader = new threeStdlib.MMDLoader();
161
+ loader.load(
162
+ modelUrl,
163
+ (mesh) => {
164
+ scene.add(mesh);
165
+ if (vmdUrl) {
166
+ loader.loadAnimation(
167
+ vmdUrl,
168
+ mesh,
169
+ (vmdObject) => {
170
+ helper.add(mesh, {
171
+ animation: vmdObject,
172
+ physics
173
+ });
174
+ },
175
+ (xhr) => {
176
+ if (onProgress) onProgress(xhr);
177
+ },
178
+ (err) => {
179
+ console.error("Error loading animation", err);
180
+ if (onError) onError(err);
181
+ }
182
+ );
183
+ } else {
184
+ helper.add(mesh, { physics });
185
+ }
186
+ if (cameraUrl) {
187
+ loader.loadAnimation(
188
+ cameraUrl,
189
+ camera,
190
+ (cameraVmdObject) => {
191
+ helper.add(camera, {
192
+ animation: cameraVmdObject
193
+ });
194
+ },
195
+ void 0,
196
+ (err) => {
197
+ console.error("Error loading camera motion", err);
198
+ }
199
+ );
200
+ }
201
+ if (audioUrl) {
202
+ new THREE2__namespace.AudioLoader().load(
203
+ audioUrl,
204
+ (buffer) => {
205
+ const listener = new THREE2__namespace.AudioListener();
206
+ camera.add(listener);
207
+ const audio = new THREE2__namespace.Audio(listener);
208
+ audio.setBuffer(buffer);
209
+ helper.add(audio);
210
+ },
211
+ void 0,
212
+ (err) => {
213
+ console.error("Error loading audio", err);
214
+ }
215
+ );
216
+ }
217
+ if (onLoad) onLoad();
218
+ setLoading(false);
219
+ },
220
+ (xhr) => {
221
+ if (onProgress) onProgress(xhr);
222
+ },
223
+ (err) => {
224
+ setError("Failed to load model");
225
+ if (onError) onError(err);
226
+ setLoading(false);
227
+ }
228
+ );
229
+ clock = new THREE2__namespace.Clock();
230
+ const animate = () => {
231
+ animationId = requestAnimationFrame(animate);
232
+ helper.update(clock.getDelta());
233
+ effect.render(scene, camera);
234
+ };
235
+ animate();
236
+ const handleResize = () => {
237
+ if (!container) return;
238
+ const width2 = container.clientWidth;
239
+ const height2 = container.clientHeight;
240
+ camera.aspect = width2 / height2;
241
+ camera.updateProjectionMatrix();
242
+ effect.setSize(width2, height2);
243
+ };
244
+ window.addEventListener("resize", handleResize);
245
+ return () => {
246
+ window.removeEventListener("resize", handleResize);
247
+ };
248
+ } catch (e) {
249
+ console.error(e);
250
+ setError("Initialization error");
251
+ setLoading(false);
252
+ }
253
+ return void 0;
254
+ };
255
+ init();
256
+ return () => {
257
+ if (animationId) cancelAnimationFrame(animationId);
258
+ if (renderer) {
259
+ renderer.dispose();
260
+ const domElement = renderer.domElement;
261
+ if (domElement && domElement.parentNode) {
262
+ domElement.parentNode.removeChild(domElement);
263
+ }
264
+ }
265
+ };
266
+ }, [modelUrl, vmdUrl, cameraUrl, audioUrl, physics]);
267
+ return /* @__PURE__ */ React2__default.default.createElement(
268
+ "div",
269
+ {
270
+ ref: containerRef,
271
+ style: { width, height, position: "relative", overflow: "hidden" }
272
+ },
273
+ loading && /* @__PURE__ */ React2__default.default.createElement("div", { style: {
274
+ position: "absolute",
275
+ top: 0,
276
+ left: 0,
277
+ width: "100%",
278
+ height: "100%",
279
+ display: "flex",
280
+ justifyContent: "center",
281
+ alignItems: "center",
282
+ background: "#f0f0f0",
283
+ color: "#666",
284
+ zIndex: 1
285
+ } }, "Loading MMD..."),
286
+ error && /* @__PURE__ */ React2__default.default.createElement("div", { style: {
287
+ position: "absolute",
288
+ top: 0,
289
+ left: 0,
290
+ width: "100%",
291
+ height: "100%",
292
+ display: "flex",
293
+ justifyContent: "center",
294
+ alignItems: "center",
295
+ background: "#ffeeee",
296
+ color: "#cc0000",
297
+ zIndex: 2
298
+ } }, error)
299
+ );
300
+ };
301
+ var MMDPlayerEnhanced = ({
302
+ resources,
303
+ resourcesList,
304
+ defaultResourceId,
305
+ resourceOptions,
306
+ defaultSelection,
307
+ stage,
308
+ autoPlay = false,
309
+ loop = false,
310
+ className = "",
311
+ style,
312
+ onLoad,
313
+ onError,
314
+ onResourceChange,
315
+ onSelectionChange,
316
+ onAudioEnded,
317
+ onAnimationEnded
318
+ }) => {
319
+ console.log("\u{1F3A8} [MMDPlayerEnhanced] \u7EC4\u4EF6\u521D\u59CB\u5316");
320
+ const [selectedResourceId, setSelectedResourceId] = React2.useState(
321
+ defaultResourceId || resourcesList?.[0]?.id || ""
322
+ );
323
+ const [selectedModelId, setSelectedModelId] = React2.useState(
324
+ defaultSelection?.modelId || resourceOptions?.models?.[0]?.id || ""
325
+ );
326
+ const [selectedMotionId, setSelectedMotionId] = React2.useState(
327
+ defaultSelection?.motionId || ""
328
+ );
329
+ const [selectedAudioId, setSelectedAudioId] = React2.useState(
330
+ defaultSelection?.audioId || ""
331
+ );
332
+ const [selectedCameraId, setSelectedCameraId] = React2.useState(
333
+ defaultSelection?.cameraId || ""
334
+ );
335
+ const [selectedStageModelId, setSelectedStageModelId] = React2.useState(
336
+ defaultSelection?.stageModelId || ""
337
+ );
338
+ const [selectedBackgroundId, setSelectedBackgroundId] = React2.useState(
339
+ defaultSelection?.backgroundId || ""
340
+ );
341
+ const [showSettings, setShowSettings] = React2.useState(false);
342
+ const [expandedSection, setExpandedSection] = React2.useState(null);
343
+ const currentResources = React2.useMemo(() => {
344
+ if (resourceOptions) {
345
+ const model = resourceOptions.models?.find((m) => m.id === selectedModelId);
346
+ const motion = resourceOptions.motions?.find((m) => m.id === selectedMotionId);
347
+ const audio = resourceOptions.audios?.find((a) => a.id === selectedAudioId);
348
+ const camera = resourceOptions.cameras?.find((c) => c.id === selectedCameraId);
349
+ const stageModel = resourceOptions.stageModels?.find((s) => s.id === selectedStageModelId);
350
+ const background = resourceOptions.backgrounds?.find((b) => b.id === selectedBackgroundId);
351
+ return {
352
+ modelPath: model?.path || resourceOptions.models?.[0]?.path || "",
353
+ motionPath: motion?.path,
354
+ audioPath: audio?.path,
355
+ cameraPath: camera?.path,
356
+ stageModelPath: stageModel?.path,
357
+ backgroundPath: background?.path
358
+ };
359
+ }
360
+ if (resourcesList && resourcesList.length > 0) {
361
+ const selected = resourcesList.find((r) => r.id === selectedResourceId);
362
+ const resourceItem = selected || resourcesList[0];
363
+ if (!resourceItem) {
364
+ throw new Error("\u65E0\u6CD5\u627E\u5230\u6709\u6548\u7684\u8D44\u6E90\u914D\u7F6E");
365
+ }
366
+ return resourceItem.resources;
367
+ }
368
+ if (!resources) {
369
+ throw new Error("\u5FC5\u987B\u63D0\u4F9B resources\u3001resourcesList \u6216 resourceOptions");
370
+ }
371
+ return resources;
372
+ }, [
373
+ resources,
374
+ resourcesList,
375
+ selectedResourceId,
376
+ resourceOptions,
377
+ selectedModelId,
378
+ selectedMotionId,
379
+ selectedAudioId,
380
+ selectedCameraId,
381
+ selectedStageModelId,
382
+ selectedBackgroundId
383
+ ]);
384
+ console.log("\u{1F4C2} [MMDPlayerEnhanced] \u5F53\u524D\u8D44\u6E90\u914D\u7F6E:", currentResources);
385
+ console.log("\u{1F3AD} [MMDPlayerEnhanced] \u821E\u53F0\u914D\u7F6E:", stage);
386
+ const containerRef = React2.useRef(null);
387
+ const rendererRef = React2.useRef(null);
388
+ const sceneRef = React2.useRef(null);
389
+ const cameraRef = React2.useRef(null);
390
+ const controlsRef = React2.useRef(null);
391
+ const helperRef = React2.useRef(null);
392
+ const clockRef = React2.useRef(new THREE2__namespace.Clock());
393
+ const audioRef = React2.useRef(null);
394
+ const animationIdRef = React2.useRef(null);
395
+ const isPlayingRef = React2.useRef(false);
396
+ const isLoadedRef = React2.useRef(false);
397
+ const shouldAutoPlayAfterReloadRef = React2.useRef(false);
398
+ const vmdDataRef = React2.useRef(null);
399
+ const animationDurationRef = React2.useRef(0);
400
+ const hasAudioRef = React2.useRef(false);
401
+ const animationEndedFiredRef = React2.useRef(false);
402
+ const lastAnimationTimeRef = React2.useRef(0);
403
+ const animationStoppedCountRef = React2.useRef(0);
404
+ const [loading, setLoading] = React2.useState(false);
405
+ const [loadingProgress, setLoadingProgress] = React2.useState(0);
406
+ const [error, setError] = React2.useState(null);
407
+ const [isPlaying, setIsPlaying] = React2.useState(false);
408
+ const [isInitialized, setIsInitialized] = React2.useState(false);
409
+ const [reloadTrigger, setReloadTrigger] = React2.useState(0);
410
+ const [needReset, setNeedReset] = React2.useState(false);
411
+ React2.useEffect(() => {
412
+ console.log("\u{1F3D7}\uFE0F [MMDPlayerEnhanced] \u573A\u666F\u521D\u59CB\u5316 useEffect \u89E6\u53D1");
413
+ if (!containerRef.current) {
414
+ console.warn("\u26A0\uFE0F [MMDPlayerEnhanced] containerRef.current \u4E0D\u5B58\u5728");
415
+ return;
416
+ }
417
+ console.log("\u2705 [MMDPlayerEnhanced] \u5BB9\u5668\u5143\u7D20\u5B58\u5728\uFF0C\u5F00\u59CB\u521D\u59CB\u5316\u573A\u666F");
418
+ const container = containerRef.current;
419
+ if (container.children.length > 0) {
420
+ console.log("\u26A0\uFE0F [MMDPlayerEnhanced] \u573A\u666F\u5DF2\u7ECF\u521D\u59CB\u5316\uFF0C\u8DF3\u8FC7");
421
+ return;
422
+ }
423
+ const width = container.clientWidth;
424
+ const height = container.clientHeight;
425
+ const scene = new THREE2__namespace.Scene();
426
+ scene.background = new THREE2__namespace.Color(stage?.backgroundColor || "#000000");
427
+ sceneRef.current = scene;
428
+ const camera = new THREE2__namespace.PerspectiveCamera(45, width / height, 1, 2e3);
429
+ const camPos = stage?.cameraPosition || { x: 0, y: 10, z: 30 };
430
+ camera.position.set(camPos.x, camPos.y, camPos.z);
431
+ cameraRef.current = camera;
432
+ const renderer = new THREE2__namespace.WebGLRenderer({ antialias: true });
433
+ renderer.setSize(width, height);
434
+ renderer.setPixelRatio(window.devicePixelRatio);
435
+ container.appendChild(renderer.domElement);
436
+ rendererRef.current = renderer;
437
+ const ambient = new THREE2__namespace.AmbientLight(16777215, 0.6);
438
+ scene.add(ambient);
439
+ const directionalLight = new THREE2__namespace.DirectionalLight(16777215, 0.8);
440
+ directionalLight.position.set(1, 1, 1);
441
+ scene.add(directionalLight);
442
+ if (stage?.showGrid !== false) {
443
+ const gridHelper = new THREE2__namespace.PolarGridHelper(30, 10);
444
+ scene.add(gridHelper);
445
+ }
446
+ const controls = new threeStdlib.OrbitControls(camera, renderer.domElement);
447
+ const target = stage?.cameraTarget || { x: 0, y: 10, z: 0 };
448
+ controls.target.set(target.x, target.y, target.z);
449
+ controls.update();
450
+ controlsRef.current = controls;
451
+ const handleResize = () => {
452
+ if (!container || !camera || !renderer) return;
453
+ const newWidth = container.clientWidth;
454
+ const newHeight = container.clientHeight;
455
+ camera.aspect = newWidth / newHeight;
456
+ camera.updateProjectionMatrix();
457
+ renderer.setSize(newWidth, newHeight);
458
+ };
459
+ window.addEventListener("resize", handleResize);
460
+ const animate = () => {
461
+ animationIdRef.current = requestAnimationFrame(animate);
462
+ if (helperRef.current && isPlayingRef.current) {
463
+ const delta = clockRef.current.getDelta();
464
+ helperRef.current.update(delta);
465
+ if (!hasAudioRef.current && !loop && !animationEndedFiredRef.current) {
466
+ const currentTime = clockRef.current.getElapsedTime();
467
+ if (animationDurationRef.current > 0) {
468
+ if (currentTime >= animationDurationRef.current - 0.1) {
469
+ console.log("\u{1F3AC} [MMDPlayerEnhanced] \u52A8\u753B\u64AD\u653E\u7ED3\u675F\uFF08\u65F6\u957F\u5224\u5B9A\uFF09");
470
+ animationEndedFiredRef.current = true;
471
+ isPlayingRef.current = false;
472
+ setIsPlaying(false);
473
+ onAnimationEnded?.();
474
+ }
475
+ } else {
476
+ if (Math.abs(currentTime - lastAnimationTimeRef.current) < 1e-3) {
477
+ animationStoppedCountRef.current++;
478
+ if (animationStoppedCountRef.current > 30) {
479
+ console.log("\u{1F3AC} [MMDPlayerEnhanced] \u52A8\u753B\u64AD\u653E\u7ED3\u675F\uFF08\u505C\u6B62\u68C0\u6D4B\uFF09");
480
+ animationEndedFiredRef.current = true;
481
+ isPlayingRef.current = false;
482
+ setIsPlaying(false);
483
+ onAnimationEnded?.();
484
+ }
485
+ } else {
486
+ animationStoppedCountRef.current = 0;
487
+ }
488
+ lastAnimationTimeRef.current = currentTime;
489
+ }
490
+ }
491
+ }
492
+ if (controlsRef.current) {
493
+ controlsRef.current.update();
494
+ }
495
+ if (renderer && scene && camera) {
496
+ renderer.render(scene, camera);
497
+ }
498
+ };
499
+ animate();
500
+ setIsInitialized(true);
501
+ console.log("\u2705 [MMDPlayerEnhanced] \u573A\u666F\u521D\u59CB\u5316\u5B8C\u6210");
502
+ return () => {
503
+ window.removeEventListener("resize", handleResize);
504
+ if (animationIdRef.current) {
505
+ cancelAnimationFrame(animationIdRef.current);
506
+ }
507
+ if (renderer) {
508
+ renderer.dispose();
509
+ if (renderer.domElement && renderer.domElement.parentNode) {
510
+ container.removeChild(renderer.domElement);
511
+ }
512
+ }
513
+ if (controls) {
514
+ controls.dispose();
515
+ }
516
+ };
517
+ }, [stage]);
518
+ const clearOldResources = () => {
519
+ console.log("\u{1F9F9} [MMDPlayerEnhanced] \u5F00\u59CB\u6E05\u9664\u65E7\u8D44\u6E90");
520
+ if (!sceneRef.current) return;
521
+ if (isPlayingRef.current) {
522
+ isPlayingRef.current = false;
523
+ setIsPlaying(false);
524
+ }
525
+ if (audioRef.current) {
526
+ audioRef.current.pause();
527
+ audioRef.current.currentTime = 0;
528
+ audioRef.current = null;
529
+ }
530
+ if (helperRef.current) {
531
+ helperRef.current = null;
532
+ }
533
+ const objectsToRemove = [];
534
+ sceneRef.current.traverse((child) => {
535
+ if (child.type === "SkinnedMesh" || child.isSkinnedMesh) {
536
+ objectsToRemove.push(child);
537
+ }
538
+ if (child.type === "Mesh" && child !== sceneRef.current) {
539
+ objectsToRemove.push(child);
540
+ }
541
+ });
542
+ objectsToRemove.forEach((obj) => {
543
+ if (obj.parent) {
544
+ obj.parent.remove(obj);
545
+ }
546
+ if (obj.geometry) {
547
+ obj.geometry.dispose();
548
+ }
549
+ if (obj.material) {
550
+ if (Array.isArray(obj.material)) {
551
+ obj.material.forEach((mat) => mat.dispose());
552
+ } else {
553
+ obj.material.dispose();
554
+ }
555
+ }
556
+ });
557
+ clockRef.current = new THREE2__namespace.Clock();
558
+ vmdDataRef.current = null;
559
+ console.log(`\u2705 [MMDPlayerEnhanced] \u5DF2\u6E05\u9664 ${objectsToRemove.length} \u4E2A\u65E7\u5BF9\u8C61`);
560
+ };
561
+ React2.useEffect(() => {
562
+ console.log("\u{1F4E6} [MMDPlayerEnhanced] \u8D44\u6E90\u52A0\u8F7D useEffect \u89E6\u53D1");
563
+ console.log("\u{1F50D} [MMDPlayerEnhanced] sceneRef.current:", sceneRef.current);
564
+ console.log("\u{1F50D} [MMDPlayerEnhanced] cameraRef.current:", cameraRef.current);
565
+ console.log("\u{1F50D} [MMDPlayerEnhanced] isLoadedRef.current:", isLoadedRef.current);
566
+ if (!sceneRef.current || !cameraRef.current) {
567
+ console.warn("\u26A0\uFE0F [MMDPlayerEnhanced] \u573A\u666F\u6216\u76F8\u673A\u672A\u521D\u59CB\u5316\uFF0C\u8DF3\u8FC7\u8D44\u6E90\u52A0\u8F7D");
568
+ return;
569
+ }
570
+ if (isLoadedRef.current) {
571
+ console.log("\u26A0\uFE0F [MMDPlayerEnhanced] \u8D44\u6E90\u5DF2\u52A0\u8F7D\uFF0C\u8DF3\u8FC7\u91CD\u590D\u52A0\u8F7D");
572
+ return;
573
+ }
574
+ console.log("\u2705 [MMDPlayerEnhanced] \u573A\u666F\u548C\u76F8\u673A\u5DF2\u5C31\u7EEA\uFF0C\u5F00\u59CB\u52A0\u8F7D\u8D44\u6E90");
575
+ clearOldResources();
576
+ isLoadedRef.current = true;
577
+ const loadMMD = async () => {
578
+ try {
579
+ setLoading(true);
580
+ setLoadingProgress(0);
581
+ animationDurationRef.current = 0;
582
+ hasAudioRef.current = false;
583
+ animationEndedFiredRef.current = false;
584
+ lastAnimationTimeRef.current = 0;
585
+ animationStoppedCountRef.current = 0;
586
+ if (stage?.enablePhysics !== false) {
587
+ const ammoScriptPath = stage?.ammoPath || "/mikutalking/libs/ammo.wasm.js";
588
+ const ammoWasmPath = stage?.ammoWasmPath || "/mikutalking/libs/";
589
+ console.log("\u{1F527} [MMDPlayerEnhanced] \u68C0\u6D4B\u5230\u542F\u7528\u7269\u7406\uFF0C\u5F00\u59CB\u52A0\u8F7D Ammo.js");
590
+ console.log("\u{1F4C2} [MMDPlayerEnhanced] Ammo \u811A\u672C\u8DEF\u5F84:", ammoScriptPath);
591
+ console.log("\u{1F4C2} [MMDPlayerEnhanced] Ammo WASM \u8DEF\u5F84:", ammoWasmPath);
592
+ setLoadingProgress(5);
593
+ await loadAmmo({
594
+ scriptPath: ammoScriptPath,
595
+ wasmBasePath: ammoWasmPath
596
+ });
597
+ console.log("\u2705 [MMDPlayerEnhanced] Ammo.js \u52A0\u8F7D\u5B8C\u6210");
598
+ }
599
+ const loader = new threeStdlib.MMDLoader();
600
+ const helper = new threeStdlib.MMDAnimationHelper();
601
+ helperRef.current = helper;
602
+ setLoadingProgress(20);
603
+ console.log("\u{1F3AD} \u5F00\u59CB\u52A0\u8F7D\u6A21\u578B:", currentResources.modelPath);
604
+ const mesh = await new Promise((resolve, reject) => {
605
+ loader.load(
606
+ currentResources.modelPath,
607
+ (object) => {
608
+ console.log("\u2705 \u6A21\u578B\u52A0\u8F7D\u6210\u529F");
609
+ resolve(object);
610
+ },
611
+ (progress) => {
612
+ if (progress.total > 0) {
613
+ const percent = progress.loaded / progress.total * 30 + 20;
614
+ setLoadingProgress(Math.min(percent, 50));
615
+ }
616
+ },
617
+ (error2) => {
618
+ console.error("\u274C \u6A21\u578B\u52A0\u8F7D\u5931\u8D25:", error2);
619
+ reject(error2);
620
+ }
621
+ );
622
+ });
623
+ if (!sceneRef.current) {
624
+ throw new Error("\u573A\u666F\u672A\u521D\u59CB\u5316");
625
+ }
626
+ sceneRef.current.add(mesh);
627
+ if (currentResources.stageModelPath) {
628
+ console.log("\u{1F3F0} \u5F00\u59CB\u52A0\u8F7D\u573A\u666F\u6A21\u578B:", currentResources.stageModelPath);
629
+ const stageMesh = await new Promise((resolve, reject) => {
630
+ loader.load(
631
+ currentResources.stageModelPath,
632
+ (object) => {
633
+ console.log("\u2705 \u573A\u666F\u6A21\u578B\u52A0\u8F7D\u6210\u529F");
634
+ resolve(object);
635
+ },
636
+ void 0,
637
+ (error2) => {
638
+ console.error("\u274C \u573A\u666F\u6A21\u578B\u52A0\u8F7D\u5931\u8D25:", error2);
639
+ reject(error2);
640
+ }
641
+ );
642
+ });
643
+ sceneRef.current.add(stageMesh);
644
+ }
645
+ if (currentResources.backgroundPath && sceneRef.current) {
646
+ console.log("\u{1F5BC}\uFE0F \u5F00\u59CB\u52A0\u8F7D\u80CC\u666F\u56FE\u7247:", currentResources.backgroundPath);
647
+ const textureLoader = new THREE2__namespace.TextureLoader();
648
+ const backgroundTexture = await new Promise((resolve, reject) => {
649
+ textureLoader.load(
650
+ currentResources.backgroundPath,
651
+ (texture) => resolve(texture),
652
+ void 0,
653
+ (err) => reject(err)
654
+ );
655
+ });
656
+ backgroundTexture.colorSpace = THREE2__namespace.SRGBColorSpace;
657
+ if (stage?.backgroundType === "skybox") {
658
+ backgroundTexture.mapping = THREE2__namespace.EquirectangularReflectionMapping;
659
+ sceneRef.current.background = backgroundTexture;
660
+ sceneRef.current.environment = backgroundTexture;
661
+ } else if (stage?.backgroundType === "image") {
662
+ sceneRef.current.background = backgroundTexture;
663
+ } else {
664
+ sceneRef.current.background = backgroundTexture;
665
+ }
666
+ console.log("\u2705 \u80CC\u666F\u56FE\u7247\u52A0\u8F7D\u6210\u529F");
667
+ }
668
+ let vmd = null;
669
+ let cameraVmd = null;
670
+ if (currentResources.motionPath) {
671
+ setLoadingProgress(60);
672
+ console.log("\u{1F483} \u5F00\u59CB\u52A0\u8F7D\u52A8\u4F5C:", currentResources.motionPath);
673
+ vmd = await new Promise((resolve, reject) => {
674
+ loader.loadAnimation(
675
+ currentResources.motionPath,
676
+ mesh,
677
+ (vmdObject) => {
678
+ console.log("\u2705 \u52A8\u4F5C\u52A0\u8F7D\u6210\u529F");
679
+ resolve(vmdObject);
680
+ },
681
+ (progress) => {
682
+ if (progress.total > 0) {
683
+ const percent = progress.loaded / progress.total * 20 + 60;
684
+ setLoadingProgress(Math.min(percent, 80));
685
+ }
686
+ },
687
+ (error2) => {
688
+ console.error("\u274C \u52A8\u4F5C\u52A0\u8F7D\u5931\u8D25:", error2);
689
+ reject(error2);
690
+ }
691
+ );
692
+ });
693
+ helper.add(mesh, {
694
+ animation: vmd,
695
+ physics: stage?.enablePhysics !== false
696
+ });
697
+ if (vmd) {
698
+ let maxDuration = 0;
699
+ if (vmd.duration !== void 0) {
700
+ maxDuration = vmd.duration;
701
+ } else if (Array.isArray(vmd) && vmd.length > 0 && vmd[0].duration !== void 0) {
702
+ maxDuration = vmd[0].duration;
703
+ } else if (vmd.clip && vmd.clip.duration !== void 0) {
704
+ maxDuration = vmd.clip.duration;
705
+ }
706
+ if (maxDuration > 0) {
707
+ animationDurationRef.current = maxDuration;
708
+ console.log("\u23F1\uFE0F \u52A8\u753B\u65F6\u957F:", maxDuration, "\u79D2");
709
+ } else {
710
+ console.warn("\u26A0\uFE0F \u65E0\u6CD5\u83B7\u53D6\u52A8\u753B\u65F6\u957F\uFF0C\u5C06\u65E0\u6CD5\u81EA\u52A8\u68C0\u6D4B\u52A8\u753B\u7ED3\u675F");
711
+ console.log("\u{1F4CB} VMD \u6570\u636E\u7ED3\u6784:", vmd);
712
+ }
713
+ }
714
+ } else {
715
+ helper.add(mesh, { physics: stage?.enablePhysics !== false });
716
+ }
717
+ if (currentResources.cameraPath && cameraRef.current) {
718
+ setLoadingProgress(80);
719
+ console.log("\u{1F4F7} \u5F00\u59CB\u52A0\u8F7D\u955C\u5934:", currentResources.cameraPath);
720
+ cameraVmd = await new Promise((resolve, reject) => {
721
+ loader.loadAnimation(
722
+ currentResources.cameraPath,
723
+ cameraRef.current,
724
+ (vmdObject) => {
725
+ console.log("\u2705 \u955C\u5934\u52A0\u8F7D\u6210\u529F");
726
+ resolve(vmdObject);
727
+ },
728
+ void 0,
729
+ (error2) => {
730
+ console.error("\u274C \u955C\u5934\u52A0\u8F7D\u5931\u8D25:", error2);
731
+ reject(error2);
732
+ }
733
+ );
734
+ });
735
+ helper.add(cameraRef.current, { animation: cameraVmd });
736
+ }
737
+ if (currentResources.audioPath) {
738
+ setLoadingProgress(90);
739
+ console.log("\u{1F3B5} \u5F00\u59CB\u52A0\u8F7D\u97F3\u9891:", currentResources.audioPath);
740
+ const audio = new Audio(currentResources.audioPath);
741
+ audio.volume = 0.5;
742
+ audio.loop = loop;
743
+ audioRef.current = audio;
744
+ hasAudioRef.current = true;
745
+ audio.onended = () => {
746
+ if (!loop) {
747
+ setIsPlaying(false);
748
+ if (helperRef.current && sceneRef.current) {
749
+ const mesh2 = sceneRef.current.children.find(
750
+ (child) => child.type === "SkinnedMesh"
751
+ );
752
+ if (mesh2) {
753
+ helperRef.current.pose(mesh2, {});
754
+ }
755
+ }
756
+ }
757
+ onAudioEnded?.();
758
+ };
759
+ console.log("\u2705 \u97F3\u9891\u52A0\u8F7D\u6210\u529F");
760
+ }
761
+ setLoadingProgress(100);
762
+ setLoading(false);
763
+ vmdDataRef.current = {
764
+ mesh,
765
+ vmd,
766
+ cameraVmd
767
+ };
768
+ console.log("\u{1F389} \u6240\u6709\u8D44\u6E90\u52A0\u8F7D\u5B8C\u6210\uFF01");
769
+ if (shouldAutoPlayAfterReloadRef.current) {
770
+ shouldAutoPlayAfterReloadRef.current = false;
771
+ setTimeout(() => play(), 500);
772
+ } else if (autoPlay) {
773
+ setTimeout(() => play(), 500);
774
+ }
775
+ onLoad?.();
776
+ } catch (err) {
777
+ console.error("\u274C MMD\u52A0\u8F7D\u5931\u8D25:", err);
778
+ setError(err.message || "\u52A0\u8F7D\u5931\u8D25");
779
+ setLoading(false);
780
+ isLoadedRef.current = false;
781
+ onError?.(err);
782
+ }
783
+ };
784
+ loadMMD();
785
+ }, [currentResources, stage?.enablePhysics, autoPlay, loop, onLoad, onError, reloadTrigger]);
786
+ const play = () => {
787
+ console.log("\u{1F3AC} [play] \u51FD\u6570\u88AB\u8C03\u7528\uFF0CneedReset =", needReset);
788
+ if (!helperRef.current) return;
789
+ if (needReset && vmdDataRef.current && sceneRef.current && cameraRef.current) {
790
+ console.log("\u{1F504} \u68C0\u6D4B\u5230\u9700\u8981\u91CD\u7F6E\uFF0C\u91CD\u65B0\u521D\u59CB\u5316 helper\uFF08\u4FDD\u7559\u6A21\u578B\uFF09");
791
+ const { mesh, vmd, cameraVmd } = vmdDataRef.current;
792
+ const newHelper = new threeStdlib.MMDAnimationHelper();
793
+ helperRef.current = newHelper;
794
+ clockRef.current = new THREE2__namespace.Clock();
795
+ if (vmd && typeof vmd === "object") {
796
+ console.log("\u{1F4E6} \u91CD\u65B0\u6DFB\u52A0\u6A21\u578B\u52A8\u753B\uFF0Cvmd:", vmd);
797
+ try {
798
+ newHelper.add(mesh, {
799
+ animation: vmd,
800
+ physics: stage?.enablePhysics !== false
801
+ });
802
+ } catch (error2) {
803
+ console.error("\u274C \u91CD\u65B0\u6DFB\u52A0\u6A21\u578B\u52A8\u753B\u5931\u8D25:", error2);
804
+ console.log("\u{1F4CB} vmd \u6570\u636E:", vmd);
805
+ newHelper.add(mesh, { physics: stage?.enablePhysics !== false });
806
+ }
807
+ } else {
808
+ newHelper.add(mesh, { physics: stage?.enablePhysics !== false });
809
+ }
810
+ if (cameraVmd && typeof cameraVmd === "object") {
811
+ console.log("\u{1F4F7} \u91CD\u65B0\u6DFB\u52A0\u76F8\u673A\u52A8\u753B");
812
+ try {
813
+ newHelper.add(cameraRef.current, { animation: cameraVmd });
814
+ } catch (error2) {
815
+ console.error("\u274C \u91CD\u65B0\u6DFB\u52A0\u76F8\u673A\u52A8\u753B\u5931\u8D25:", error2);
816
+ }
817
+ }
818
+ if (audioRef.current) {
819
+ audioRef.current.currentTime = 0;
820
+ }
821
+ setNeedReset(false);
822
+ console.log("\u2705 Helper \u91CD\u65B0\u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u51C6\u5907\u4ECE\u7B2C\u4E00\u5E27\u64AD\u653E");
823
+ }
824
+ if (audioRef.current) {
825
+ audioRef.current.play();
826
+ }
827
+ helperRef.current.enable("animation", true);
828
+ helperRef.current.enable("ik", true);
829
+ helperRef.current.enable("grant", true);
830
+ helperRef.current.enable("physics", true);
831
+ if (!isPlaying) {
832
+ clockRef.current.start();
833
+ }
834
+ animationEndedFiredRef.current = false;
835
+ lastAnimationTimeRef.current = 0;
836
+ animationStoppedCountRef.current = 0;
837
+ isPlayingRef.current = true;
838
+ setIsPlaying(true);
839
+ console.log("\u25B6\uFE0F \u5F00\u59CB\u64AD\u653E\uFF08\u5305\u62EC\u76F8\u673A\u52A8\u753B\uFF09");
840
+ };
841
+ const pause = () => {
842
+ if (!helperRef.current) return;
843
+ if (audioRef.current) {
844
+ audioRef.current.pause();
845
+ }
846
+ clockRef.current.stop();
847
+ isPlayingRef.current = false;
848
+ setIsPlaying(false);
849
+ console.log("\u23F8\uFE0F \u6682\u505C\u64AD\u653E\uFF08\u5305\u62EC\u76F8\u673A\u52A8\u753B\uFF09");
850
+ };
851
+ const stop = () => {
852
+ if (!helperRef.current || !sceneRef.current) return;
853
+ isPlayingRef.current = false;
854
+ setIsPlaying(false);
855
+ if (audioRef.current) {
856
+ audioRef.current.pause();
857
+ audioRef.current.currentTime = 0;
858
+ }
859
+ clockRef.current.stop();
860
+ clockRef.current = new THREE2__namespace.Clock();
861
+ const mesh = sceneRef.current.children.find(
862
+ (child) => child.type === "SkinnedMesh" || child.isSkinnedMesh
863
+ );
864
+ if (mesh && mesh.skeleton) {
865
+ mesh.skeleton.pose();
866
+ }
867
+ if (cameraRef.current) {
868
+ const camPos = stage?.cameraPosition || { x: 0, y: 10, z: 30 };
869
+ const camTarget = stage?.cameraTarget || { x: 0, y: 10, z: 0 };
870
+ cameraRef.current.position.set(camPos.x, camPos.y, camPos.z);
871
+ if (controlsRef.current) {
872
+ controlsRef.current.target.set(camTarget.x, camTarget.y, camTarget.z);
873
+ controlsRef.current.update();
874
+ } else {
875
+ cameraRef.current.lookAt(camTarget.x, camTarget.y, camTarget.z);
876
+ }
877
+ }
878
+ setNeedReset(true);
879
+ console.log("\u23F9\uFE0F \u505C\u6B62\u64AD\u653E\u5E76\u91CD\u7F6E\u5230\u521D\u59CB\u72B6\u6001\uFF0CneedReset = true");
880
+ };
881
+ const handleResourceChange = (resourceId) => {
882
+ console.log("\u{1F504} [MMDPlayerEnhanced] \u5207\u6362\u8D44\u6E90:", resourceId);
883
+ if (isPlayingRef.current) {
884
+ isPlayingRef.current = false;
885
+ setIsPlaying(false);
886
+ }
887
+ if (audioRef.current) {
888
+ audioRef.current.pause();
889
+ audioRef.current.currentTime = 0;
890
+ }
891
+ setSelectedResourceId(resourceId);
892
+ isLoadedRef.current = false;
893
+ setNeedReset(false);
894
+ setReloadTrigger((prev) => prev + 1);
895
+ if (onResourceChange) {
896
+ onResourceChange(resourceId);
897
+ }
898
+ setShowSettings(false);
899
+ };
900
+ const handleSelectionChange = (type, id) => {
901
+ console.log(`\u{1F504} [MMDPlayerEnhanced] \u9009\u62E9${type}:`, id);
902
+ const wasPlaying = isPlayingRef.current;
903
+ if (isPlayingRef.current) {
904
+ isPlayingRef.current = false;
905
+ setIsPlaying(false);
906
+ }
907
+ if (audioRef.current) {
908
+ audioRef.current.pause();
909
+ audioRef.current.currentTime = 0;
910
+ }
911
+ if (type === "model") setSelectedModelId(id);
912
+ if (type === "motion") setSelectedMotionId(id);
913
+ if (type === "audio") setSelectedAudioId(id);
914
+ if (type === "camera") setSelectedCameraId(id);
915
+ if (type === "stageModel") setSelectedStageModelId(id);
916
+ if (type === "background") setSelectedBackgroundId(id);
917
+ isLoadedRef.current = false;
918
+ setNeedReset(false);
919
+ if (wasPlaying || autoPlay) {
920
+ shouldAutoPlayAfterReloadRef.current = true;
921
+ }
922
+ setReloadTrigger((prev) => prev + 1);
923
+ if (onSelectionChange) {
924
+ const newSelection = {
925
+ modelId: type === "model" ? id : selectedModelId,
926
+ motionId: type === "motion" ? id : selectedMotionId,
927
+ audioId: type === "audio" ? id : selectedAudioId,
928
+ cameraId: type === "camera" ? id : selectedCameraId,
929
+ stageModelId: type === "stageModel" ? id : selectedStageModelId,
930
+ backgroundId: type === "background" ? id : selectedBackgroundId
931
+ };
932
+ onSelectionChange(newSelection);
933
+ }
934
+ };
935
+ return /* @__PURE__ */ React2__default.default.createElement("div", { className: `relative h-full w-full ${className}`, style }, /* @__PURE__ */ React2__default.default.createElement("div", { ref: containerRef, className: "h-full w-full" }), loading && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-black text-white" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "mb-4 text-2xl" }, "\u{1F3AD} \u52A0\u8F7DMMD\u8D44\u6E90\u4E2D..."), /* @__PURE__ */ React2__default.default.createElement("div", { className: "h-4 w-3/4 max-w-md overflow-hidden rounded-full bg-gray-700" }, /* @__PURE__ */ React2__default.default.createElement(
936
+ "div",
937
+ {
938
+ className: "h-full bg-gradient-to-r from-blue-500 to-purple-500 transition-all duration-300",
939
+ style: { width: `${loadingProgress}%` }
940
+ }
941
+ )), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-2 text-sm text-gray-400" }, Math.round(loadingProgress), "%")), isInitialized && !loading && !error && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute bottom-4 left-1/2 flex -translate-x-1/2 gap-2 rounded-full bg-black/50 px-4 py-2 backdrop-blur-md" }, !isPlaying ? /* @__PURE__ */ React2__default.default.createElement(
942
+ "button",
943
+ {
944
+ onClick: play,
945
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-green-500 text-xl text-white transition-colors hover:bg-green-600",
946
+ title: "\u64AD\u653E"
947
+ },
948
+ "\u25B6\uFE0F"
949
+ ) : /* @__PURE__ */ React2__default.default.createElement(
950
+ "button",
951
+ {
952
+ onClick: pause,
953
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-yellow-500 text-xl text-white transition-colors hover:bg-yellow-600",
954
+ title: "\u6682\u505C"
955
+ },
956
+ "\u23F8\uFE0F"
957
+ ), /* @__PURE__ */ React2__default.default.createElement(
958
+ "button",
959
+ {
960
+ onClick: stop,
961
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-red-500 text-xl text-white transition-colors hover:bg-red-600",
962
+ title: "\u505C\u6B62"
963
+ },
964
+ "\u23F9\uFE0F"
965
+ ), (resourcesList && resourcesList.length > 1 || resourceOptions) && /* @__PURE__ */ React2__default.default.createElement(
966
+ "button",
967
+ {
968
+ onClick: () => setShowSettings(true),
969
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-purple-500 text-xl text-white transition-colors hover:bg-purple-600",
970
+ title: "\u8BBE\u7F6E"
971
+ },
972
+ "\u2699\uFE0F"
973
+ )), showSettings && resourcesList && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "max-h-[80vh] w-full max-w-md overflow-hidden rounded-2xl bg-gradient-to-br from-gray-900 to-black shadow-2xl" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center justify-between border-b border-white/10 px-6 py-4" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-xl font-bold text-white" }, "\u9009\u62E9\u8D44\u6E90"), /* @__PURE__ */ React2__default.default.createElement(
974
+ "button",
975
+ {
976
+ onClick: () => setShowSettings(false),
977
+ className: "text-2xl text-white/60 transition-colors hover:text-white"
978
+ },
979
+ "\u2715"
980
+ )), /* @__PURE__ */ React2__default.default.createElement("div", { className: "max-h-[60vh] overflow-y-auto p-4" }, resourcesList.map((item) => /* @__PURE__ */ React2__default.default.createElement(
981
+ "button",
982
+ {
983
+ key: item.id,
984
+ onClick: () => handleResourceChange(item.id),
985
+ className: `mb-3 w-full rounded-xl p-4 text-left transition-all ${selectedResourceId === item.id ? "bg-gradient-to-r from-purple-600 to-blue-600 shadow-lg" : "bg-white/5 hover:bg-white/10"}`
986
+ },
987
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React2__default.default.createElement("h4", { className: "font-semibold text-white" }, item.name), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-1 flex flex-wrap gap-2 text-xs text-white/60" }, item.resources.modelPath && /* @__PURE__ */ React2__default.default.createElement("span", { className: "rounded bg-white/10 px-2 py-1" }, "\u6A21\u578B"), item.resources.motionPath && /* @__PURE__ */ React2__default.default.createElement("span", { className: "rounded bg-white/10 px-2 py-1" }, "\u52A8\u4F5C"), item.resources.cameraPath && /* @__PURE__ */ React2__default.default.createElement("span", { className: "rounded bg-white/10 px-2 py-1" }, "\u76F8\u673A"), item.resources.audioPath && /* @__PURE__ */ React2__default.default.createElement("span", { className: "rounded bg-white/10 px-2 py-1" }, "\u97F3\u9891"))), selectedResourceId === item.id && /* @__PURE__ */ React2__default.default.createElement("div", { className: "ml-4 text-2xl" }, "\u2713"))
988
+ ))))), showSettings && resourceOptions && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute top-4 right-4 z-50 w-80 rounded-xl bg-black/90 backdrop-blur-md shadow-2xl border border-white/10" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center justify-between border-b border-white/10 px-4 py-3" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-sm font-bold text-white" }, "\u8D44\u6E90\u8BBE\u7F6E"), /* @__PURE__ */ React2__default.default.createElement(
989
+ "button",
990
+ {
991
+ onClick: () => setShowSettings(false),
992
+ className: "text-lg text-white/60 transition-colors hover:text-white"
993
+ },
994
+ "\u2715"
995
+ )), /* @__PURE__ */ React2__default.default.createElement("div", { className: "max-h-[70vh] overflow-y-auto p-4 space-y-2" }, resourceOptions.models && resourceOptions.models.length > 0 && /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-lg bg-white/5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
996
+ "button",
997
+ {
998
+ onClick: () => setExpandedSection(expandedSection === "model" ? null : "model"),
999
+ className: "w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-white/10 transition-colors"
1000
+ },
1001
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs font-medium text-white/70" }, "\u6A21\u578B"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm text-white font-medium" }, resourceOptions.models.find((m) => m.id === selectedModelId)?.name || "\u672A\u9009\u62E9")),
1002
+ /* @__PURE__ */ React2__default.default.createElement("span", { className: `text-white/60 transition-transform ${expandedSection === "model" ? "rotate-180" : ""}` }, "\u25BC")
1003
+ ), expandedSection === "model" && /* @__PURE__ */ React2__default.default.createElement("div", { className: "border-t border-white/10 p-2 space-y-1 max-h-60 overflow-y-auto" }, resourceOptions.models.map((model) => /* @__PURE__ */ React2__default.default.createElement(
1004
+ "button",
1005
+ {
1006
+ key: model.id,
1007
+ onClick: () => {
1008
+ handleSelectionChange("model", model.id);
1009
+ setExpandedSection(null);
1010
+ },
1011
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedModelId === model.id ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1012
+ },
1013
+ model.name
1014
+ )))), resourceOptions.motions && resourceOptions.motions.length > 0 && /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-lg bg-white/5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
1015
+ "button",
1016
+ {
1017
+ onClick: () => setExpandedSection(expandedSection === "motion" ? null : "motion"),
1018
+ className: "w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-white/10 transition-colors"
1019
+ },
1020
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs font-medium text-white/70" }, "\u52A8\u4F5C"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm text-white font-medium" }, selectedMotionId ? resourceOptions.motions.find((m) => m.id === selectedMotionId)?.name : "\u65E0")),
1021
+ /* @__PURE__ */ React2__default.default.createElement("span", { className: `text-white/60 transition-transform ${expandedSection === "motion" ? "rotate-180" : ""}` }, "\u25BC")
1022
+ ), expandedSection === "motion" && /* @__PURE__ */ React2__default.default.createElement("div", { className: "border-t border-white/10 p-2 space-y-1 max-h-60 overflow-y-auto" }, /* @__PURE__ */ React2__default.default.createElement(
1023
+ "button",
1024
+ {
1025
+ onClick: () => {
1026
+ handleSelectionChange("motion", "");
1027
+ setExpandedSection(null);
1028
+ },
1029
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedMotionId === "" ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1030
+ },
1031
+ "\u65E0"
1032
+ ), resourceOptions.motions.map((motion) => /* @__PURE__ */ React2__default.default.createElement(
1033
+ "button",
1034
+ {
1035
+ key: motion.id,
1036
+ onClick: () => {
1037
+ handleSelectionChange("motion", motion.id);
1038
+ setExpandedSection(null);
1039
+ },
1040
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedMotionId === motion.id ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1041
+ },
1042
+ motion.name
1043
+ )))), resourceOptions.audios && resourceOptions.audios.length > 0 && /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-lg bg-white/5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
1044
+ "button",
1045
+ {
1046
+ onClick: () => setExpandedSection(expandedSection === "audio" ? null : "audio"),
1047
+ className: "w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-white/10 transition-colors"
1048
+ },
1049
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs font-medium text-white/70" }, "\u97F3\u4E50"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm text-white font-medium" }, selectedAudioId ? resourceOptions.audios.find((a) => a.id === selectedAudioId)?.name : "\u65E0")),
1050
+ /* @__PURE__ */ React2__default.default.createElement("span", { className: `text-white/60 transition-transform ${expandedSection === "audio" ? "rotate-180" : ""}` }, "\u25BC")
1051
+ ), expandedSection === "audio" && /* @__PURE__ */ React2__default.default.createElement("div", { className: "border-t border-white/10 p-2 space-y-1 max-h-60 overflow-y-auto" }, /* @__PURE__ */ React2__default.default.createElement(
1052
+ "button",
1053
+ {
1054
+ onClick: () => {
1055
+ handleSelectionChange("audio", "");
1056
+ setExpandedSection(null);
1057
+ },
1058
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedAudioId === "" ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1059
+ },
1060
+ "\u65E0"
1061
+ ), resourceOptions.audios.map((audio) => /* @__PURE__ */ React2__default.default.createElement(
1062
+ "button",
1063
+ {
1064
+ key: audio.id,
1065
+ onClick: () => {
1066
+ handleSelectionChange("audio", audio.id);
1067
+ setExpandedSection(null);
1068
+ },
1069
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedAudioId === audio.id ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1070
+ },
1071
+ audio.name
1072
+ )))), resourceOptions.cameras && resourceOptions.cameras.length > 0 && /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-lg bg-white/5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
1073
+ "button",
1074
+ {
1075
+ onClick: () => setExpandedSection(expandedSection === "camera" ? null : "camera"),
1076
+ className: "w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-white/10 transition-colors"
1077
+ },
1078
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs font-medium text-white/70" }, "\u76F8\u673A"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm text-white font-medium" }, selectedCameraId ? resourceOptions.cameras.find((c) => c.id === selectedCameraId)?.name : "\u65E0")),
1079
+ /* @__PURE__ */ React2__default.default.createElement("span", { className: `text-white/60 transition-transform ${expandedSection === "camera" ? "rotate-180" : ""}` }, "\u25BC")
1080
+ ), expandedSection === "camera" && /* @__PURE__ */ React2__default.default.createElement("div", { className: "border-t border-white/10 p-2 space-y-1 max-h-60 overflow-y-auto" }, /* @__PURE__ */ React2__default.default.createElement(
1081
+ "button",
1082
+ {
1083
+ onClick: () => {
1084
+ handleSelectionChange("camera", "");
1085
+ setExpandedSection(null);
1086
+ },
1087
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedCameraId === "" ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1088
+ },
1089
+ "\u65E0"
1090
+ ), resourceOptions.cameras.map((camera) => /* @__PURE__ */ React2__default.default.createElement(
1091
+ "button",
1092
+ {
1093
+ key: camera.id,
1094
+ onClick: () => {
1095
+ handleSelectionChange("camera", camera.id);
1096
+ setExpandedSection(null);
1097
+ },
1098
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedCameraId === camera.id ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1099
+ },
1100
+ camera.name
1101
+ )))), resourceOptions.stageModels && resourceOptions.stageModels.length > 0 && /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-lg bg-white/5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
1102
+ "button",
1103
+ {
1104
+ onClick: () => setExpandedSection(expandedSection === "stageModel" ? null : "stageModel"),
1105
+ className: "w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-white/10 transition-colors"
1106
+ },
1107
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs font-medium text-white/70" }, "\u573A\u666F"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm text-white font-medium" }, selectedStageModelId ? resourceOptions.stageModels.find((s) => s.id === selectedStageModelId)?.name : "\u65E0")),
1108
+ /* @__PURE__ */ React2__default.default.createElement("span", { className: `text-white/60 transition-transform ${expandedSection === "stageModel" ? "rotate-180" : ""}` }, "\u25BC")
1109
+ ), expandedSection === "stageModel" && /* @__PURE__ */ React2__default.default.createElement("div", { className: "border-t border-white/10 p-2 space-y-1 max-h-60 overflow-y-auto" }, /* @__PURE__ */ React2__default.default.createElement(
1110
+ "button",
1111
+ {
1112
+ onClick: () => {
1113
+ handleSelectionChange("stageModel", "");
1114
+ setExpandedSection(null);
1115
+ },
1116
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedStageModelId === "" ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1117
+ },
1118
+ "\u65E0"
1119
+ ), resourceOptions.stageModels.map((stageModel) => /* @__PURE__ */ React2__default.default.createElement(
1120
+ "button",
1121
+ {
1122
+ key: stageModel.id,
1123
+ onClick: () => {
1124
+ handleSelectionChange("stageModel", stageModel.id);
1125
+ setExpandedSection(null);
1126
+ },
1127
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedStageModelId === stageModel.id ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1128
+ },
1129
+ stageModel.name
1130
+ )))), resourceOptions.backgrounds && resourceOptions.backgrounds.length > 0 && /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-lg bg-white/5 overflow-hidden" }, /* @__PURE__ */ React2__default.default.createElement(
1131
+ "button",
1132
+ {
1133
+ onClick: () => setExpandedSection(expandedSection === "background" ? null : "background"),
1134
+ className: "w-full flex items-center justify-between px-3 py-2.5 text-left hover:bg-white/10 transition-colors"
1135
+ },
1136
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs font-medium text-white/70" }, "\u80CC\u666F"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm text-white font-medium" }, selectedBackgroundId ? resourceOptions.backgrounds.find((b) => b.id === selectedBackgroundId)?.name : "\u65E0")),
1137
+ /* @__PURE__ */ React2__default.default.createElement("span", { className: `text-white/60 transition-transform ${expandedSection === "background" ? "rotate-180" : ""}` }, "\u25BC")
1138
+ ), expandedSection === "background" && /* @__PURE__ */ React2__default.default.createElement("div", { className: "border-t border-white/10 p-2 space-y-1 max-h-60 overflow-y-auto" }, /* @__PURE__ */ React2__default.default.createElement(
1139
+ "button",
1140
+ {
1141
+ onClick: () => {
1142
+ handleSelectionChange("background", "");
1143
+ setExpandedSection(null);
1144
+ },
1145
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedBackgroundId === "" ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1146
+ },
1147
+ "\u65E0"
1148
+ ), resourceOptions.backgrounds.map((background) => /* @__PURE__ */ React2__default.default.createElement(
1149
+ "button",
1150
+ {
1151
+ key: background.id,
1152
+ onClick: () => {
1153
+ handleSelectionChange("background", background.id);
1154
+ setExpandedSection(null);
1155
+ },
1156
+ className: `w-full rounded px-3 py-2 text-left text-sm transition-all ${selectedBackgroundId === background.id ? "bg-purple-600 text-white font-medium" : "text-white/80 hover:bg-white/10"}`
1157
+ },
1158
+ background.name
1159
+ )))))));
1160
+ };
1161
+ var MMDPlaylist = ({
1162
+ playlist,
1163
+ stage,
1164
+ defaultNodeIndex = 0,
1165
+ className,
1166
+ style,
1167
+ onLoad,
1168
+ onError,
1169
+ onNodeChange,
1170
+ onPlaylistComplete
1171
+ }) => {
1172
+ console.log("\u{1F3AC} [MMDPlaylist] \u7EC4\u4EF6\u521D\u59CB\u5316");
1173
+ console.log("\u{1F4CB} [MMDPlaylist] \u64AD\u653E\u5217\u8868:", playlist.name, "\u8282\u70B9\u6570:", playlist.nodes.length);
1174
+ const [currentNodeIndex, setCurrentNodeIndex] = React2.useState(defaultNodeIndex);
1175
+ const [showSettings, setShowSettings] = React2.useState(false);
1176
+ const [preloadedNodes, setPreloadedNodes] = React2.useState(/* @__PURE__ */ new Set());
1177
+ const [isPreloading, setIsPreloading] = React2.useState(true);
1178
+ const [preloadProgress, setPreloadProgress] = React2.useState(0);
1179
+ const [editableNodes, setEditableNodes] = React2.useState(playlist.nodes);
1180
+ const currentNodeIndexRef = React2.useRef(defaultNodeIndex);
1181
+ const isAutoSwitchRef = React2.useRef(false);
1182
+ const playerRefsMap = React2.useRef(/* @__PURE__ */ new Map());
1183
+ React2.useEffect(() => {
1184
+ currentNodeIndexRef.current = currentNodeIndex;
1185
+ }, [currentNodeIndex]);
1186
+ const currentNode = editableNodes[currentNodeIndex];
1187
+ if (!currentNode) {
1188
+ console.error("\u274C [MMDPlaylist] \u65E0\u6548\u7684\u8282\u70B9\u7D22\u5F15:", currentNodeIndex);
1189
+ return /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex h-full w-full items-center justify-center bg-black text-white" }, /* @__PURE__ */ React2__default.default.createElement("p", null, "\u64AD\u653E\u5217\u8868\u8282\u70B9\u7D22\u5F15\u65E0\u6548"));
1190
+ }
1191
+ console.log("\u{1F3AF} [MMDPlaylist] \u5F53\u524D\u8282\u70B9:", currentNode.name, "\u7D22\u5F15:", currentNodeIndex);
1192
+ React2.useEffect(() => {
1193
+ console.log(`\u{1F504} [MMDPlaylist] \u8282\u70B9\u5207\u6362: ${currentNodeIndex} - ${currentNode.name}`);
1194
+ onNodeChange?.(currentNodeIndex, currentNode);
1195
+ if (!isPreloading && (isAutoSwitchRef.current || playlist.autoPlay)) {
1196
+ console.log(`\u25B6\uFE0F [MMDPlaylist] \u51C6\u5907\u64AD\u653E\u8282\u70B9 ${currentNodeIndex}`);
1197
+ if (!preloadedNodes.has(currentNodeIndex)) {
1198
+ console.warn(`\u26A0\uFE0F [MMDPlaylist] \u8282\u70B9 ${currentNodeIndex} \u5C1A\u672A\u9884\u52A0\u8F7D\u5B8C\u6210\uFF0C\u7B49\u5F85...`);
1199
+ return;
1200
+ }
1201
+ requestAnimationFrame(() => {
1202
+ const playerElement = playerRefsMap.current.get(currentNodeIndex);
1203
+ if (playerElement) {
1204
+ const playButton = playerElement.querySelector('button[title="\u64AD\u653E"]');
1205
+ if (playButton) {
1206
+ console.log(`\u{1F3AC} [MMDPlaylist] \u89E6\u53D1\u8282\u70B9 ${currentNodeIndex} \u64AD\u653E`);
1207
+ playButton.click();
1208
+ } else {
1209
+ console.warn(`\u26A0\uFE0F [MMDPlaylist] \u672A\u627E\u5230\u8282\u70B9 ${currentNodeIndex} \u7684\u64AD\u653E\u6309\u94AE`);
1210
+ }
1211
+ } else {
1212
+ console.warn(`\u26A0\uFE0F [MMDPlaylist] \u672A\u627E\u5230\u8282\u70B9 ${currentNodeIndex} \u7684 DOM \u5143\u7D20`);
1213
+ }
1214
+ });
1215
+ }
1216
+ }, [currentNodeIndex, currentNode, onNodeChange, isPreloading, playlist.autoPlay, preloadedNodes]);
1217
+ const handleNodePreloaded = (nodeIndex) => {
1218
+ console.log(`\u2705 [MMDPlaylist] \u8282\u70B9 ${nodeIndex} \u9884\u52A0\u8F7D\u5B8C\u6210`);
1219
+ setPreloadedNodes((prev) => {
1220
+ const newSet = new Set(prev);
1221
+ newSet.add(nodeIndex);
1222
+ return newSet;
1223
+ });
1224
+ };
1225
+ React2.useEffect(() => {
1226
+ if (preloadedNodes.size === editableNodes.length) {
1227
+ console.log("\u{1F389} [MMDPlaylist] \u6240\u6709\u8282\u70B9\u9884\u52A0\u8F7D\u5B8C\u6210");
1228
+ setIsPreloading(false);
1229
+ onLoad?.();
1230
+ } else {
1231
+ const progress = Math.round(preloadedNodes.size / editableNodes.length * 100);
1232
+ setPreloadProgress(progress);
1233
+ }
1234
+ }, [preloadedNodes, editableNodes.length, onLoad]);
1235
+ const handlePlaybackEnded = (nodeIndex) => {
1236
+ console.log(`\u{1F3B5} [MMDPlaylist] \u8282\u70B9 ${nodeIndex} \u64AD\u653E\u5B8C\u6210`);
1237
+ if (nodeIndex !== currentNodeIndexRef.current) {
1238
+ console.log(`\u26A0\uFE0F [MMDPlaylist] \u5FFD\u7565\u975E\u5F53\u524D\u8282\u70B9 ${nodeIndex} \u7684\u64AD\u653E\u7ED3\u675F\u4E8B\u4EF6\uFF08\u5F53\u524D: ${currentNodeIndexRef.current}\uFF09`);
1239
+ return;
1240
+ }
1241
+ const node = editableNodes[nodeIndex];
1242
+ if (!node) return;
1243
+ if (node.loop) {
1244
+ console.log("\u{1F501} [MMDPlaylist] \u5F53\u524D\u8282\u70B9\u5FAA\u73AF\u64AD\u653E");
1245
+ return;
1246
+ }
1247
+ const isLastNode = nodeIndex === editableNodes.length - 1;
1248
+ if (!isLastNode) {
1249
+ console.log(`\u27A1\uFE0F [MMDPlaylist] \u5207\u6362\u5230\u4E0B\u4E00\u4E2A\u8282\u70B9: ${nodeIndex + 1}`);
1250
+ isAutoSwitchRef.current = true;
1251
+ setCurrentNodeIndex(nodeIndex + 1);
1252
+ return;
1253
+ }
1254
+ if (playlist.loop) {
1255
+ console.log("\u{1F501} [MMDPlaylist] \u64AD\u653E\u5217\u8868\u5FAA\u73AF\uFF0C\u56DE\u5230\u7B2C\u4E00\u4E2A\u8282\u70B9");
1256
+ isAutoSwitchRef.current = true;
1257
+ setCurrentNodeIndex(0);
1258
+ return;
1259
+ }
1260
+ console.log("\u2705 [MMDPlaylist] \u64AD\u653E\u5217\u8868\u64AD\u653E\u5B8C\u6210");
1261
+ onPlaylistComplete?.();
1262
+ };
1263
+ const playlistPrevious = () => {
1264
+ const newIndex = currentNodeIndex > 0 ? currentNodeIndex - 1 : editableNodes.length - 1;
1265
+ console.log(`\u2B05\uFE0F [MMDPlaylist] \u4E0A\u4E00\u4E2A\u8282\u70B9: ${newIndex}`);
1266
+ isAutoSwitchRef.current = false;
1267
+ setCurrentNodeIndex(newIndex);
1268
+ };
1269
+ const playlistNext = () => {
1270
+ const newIndex = currentNodeIndex < editableNodes.length - 1 ? currentNodeIndex + 1 : 0;
1271
+ console.log(`\u27A1\uFE0F [MMDPlaylist] \u4E0B\u4E00\u4E2A\u8282\u70B9: ${newIndex}`);
1272
+ isAutoSwitchRef.current = false;
1273
+ setCurrentNodeIndex(newIndex);
1274
+ };
1275
+ const playlistJumpTo = (index) => {
1276
+ if (index < 0 || index >= editableNodes.length) return;
1277
+ console.log(`\u{1F3AF} [MMDPlaylist] \u8DF3\u8F6C\u5230\u8282\u70B9: ${index}`);
1278
+ isAutoSwitchRef.current = false;
1279
+ setCurrentNodeIndex(index);
1280
+ };
1281
+ const handleDeleteNode = (index) => {
1282
+ if (editableNodes.length <= 1) {
1283
+ alert("\u64AD\u653E\u5217\u8868\u81F3\u5C11\u9700\u8981\u4FDD\u7559\u4E00\u4E2A\u8282\u70B9");
1284
+ return;
1285
+ }
1286
+ const newNodes = editableNodes.filter((_, i) => i !== index);
1287
+ setEditableNodes(newNodes);
1288
+ if (index < currentNodeIndex) {
1289
+ setCurrentNodeIndex(currentNodeIndex - 1);
1290
+ } else if (index === currentNodeIndex) {
1291
+ const newIndex = Math.max(0, currentNodeIndex - 1);
1292
+ setCurrentNodeIndex(newIndex);
1293
+ }
1294
+ console.log(`\u{1F5D1}\uFE0F [MMDPlaylist] \u5220\u9664\u8282\u70B9 ${index}`);
1295
+ };
1296
+ const handleMoveNodeUp = (index) => {
1297
+ if (index === 0) return;
1298
+ const newNodes = [...editableNodes];
1299
+ const temp = newNodes[index - 1];
1300
+ newNodes[index - 1] = newNodes[index];
1301
+ newNodes[index] = temp;
1302
+ setEditableNodes(newNodes);
1303
+ if (currentNodeIndex === index) {
1304
+ setCurrentNodeIndex(index - 1);
1305
+ } else if (currentNodeIndex === index - 1) {
1306
+ setCurrentNodeIndex(index);
1307
+ }
1308
+ console.log(`\u2B06\uFE0F [MMDPlaylist] \u8282\u70B9 ${index} \u4E0A\u79FB`);
1309
+ };
1310
+ const handleMoveNodeDown = (index) => {
1311
+ if (index === editableNodes.length - 1) return;
1312
+ const newNodes = [...editableNodes];
1313
+ const temp = newNodes[index];
1314
+ newNodes[index] = newNodes[index + 1];
1315
+ newNodes[index + 1] = temp;
1316
+ setEditableNodes(newNodes);
1317
+ if (currentNodeIndex === index) {
1318
+ setCurrentNodeIndex(index + 1);
1319
+ } else if (currentNodeIndex === index + 1) {
1320
+ setCurrentNodeIndex(index);
1321
+ }
1322
+ console.log(`\u2B07\uFE0F [MMDPlaylist] \u8282\u70B9 ${index} \u4E0B\u79FB`);
1323
+ };
1324
+ const shouldAutoPlayInitial = playlist.autoPlay && currentNodeIndex === defaultNodeIndex && !isPreloading;
1325
+ return /* @__PURE__ */ React2__default.default.createElement("div", { className: `relative ${className || ""}`, style }, editableNodes.map((node, index) => {
1326
+ return /* @__PURE__ */ React2__default.default.createElement(
1327
+ "div",
1328
+ {
1329
+ key: `player-${node.id}-${index}`,
1330
+ ref: (el) => {
1331
+ if (el) {
1332
+ playerRefsMap.current.set(index, el);
1333
+ }
1334
+ },
1335
+ className: "absolute inset-0",
1336
+ style: {
1337
+ visibility: index === currentNodeIndex ? "visible" : "hidden",
1338
+ zIndex: index === currentNodeIndex ? 1 : 0
1339
+ }
1340
+ },
1341
+ /* @__PURE__ */ React2__default.default.createElement(
1342
+ MMDPlayerEnhanced,
1343
+ {
1344
+ resources: node.resources,
1345
+ stage,
1346
+ autoPlay: index === currentNodeIndex && shouldAutoPlayInitial,
1347
+ loop: node.loop || false,
1348
+ className: "h-full w-full",
1349
+ onLoad: () => {
1350
+ handleNodePreloaded(index);
1351
+ },
1352
+ onError: (error) => {
1353
+ console.error(`\u274C [MMDPlaylist] \u8282\u70B9 ${index} \u52A0\u8F7D\u5931\u8D25:`, error);
1354
+ if (index === currentNodeIndex) {
1355
+ onError?.(error);
1356
+ }
1357
+ },
1358
+ onAudioEnded: () => handlePlaybackEnded(index),
1359
+ onAnimationEnded: () => handlePlaybackEnded(index)
1360
+ }
1361
+ )
1362
+ );
1363
+ }), isPreloading && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute inset-0 z-50 flex flex-col items-center justify-center bg-black/80 backdrop-blur-sm" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "mb-4 text-2xl font-bold text-white" }, "\u6B63\u5728\u9884\u52A0\u8F7D\u64AD\u653E\u5217\u8868"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mb-2 text-lg text-white/80" }, preloadedNodes.size, " / ", editableNodes.length, " \u8282\u70B9"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "h-2 w-64 overflow-hidden rounded-full bg-white/20" }, /* @__PURE__ */ React2__default.default.createElement(
1364
+ "div",
1365
+ {
1366
+ className: "h-full bg-gradient-to-r from-purple-500 to-blue-500 transition-all duration-300",
1367
+ style: { width: `${preloadProgress}%` }
1368
+ }
1369
+ )), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mt-4 text-sm text-white/60" }, "\u9884\u52A0\u8F7D\u6240\u6709\u8D44\u6E90\u540E\uFF0C\u5207\u6362\u8282\u70B9\u5C06\u65E0\u9700\u7B49\u5F85"))), !isPreloading && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute bottom-4 right-4 z-10 flex gap-2" }, editableNodes.length > 1 && /* @__PURE__ */ React2__default.default.createElement(
1370
+ "button",
1371
+ {
1372
+ onClick: playlistPrevious,
1373
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-blue-500/90 text-xl text-white shadow-lg backdrop-blur-md transition-all hover:bg-blue-600 hover:scale-110",
1374
+ title: "\u4E0A\u4E00\u4E2A\u8282\u70B9"
1375
+ },
1376
+ "\u23EE\uFE0F"
1377
+ ), /* @__PURE__ */ React2__default.default.createElement(
1378
+ "button",
1379
+ {
1380
+ onClick: () => setShowSettings(true),
1381
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-purple-500/90 text-xl text-white shadow-lg backdrop-blur-md transition-all hover:bg-purple-600 hover:scale-110",
1382
+ title: "\u64AD\u653E\u5217\u8868\u8BBE\u7F6E"
1383
+ },
1384
+ "\u2699\uFE0F"
1385
+ ), editableNodes.length > 1 && /* @__PURE__ */ React2__default.default.createElement(
1386
+ "button",
1387
+ {
1388
+ onClick: playlistNext,
1389
+ className: "flex h-12 w-12 items-center justify-center rounded-full bg-blue-500/90 text-xl text-white shadow-lg backdrop-blur-md transition-all hover:bg-blue-600 hover:scale-110",
1390
+ title: "\u4E0B\u4E00\u4E2A\u8282\u70B9"
1391
+ },
1392
+ "\u23ED\uFE0F"
1393
+ )), !isPreloading && /* @__PURE__ */ React2__default.default.createElement("div", { className: "absolute left-4 top-4 z-10 rounded-lg bg-black/50 px-4 py-2 backdrop-blur-md" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm font-bold text-white/60" }, currentNodeIndex + 1, "/", editableNodes.length), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-sm font-medium text-white" }, currentNode.name), currentNode.loop && /* @__PURE__ */ React2__default.default.createElement("span", { className: "rounded bg-white/20 px-2 py-0.5 text-xs text-white" }, "\u{1F501}"))), showSettings && /* @__PURE__ */ React2__default.default.createElement(
1394
+ "div",
1395
+ {
1396
+ className: "absolute inset-0 z-[100] flex items-start justify-end bg-black/40",
1397
+ onClick: () => setShowSettings(false)
1398
+ },
1399
+ /* @__PURE__ */ React2__default.default.createElement(
1400
+ "div",
1401
+ {
1402
+ className: "relative m-4 flex w-full max-w-md flex-col overflow-hidden rounded-xl bg-gradient-to-br from-gray-900 to-black shadow-2xl border border-white/20",
1403
+ style: { maxHeight: "calc(100vh - 2rem)" },
1404
+ onClick: (e) => e.stopPropagation()
1405
+ },
1406
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center justify-between border-b border-white/10 bg-gradient-to-r from-purple-900/50 to-blue-900/50 px-4 py-3 flex-shrink-0" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "flex items-center gap-2 text-base font-bold text-white" }, "\u2699\uFE0F \u64AD\u653E\u5217\u8868\u914D\u7F6E"), /* @__PURE__ */ React2__default.default.createElement(
1407
+ "button",
1408
+ {
1409
+ onClick: () => setShowSettings(false),
1410
+ className: "text-xl text-white/60 transition-colors hover:text-white"
1411
+ },
1412
+ "\u2715"
1413
+ )),
1414
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex-1 overflow-y-auto p-4", style: { scrollbarWidth: "thin", scrollbarColor: "rgba(255,255,255,0.2) transparent" } }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "mb-3 rounded-lg bg-gradient-to-br from-indigo-900/30 to-purple-900/30 p-3 border border-white/10" }, /* @__PURE__ */ React2__default.default.createElement("h4", { className: "text-sm font-semibold text-white mb-2 flex items-center gap-2" }, "\u{1F4CB} \u64AD\u653E\u5217\u8868"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "space-y-1 text-xs" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white/60" }, "\u540D\u79F0\uFF1A"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white font-medium" }, playlist.name)), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white/60" }, "\u8282\u70B9\u6570\uFF1A"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white font-medium" }, editableNodes.length)), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white/60" }, "\u5FAA\u73AF\uFF1A"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white font-medium" }, playlist.loop ? "\u662F" : "\u5426")))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "mb-3 rounded-lg bg-gradient-to-br from-blue-900/30 to-cyan-900/30 p-3 border border-white/10" }, /* @__PURE__ */ React2__default.default.createElement("h4", { className: "text-sm font-semibold text-white mb-2 flex items-center gap-2" }, "\u{1F3AF} \u5F53\u524D\u8282\u70B9"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "space-y-1 text-xs" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white/60" }, "\u540D\u79F0\uFF1A"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white font-medium truncate ml-2" }, currentNode.name)), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex justify-between" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white/60" }, "\u4F4D\u7F6E\uFF1A"), /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-white font-medium" }, currentNodeIndex + 1, " / ", editableNodes.length)), currentNode.resources.audioPath && /* @__PURE__ */ React2__default.default.createElement("div", { className: "text-white/80 mt-1" }, "\u{1F3B5} \u6709\u97F3\u4E50"), currentNode.resources.cameraPath && /* @__PURE__ */ React2__default.default.createElement("div", { className: "text-white/80" }, "\u{1F4F7} \u6709\u76F8\u673A"))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "rounded-lg bg-gradient-to-br from-gray-800/50 to-gray-900/50 border border-white/10 p-3" }, /* @__PURE__ */ React2__default.default.createElement("h4", { className: "mb-2 flex items-center gap-2 text-sm font-semibold text-white" }, "\u{1F4DD} \u8282\u70B9\u7BA1\u7406"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "max-h-64 space-y-2 overflow-y-auto pr-1", style: { scrollbarWidth: "thin", scrollbarColor: "rgba(255,255,255,0.2) transparent" } }, editableNodes.map((node, index) => /* @__PURE__ */ React2__default.default.createElement(
1415
+ "div",
1416
+ {
1417
+ key: `${node.id}-${index}`,
1418
+ className: `rounded-md p-2 transition-all text-xs ${currentNodeIndex === index ? "bg-gradient-to-r from-purple-600/50 to-blue-600/50 border border-purple-400/50" : "bg-white/5 hover:bg-white/10 border border-white/10"}`
1419
+ },
1420
+ /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-start justify-between gap-2" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-1 mb-1" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "text-xs font-bold text-white/40" }, "#", index + 1), /* @__PURE__ */ React2__default.default.createElement("h5", { className: "font-semibold text-white text-xs truncate" }, node.name), currentNodeIndex === index && /* @__PURE__ */ React2__default.default.createElement("span", { className: "rounded bg-green-500/30 px-1 py-0.5 text-[10px] text-green-300 flex-shrink-0" }, "\u25B6\uFE0F")), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-wrap gap-1 text-[10px] text-white/60" }, node.resources.modelPath && /* @__PURE__ */ React2__default.default.createElement("span", null, "\u{1F464}"), node.resources.motionPath && /* @__PURE__ */ React2__default.default.createElement("span", null, "\u{1F483}"), node.resources.audioPath && /* @__PURE__ */ React2__default.default.createElement("span", null, "\u{1F3B5}"), node.resources.cameraPath && /* @__PURE__ */ React2__default.default.createElement("span", null, "\u{1F4F7}"))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-col gap-0.5 flex-shrink-0" }, index > 0 && /* @__PURE__ */ React2__default.default.createElement(
1421
+ "button",
1422
+ {
1423
+ onClick: () => handleMoveNodeUp(index),
1424
+ className: "p-0.5 rounded bg-white/10 hover:bg-white/20 text-white text-[10px] transition-colors",
1425
+ title: "\u4E0A\u79FB"
1426
+ },
1427
+ "\u2B06\uFE0F"
1428
+ ), index < editableNodes.length - 1 && /* @__PURE__ */ React2__default.default.createElement(
1429
+ "button",
1430
+ {
1431
+ onClick: () => handleMoveNodeDown(index),
1432
+ className: "p-0.5 rounded bg-white/10 hover:bg-white/20 text-white text-[10px] transition-colors",
1433
+ title: "\u4E0B\u79FB"
1434
+ },
1435
+ "\u2B07\uFE0F"
1436
+ ), /* @__PURE__ */ React2__default.default.createElement(
1437
+ "button",
1438
+ {
1439
+ onClick: () => playlistJumpTo(index),
1440
+ className: "p-0.5 rounded bg-blue-500/30 hover:bg-blue-500/50 text-white text-[10px] transition-colors",
1441
+ title: "\u8DF3\u8F6C"
1442
+ },
1443
+ "\u25B6\uFE0F"
1444
+ ), /* @__PURE__ */ React2__default.default.createElement(
1445
+ "button",
1446
+ {
1447
+ onClick: () => {
1448
+ if (confirm(`\u786E\u5B9A\u5220\u9664 "${node.name}"\uFF1F`)) {
1449
+ handleDeleteNode(index);
1450
+ }
1451
+ },
1452
+ className: "p-0.5 rounded bg-red-500/30 hover:bg-red-500/50 text-white text-[10px] transition-colors",
1453
+ title: "\u5220\u9664"
1454
+ },
1455
+ "\u{1F5D1}\uFE0F"
1456
+ )))
1457
+ )))))
1458
+ )
1459
+ ));
1460
+ };
1461
+
1462
+ // src/mmd/presets.ts
1463
+ var defaultMMDPreset = {
1464
+ id: "default",
1465
+ name: "\u9ED8\u8BA4\u6A21\u578B",
1466
+ summary: "\u4EC5\u5C55\u793A\u6A21\u578B\uFF0C\u65E0\u52A8\u4F5C\u548C\u97F3\u9891",
1467
+ badges: ["\u6A21\u578B", "\u9759\u6001"],
1468
+ resources: {
1469
+ modelPath: "/mikutalking/models/YYB_Z6SakuraMiku/miku.pmx"
1470
+ },
1471
+ stage: {
1472
+ backgroundColor: "#000000",
1473
+ cameraPosition: { x: 0, y: 10, z: 30 },
1474
+ cameraTarget: { x: 0, y: 10, z: 0 },
1475
+ enablePhysics: true,
1476
+ showGrid: true,
1477
+ ammoPath: "/mikutalking/libs/ammo.wasm.js",
1478
+ ammoWasmPath: "/mikutalking/libs/"
1479
+ }
1480
+ };
1481
+ var catchTheWavePreset = {
1482
+ id: "catch-the-wave",
1483
+ name: "Catch The Wave",
1484
+ summary: "\u5B8C\u6574\u7684MMD\u8868\u6F14\uFF1A\u6A21\u578B\u3001\u52A8\u4F5C\u3001\u76F8\u673A\u8FD0\u955C\u3001\u97F3\u9891\u540C\u6B65",
1485
+ badges: ["\u6A21\u578B", "\u52A8\u4F5C", "\u76F8\u673A", "\u97F3\u9891"],
1486
+ resources: {
1487
+ modelPath: "/mikutalking/models/YYB_Z6SakuraMiku/miku.pmx",
1488
+ motionPath: "/mikutalking/actions/CatchTheWave/mmd_CatchTheWave_motion.vmd",
1489
+ cameraPath: "/mikutalking/actions/CatchTheWave/camera.vmd",
1490
+ audioPath: "/mikutalking/actions/CatchTheWave/pv_268.wav"
1491
+ },
1492
+ stage: {
1493
+ backgroundColor: "#01030b",
1494
+ cameraPosition: { x: 0, y: 10, z: 30 },
1495
+ cameraTarget: { x: 0, y: 10, z: 0 },
1496
+ enablePhysics: true,
1497
+ showGrid: false,
1498
+ ammoPath: "/mikutalking/libs/ammo.wasm.js",
1499
+ ammoWasmPath: "/mikutalking/libs/"
1500
+ }
1501
+ };
1502
+ var simpleModelPreset = {
1503
+ id: "simple-model",
1504
+ name: "\u7B80\u5355\u6A21\u578B",
1505
+ summary: "\u8F7B\u91CF\u7EA7\u6D4B\u8BD5\u6A21\u578B",
1506
+ badges: ["\u6A21\u578B", "\u8F7B\u91CF"],
1507
+ resources: {
1508
+ modelPath: "/mikutalking/models/test/v4c5.0.pmx"
1509
+ },
1510
+ stage: {
1511
+ backgroundColor: "#ffffff",
1512
+ cameraPosition: { x: 0, y: 10, z: 30 },
1513
+ cameraTarget: { x: 0, y: 10, z: 0 },
1514
+ enablePhysics: true,
1515
+ showGrid: true,
1516
+ ammoPath: "/mikutalking/libs/ammo.wasm.js",
1517
+ ammoWasmPath: "/mikutalking/libs/"
1518
+ }
1519
+ };
1520
+ var availableMMDPresets = [
1521
+ catchTheWavePreset,
1522
+ defaultMMDPreset,
1523
+ simpleModelPreset
1524
+ ];
1525
+
1526
+ exports.MMDPlayerBase = MMDPlayerBase;
1527
+ exports.MMDPlayerEnhanced = MMDPlayerEnhanced;
1528
+ exports.MMDPlaylist = MMDPlaylist;
1529
+ exports.availableMMDPresets = availableMMDPresets;
1530
+ exports.catchTheWavePreset = catchTheWavePreset;
1531
+ exports.defaultMMDPreset = defaultMMDPreset;
1532
+ exports.loadAmmo = loadAmmo;
1533
+ exports.simpleModelPreset = simpleModelPreset;
1534
+ //# sourceMappingURL=index.js.map
1535
+ //# sourceMappingURL=index.js.map