sa2kit 1.4.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ConfigService-7MEZXKJ5.js +21 -0
- package/dist/ConfigService-7MEZXKJ5.js.map +1 -0
- package/dist/ConfigService-BV57YYFW.mjs +4 -0
- package/dist/ConfigService-BV57YYFW.mjs.map +1 -0
- package/dist/ConfigService-BxK06xP6.d.mts +262 -0
- package/dist/ConfigService-BxK06xP6.d.ts +262 -0
- package/dist/audioDetection/index.d.mts +449 -0
- package/dist/audioDetection/index.d.ts +449 -0
- package/dist/audioDetection/index.js +1244 -0
- package/dist/audioDetection/index.js.map +1 -0
- package/dist/audioDetection/index.mjs +1227 -0
- package/dist/audioDetection/index.mjs.map +1 -0
- package/dist/chunk-5XUE72Y3.mjs +1001 -0
- package/dist/chunk-5XUE72Y3.mjs.map +1 -0
- package/dist/chunk-DQVPZTVC.js +1009 -0
- package/dist/chunk-DQVPZTVC.js.map +1 -0
- package/dist/chunk-NEPD75MX.mjs +467 -0
- package/dist/chunk-NEPD75MX.mjs.map +1 -0
- package/dist/chunk-OEDY7GI4.js +473 -0
- package/dist/chunk-OEDY7GI4.js.map +1 -0
- package/dist/chunk-TFQF2HDO.mjs +354 -0
- package/dist/chunk-TFQF2HDO.mjs.map +1 -0
- package/dist/chunk-TOC5FSHP.js +358 -0
- package/dist/chunk-TOC5FSHP.js.map +1 -0
- package/dist/imageCrop/index.d.mts +165 -0
- package/dist/imageCrop/index.d.ts +165 -0
- package/dist/imageCrop/index.js +559 -0
- package/dist/imageCrop/index.js.map +1 -0
- package/dist/imageCrop/index.mjs +540 -0
- package/dist/imageCrop/index.mjs.map +1 -0
- package/dist/index.d.mts +139 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +670 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +662 -0
- package/dist/index.mjs.map +1 -1
- package/dist/mmd/index.d.mts +113 -2
- package/dist/mmd/index.d.ts +113 -2
- package/dist/mmd/index.js +484 -2
- package/dist/mmd/index.js.map +1 -1
- package/dist/mmd/index.mjs +482 -4
- package/dist/mmd/index.mjs.map +1 -1
- package/dist/testYourself/admin/index.d.mts +58 -0
- package/dist/testYourself/admin/index.d.ts +58 -0
- package/dist/testYourself/admin/index.js +17 -0
- package/dist/testYourself/admin/index.js.map +1 -0
- package/dist/testYourself/admin/index.mjs +4 -0
- package/dist/testYourself/admin/index.mjs.map +1 -0
- package/dist/testYourself/index.d.mts +6 -98
- package/dist/testYourself/index.d.ts +6 -98
- package/dist/testYourself/index.js +90 -334
- package/dist/testYourself/index.js.map +1 -1
- package/dist/testYourself/index.mjs +47 -333
- package/dist/testYourself/index.mjs.map +1 -1
- package/dist/testYourself/server/index.d.mts +1029 -0
- package/dist/testYourself/server/index.d.ts +1029 -0
- package/dist/testYourself/server/index.js +42 -0
- package/dist/testYourself/server/index.js.map +1 -0
- package/dist/testYourself/server/index.mjs +5 -0
- package/dist/testYourself/server/index.mjs.map +1 -0
- package/dist/universalFile/server/index.js +5 -5
- package/dist/universalFile/server/index.mjs +1 -1
- package/package.json +62 -20
package/dist/mmd/index.js
CHANGED
|
@@ -72,6 +72,9 @@ var loadAmmo = (path = "/libs/ammo.wasm.js") => {
|
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
// src/mmd/components/MMDPlayerBase.tsx
|
|
75
|
+
if (typeof window !== "undefined") {
|
|
76
|
+
THREE__namespace.Cache.enabled = true;
|
|
77
|
+
}
|
|
75
78
|
async function waitForMaterialsReady(object, renderer, scene, camera) {
|
|
76
79
|
const textures = [];
|
|
77
80
|
let meshCount = 0;
|
|
@@ -2597,6 +2600,61 @@ var LoadingOverlay = ({
|
|
|
2597
2600
|
));
|
|
2598
2601
|
};
|
|
2599
2602
|
LoadingOverlay.displayName = "LoadingOverlay";
|
|
2603
|
+
var SkipConfirmDialog = ({
|
|
2604
|
+
onConfirm,
|
|
2605
|
+
onCancel
|
|
2606
|
+
}) => {
|
|
2607
|
+
const [isMounted, setIsMounted] = React6__default.default.useState(false);
|
|
2608
|
+
React6__default.default.useEffect(() => {
|
|
2609
|
+
setIsMounted(true);
|
|
2610
|
+
}, []);
|
|
2611
|
+
if (!isMounted) return null;
|
|
2612
|
+
const content = /* @__PURE__ */ React6__default.default.createElement(
|
|
2613
|
+
"div",
|
|
2614
|
+
{
|
|
2615
|
+
className: "fixed inset-0 flex items-center justify-center bg-black/40 backdrop-blur-sm pointer-events-auto",
|
|
2616
|
+
style: { zIndex: 999999 }
|
|
2617
|
+
},
|
|
2618
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
2619
|
+
"div",
|
|
2620
|
+
{
|
|
2621
|
+
className: "p-8 rounded-3xl border border-white/30 shadow-2xl max-w-sm w-full mx-4 overflow-hidden relative",
|
|
2622
|
+
style: {
|
|
2623
|
+
background: `linear-gradient(135deg,
|
|
2624
|
+
rgba(255, 255, 255, 0.2) 0%,
|
|
2625
|
+
rgba(255, 255, 255, 0.1) 100%)`,
|
|
2626
|
+
backdropFilter: "blur(32px) saturate(200%)",
|
|
2627
|
+
WebkitBackdropFilter: "blur(32px) saturate(200%)"
|
|
2628
|
+
}
|
|
2629
|
+
},
|
|
2630
|
+
/* @__PURE__ */ React6__default.default.createElement("h3", { className: "text-xl font-bold text-white mb-4 drop-shadow-md" }, "\u52A8\u753B\u5C1A\u672A\u64AD\u653E\u5B8C\u6210"),
|
|
2631
|
+
/* @__PURE__ */ React6__default.default.createElement("p", { className: "text-white/90 mb-8 leading-relaxed drop-shadow-sm" }, "\u5F53\u524D\u573A\u666F\u7684\u52A8\u753B\u8FD8\u6CA1\u6709\u5B8C\u6574\u64AD\u653E\u4E00\u904D\uFF0C\u662F\u5426\u76F4\u63A5\u8DF3\u8F6C\u5230\u4E0B\u4E00\u4E2A\u573A\u666F\uFF1F"),
|
|
2632
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "flex justify-end gap-4" }, /* @__PURE__ */ React6__default.default.createElement(
|
|
2633
|
+
"button",
|
|
2634
|
+
{
|
|
2635
|
+
onClick: onCancel,
|
|
2636
|
+
className: "px-6 py-2.5 rounded-2xl text-white/80 font-medium hover:text-white hover:bg-white/10 transition-all border border-white/10 hover:border-white/30"
|
|
2637
|
+
},
|
|
2638
|
+
"\u53D6\u6D88"
|
|
2639
|
+
), /* @__PURE__ */ React6__default.default.createElement(
|
|
2640
|
+
"button",
|
|
2641
|
+
{
|
|
2642
|
+
onClick: onConfirm,
|
|
2643
|
+
className: "px-6 py-2.5 rounded-2xl bg-white/20 hover:bg-white/30 text-white font-bold transition-all border border-white/40 shadow-lg hover:scale-105 active:scale-95"
|
|
2644
|
+
},
|
|
2645
|
+
"\u76F4\u63A5\u8DF3\u8F6C"
|
|
2646
|
+
))
|
|
2647
|
+
)
|
|
2648
|
+
);
|
|
2649
|
+
let portalContainer = document.getElementById("dialogue-portal-root");
|
|
2650
|
+
if (!portalContainer) {
|
|
2651
|
+
portalContainer = document.createElement("div");
|
|
2652
|
+
portalContainer.id = "dialogue-portal-root";
|
|
2653
|
+
portalContainer.style.cssText = "position: fixed; inset: 0; pointer-events: none; z-index: 999999;";
|
|
2654
|
+
document.body.appendChild(portalContainer);
|
|
2655
|
+
}
|
|
2656
|
+
return reactDom.createPortal(content, portalContainer);
|
|
2657
|
+
};
|
|
2600
2658
|
|
|
2601
2659
|
// src/mmd/visual-novel/MMDVisualNovel.tsx
|
|
2602
2660
|
var MMDVisualNovel = React6.forwardRef(
|
|
@@ -2630,11 +2688,14 @@ var MMDVisualNovel = React6.forwardRef(
|
|
|
2630
2688
|
const [showHistory, setShowHistory] = React6.useState(false);
|
|
2631
2689
|
const [history, setHistory] = React6.useState([]);
|
|
2632
2690
|
const [isStarted, setIsStarted] = React6.useState(autoStart);
|
|
2691
|
+
const [isVmdFinished, setIsVmdFinished] = React6.useState(false);
|
|
2692
|
+
const [pendingNodeIndex, setPendingNodeIndex] = React6.useState(null);
|
|
2633
2693
|
const playerRef = React6.useRef(null);
|
|
2634
2694
|
const containerRef = React6.useRef(null);
|
|
2635
2695
|
const autoTimerRef = React6.useRef(null);
|
|
2636
2696
|
const typingCompleteRef = React6.useRef(false);
|
|
2637
2697
|
const isStartedRef = React6.useRef(autoStart);
|
|
2698
|
+
const lastAnimationTimeRef = React6.useRef(0);
|
|
2638
2699
|
const currentNode = nodes[currentNodeIndex];
|
|
2639
2700
|
const currentDialogue = currentNode?.dialogues[currentDialogueIndex] || null;
|
|
2640
2701
|
const addToHistory = React6.useCallback((dialogue, nodeIndex, dialogueIndex) => {
|
|
@@ -2674,15 +2735,24 @@ var MMDVisualNovel = React6.forwardRef(
|
|
|
2674
2735
|
}
|
|
2675
2736
|
}, [currentNode, currentDialogueIndex, currentNodeIndex, nodes.length, loop, addToHistory, onDialogueChange, onScriptComplete]);
|
|
2676
2737
|
const goToNode = React6.useCallback(
|
|
2677
|
-
(nodeIndex) => {
|
|
2738
|
+
(nodeIndex, force = false) => {
|
|
2678
2739
|
if (nodeIndex < 0 || nodeIndex >= nodes.length) return;
|
|
2679
2740
|
if (isTransitioning) return;
|
|
2680
2741
|
const node = nodes[nodeIndex];
|
|
2681
2742
|
if (!node) return;
|
|
2743
|
+
const currentResources = nodes[currentNodeIndex]?.resources;
|
|
2744
|
+
if (!force && currentResources?.motionPath && !isVmdFinished) {
|
|
2745
|
+
console.log("[MMDVisualNovel] VMD not finished, showing confirmation");
|
|
2746
|
+
setPendingNodeIndex(nodeIndex);
|
|
2747
|
+
return;
|
|
2748
|
+
}
|
|
2682
2749
|
console.log(`[MMDVisualNovel] Transitioning to node ${nodeIndex}`);
|
|
2683
2750
|
setIsTransitioning(true);
|
|
2684
2751
|
setIsLoading(true);
|
|
2685
2752
|
setIsAnimationPlaying(false);
|
|
2753
|
+
setIsVmdFinished(false);
|
|
2754
|
+
setPendingNodeIndex(null);
|
|
2755
|
+
lastAnimationTimeRef.current = 0;
|
|
2686
2756
|
setTimeout(() => {
|
|
2687
2757
|
setCurrentNodeIndex(nodeIndex);
|
|
2688
2758
|
setCurrentDialogueIndex(0);
|
|
@@ -2700,7 +2770,7 @@ var MMDVisualNovel = React6.forwardRef(
|
|
|
2700
2770
|
}, 100);
|
|
2701
2771
|
}, 300);
|
|
2702
2772
|
},
|
|
2703
|
-
[nodes, isTransitioning, addToHistory, onNodeChange, onDialogueChange]
|
|
2773
|
+
[nodes, isTransitioning, addToHistory, onNodeChange, onDialogueChange, currentNodeIndex, isVmdFinished]
|
|
2704
2774
|
);
|
|
2705
2775
|
const goToDialogue = React6.useCallback(
|
|
2706
2776
|
(dialogueIndex) => {
|
|
@@ -2840,6 +2910,19 @@ var MMDVisualNovel = React6.forwardRef(
|
|
|
2840
2910
|
console.log("[MMDVisualNovel] MMDPlayerBase onPlay called");
|
|
2841
2911
|
setIsAnimationPlaying(true);
|
|
2842
2912
|
},
|
|
2913
|
+
onTimeUpdate: (time) => {
|
|
2914
|
+
if (time < lastAnimationTimeRef.current && lastAnimationTimeRef.current > 0) {
|
|
2915
|
+
if (!isVmdFinished) {
|
|
2916
|
+
console.log("[MMDVisualNovel] VMD loop detected, marking as finished");
|
|
2917
|
+
setIsVmdFinished(true);
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
lastAnimationTimeRef.current = time;
|
|
2921
|
+
},
|
|
2922
|
+
onEnded: () => {
|
|
2923
|
+
console.log("[MMDVisualNovel] VMD ended, marking as finished");
|
|
2924
|
+
setIsVmdFinished(true);
|
|
2925
|
+
},
|
|
2843
2926
|
onError
|
|
2844
2927
|
}
|
|
2845
2928
|
)
|
|
@@ -2896,6 +2979,19 @@ var MMDVisualNovel = React6.forwardRef(
|
|
|
2896
2979
|
}
|
|
2897
2980
|
) : null;
|
|
2898
2981
|
})(),
|
|
2982
|
+
pendingNodeIndex !== null && /* @__PURE__ */ React6__default.default.createElement(
|
|
2983
|
+
SkipConfirmDialog,
|
|
2984
|
+
{
|
|
2985
|
+
onConfirm: () => {
|
|
2986
|
+
if (pendingNodeIndex !== null) {
|
|
2987
|
+
goToNode(pendingNodeIndex, true);
|
|
2988
|
+
}
|
|
2989
|
+
},
|
|
2990
|
+
onCancel: () => {
|
|
2991
|
+
setPendingNodeIndex(null);
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
),
|
|
2899
2995
|
showHistory && /* @__PURE__ */ React6__default.default.createElement(
|
|
2900
2996
|
HistoryPanel,
|
|
2901
2997
|
{
|
|
@@ -2908,18 +3004,404 @@ var MMDVisualNovel = React6.forwardRef(
|
|
|
2908
3004
|
}
|
|
2909
3005
|
);
|
|
2910
3006
|
MMDVisualNovel.displayName = "MMDVisualNovel";
|
|
3007
|
+
var MusicControls = ({
|
|
3008
|
+
isPlaying,
|
|
3009
|
+
currentTime,
|
|
3010
|
+
duration,
|
|
3011
|
+
loopMode,
|
|
3012
|
+
onPlayPause,
|
|
3013
|
+
onNext,
|
|
3014
|
+
onPrevious,
|
|
3015
|
+
onSeek,
|
|
3016
|
+
onToggleLoop,
|
|
3017
|
+
onTogglePlaylist,
|
|
3018
|
+
className = ""
|
|
3019
|
+
}) => {
|
|
3020
|
+
const formatTime = (seconds) => {
|
|
3021
|
+
const mins = Math.floor(seconds / 60);
|
|
3022
|
+
const secs = Math.floor(seconds % 60);
|
|
3023
|
+
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
3024
|
+
};
|
|
3025
|
+
const progress = duration > 0 ? currentTime / duration * 100 : 0;
|
|
3026
|
+
return /* @__PURE__ */ React6__default.default.createElement(
|
|
3027
|
+
"div",
|
|
3028
|
+
{
|
|
3029
|
+
className: `w-full max-w-4xl mx-auto px-6 py-4 bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl shadow-2xl pointer-events-auto transition-all group ${className}`
|
|
3030
|
+
},
|
|
3031
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "relative w-full h-1.5 bg-white/20 rounded-full mb-4 cursor-pointer group/progress overflow-hidden" }, /* @__PURE__ */ React6__default.default.createElement(
|
|
3032
|
+
"div",
|
|
3033
|
+
{
|
|
3034
|
+
className: "absolute h-full bg-blue-500 rounded-full transition-all duration-300",
|
|
3035
|
+
style: { width: `${progress}%` }
|
|
3036
|
+
}
|
|
3037
|
+
), /* @__PURE__ */ React6__default.default.createElement(
|
|
3038
|
+
"input",
|
|
3039
|
+
{
|
|
3040
|
+
type: "range",
|
|
3041
|
+
min: 0,
|
|
3042
|
+
max: duration || 100,
|
|
3043
|
+
value: currentTime,
|
|
3044
|
+
onChange: (e) => onSeek(Number(e.target.value)),
|
|
3045
|
+
className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer"
|
|
3046
|
+
}
|
|
3047
|
+
)),
|
|
3048
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex items-center gap-2 text-xs font-mono text-white/60 w-32" }, /* @__PURE__ */ React6__default.default.createElement("span", null, formatTime(currentTime)), /* @__PURE__ */ React6__default.default.createElement("span", null, "/"), /* @__PURE__ */ React6__default.default.createElement("span", null, formatTime(duration))), /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex items-center gap-6" }, /* @__PURE__ */ React6__default.default.createElement(
|
|
3049
|
+
"button",
|
|
3050
|
+
{
|
|
3051
|
+
onClick: onPrevious,
|
|
3052
|
+
className: "text-white/80 hover:text-white transition-colors"
|
|
3053
|
+
},
|
|
3054
|
+
/* @__PURE__ */ React6__default.default.createElement(lucideReact.SkipBack, { className: "w-6 h-6 fill-current" })
|
|
3055
|
+
), /* @__PURE__ */ React6__default.default.createElement(
|
|
3056
|
+
"button",
|
|
3057
|
+
{
|
|
3058
|
+
onClick: onPlayPause,
|
|
3059
|
+
className: "w-12 h-12 flex items-center justify-center bg-blue-500 hover:bg-blue-400 text-white rounded-full shadow-lg shadow-blue-500/20 transition-all hover:scale-105 active:scale-95"
|
|
3060
|
+
},
|
|
3061
|
+
isPlaying ? /* @__PURE__ */ React6__default.default.createElement(lucideReact.Pause, { className: "w-6 h-6 fill-current" }) : /* @__PURE__ */ React6__default.default.createElement(lucideReact.Play, { className: "w-6 h-6 fill-current ml-1" })
|
|
3062
|
+
), /* @__PURE__ */ React6__default.default.createElement(
|
|
3063
|
+
"button",
|
|
3064
|
+
{
|
|
3065
|
+
onClick: onNext,
|
|
3066
|
+
className: "text-white/80 hover:text-white transition-colors"
|
|
3067
|
+
},
|
|
3068
|
+
/* @__PURE__ */ React6__default.default.createElement(lucideReact.SkipForward, { className: "w-6 h-6 fill-current" })
|
|
3069
|
+
)), /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex items-center gap-4 w-32 justify-end" }, /* @__PURE__ */ React6__default.default.createElement(
|
|
3070
|
+
"button",
|
|
3071
|
+
{
|
|
3072
|
+
onClick: onToggleLoop,
|
|
3073
|
+
className: "text-white/60 hover:text-white transition-colors",
|
|
3074
|
+
title: loopMode
|
|
3075
|
+
},
|
|
3076
|
+
loopMode === "list" && /* @__PURE__ */ React6__default.default.createElement(lucideReact.Repeat, { className: "w-5 h-5" }),
|
|
3077
|
+
loopMode === "single" && /* @__PURE__ */ React6__default.default.createElement(lucideReact.Repeat1, { className: "w-5 h-5 text-blue-400" }),
|
|
3078
|
+
loopMode === "shuffle" && /* @__PURE__ */ React6__default.default.createElement(lucideReact.Shuffle, { className: "w-5 h-5 text-orange-400" })
|
|
3079
|
+
), /* @__PURE__ */ React6__default.default.createElement(
|
|
3080
|
+
"button",
|
|
3081
|
+
{
|
|
3082
|
+
onClick: onTogglePlaylist,
|
|
3083
|
+
className: "text-white/60 hover:text-white transition-colors"
|
|
3084
|
+
},
|
|
3085
|
+
/* @__PURE__ */ React6__default.default.createElement(lucideReact.ListMusic, { className: "w-5 h-5" })
|
|
3086
|
+
)))
|
|
3087
|
+
);
|
|
3088
|
+
};
|
|
3089
|
+
var PlaylistPanel = ({
|
|
3090
|
+
tracks,
|
|
3091
|
+
currentIndex,
|
|
3092
|
+
isOpen,
|
|
3093
|
+
onClose,
|
|
3094
|
+
onSelectTrack,
|
|
3095
|
+
className = ""
|
|
3096
|
+
}) => {
|
|
3097
|
+
if (!isOpen) return null;
|
|
3098
|
+
return /* @__PURE__ */ React6__default.default.createElement(
|
|
3099
|
+
"div",
|
|
3100
|
+
{
|
|
3101
|
+
className: `fixed inset-y-0 right-0 w-80 bg-gray-900/90 backdrop-blur-2xl border-l border-white/10 shadow-2xl z-50 flex flex-col pointer-events-auto transform transition-transform duration-500 ease-out ${isOpen ? "translate-x-0" : "translate-x-full"} ${className}`
|
|
3102
|
+
},
|
|
3103
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "flex items-center justify-between p-6 border-b border-white/10" }, /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ React6__default.default.createElement(lucideReact.Music, { className: "w-5 h-5 text-blue-400" }), /* @__PURE__ */ React6__default.default.createElement("h3", { className: "text-lg font-bold text-white" }, "\u64AD\u653E\u5217\u8868")), /* @__PURE__ */ React6__default.default.createElement(
|
|
3104
|
+
"button",
|
|
3105
|
+
{
|
|
3106
|
+
onClick: onClose,
|
|
3107
|
+
className: "p-2 text-white/60 hover:text-white transition-colors"
|
|
3108
|
+
},
|
|
3109
|
+
/* @__PURE__ */ React6__default.default.createElement(lucideReact.X, { className: "w-5 h-5" })
|
|
3110
|
+
)),
|
|
3111
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "flex-1 overflow-y-auto p-4 space-y-2 custom-scrollbar" }, tracks.map((track, index) => {
|
|
3112
|
+
const isActive = index === currentIndex;
|
|
3113
|
+
return /* @__PURE__ */ React6__default.default.createElement(
|
|
3114
|
+
"button",
|
|
3115
|
+
{
|
|
3116
|
+
key: track.id,
|
|
3117
|
+
onClick: () => onSelectTrack(index),
|
|
3118
|
+
className: `w-full flex items-center gap-4 p-3 rounded-xl transition-all group ${isActive ? "bg-blue-500/20 border border-blue-500/30" : "hover:bg-white/5 border border-transparent"}`
|
|
3119
|
+
},
|
|
3120
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "relative w-12 h-12 flex-shrink-0 rounded-lg overflow-hidden bg-gray-800" }, track.coverUrl ? /* @__PURE__ */ React6__default.default.createElement("img", { src: track.coverUrl, alt: track.title, className: "w-full h-full object-cover" }) : /* @__PURE__ */ React6__default.default.createElement("div", { className: "w-full h-full flex items-center justify-center text-white/20" }, /* @__PURE__ */ React6__default.default.createElement(lucideReact.Music, { className: "w-6 h-6" })), isActive && /* @__PURE__ */ React6__default.default.createElement("div", { className: "absolute inset-0 bg-blue-500/40 flex items-center justify-center" }, /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex gap-1 items-end h-4" }, /* @__PURE__ */ React6__default.default.createElement("div", { className: "w-1 bg-white animate-music-bar-1" }), /* @__PURE__ */ React6__default.default.createElement("div", { className: "w-1 bg-white animate-music-bar-2" }), /* @__PURE__ */ React6__default.default.createElement("div", { className: "w-1 bg-white animate-music-bar-3" })))),
|
|
3121
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "flex-1 text-left min-w-0" }, /* @__PURE__ */ React6__default.default.createElement("h4", { className: `text-sm font-bold truncate ${isActive ? "text-blue-400" : "text-white/90"}` }, track.title), /* @__PURE__ */ React6__default.default.createElement("p", { className: "text-xs text-white/40 truncate mt-0.5" }, track.artist || "\u672A\u77E5\u827A\u672F\u5BB6")),
|
|
3122
|
+
!isActive && /* @__PURE__ */ React6__default.default.createElement("div", { className: "opacity-0 group-hover:opacity-100 transition-opacity" }, /* @__PURE__ */ React6__default.default.createElement(lucideReact.Play, { className: "w-4 h-4 text-white/40 fill-current" }))
|
|
3123
|
+
);
|
|
3124
|
+
})),
|
|
3125
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "p-6 border-t border-white/10" }, /* @__PURE__ */ React6__default.default.createElement("p", { className: "text-xs text-gray-500 text-center" }, "\u5171 ", tracks.length, " \u9996\u66F2\u76EE")),
|
|
3126
|
+
/* @__PURE__ */ React6__default.default.createElement("style", { dangerouslySetInnerHTML: { __html: `
|
|
3127
|
+
.custom-scrollbar::-webkit-scrollbar {
|
|
3128
|
+
width: 4px;
|
|
3129
|
+
}
|
|
3130
|
+
.custom-scrollbar::-webkit-scrollbar-track {
|
|
3131
|
+
background: transparent;
|
|
3132
|
+
}
|
|
3133
|
+
.custom-scrollbar::-webkit-scrollbar-thumb {
|
|
3134
|
+
background: rgba(255, 255, 255, 0.1);
|
|
3135
|
+
border-radius: 10px;
|
|
3136
|
+
}
|
|
3137
|
+
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
3138
|
+
background: rgba(255, 255, 255, 0.2);
|
|
3139
|
+
}
|
|
3140
|
+
@keyframes music-bar-1 {
|
|
3141
|
+
0%, 100% { height: 4px; }
|
|
3142
|
+
50% { height: 12px; }
|
|
3143
|
+
}
|
|
3144
|
+
@keyframes music-bar-2 {
|
|
3145
|
+
0%, 100% { height: 8px; }
|
|
3146
|
+
50% { height: 16px; }
|
|
3147
|
+
}
|
|
3148
|
+
@keyframes music-bar-3 {
|
|
3149
|
+
0%, 100% { height: 6px; }
|
|
3150
|
+
50% { height: 14px; }
|
|
3151
|
+
}
|
|
3152
|
+
.animate-music-bar-1 { animation: music-bar-1 0.6s infinite; }
|
|
3153
|
+
.animate-music-bar-2 { animation: music-bar-2 0.8s infinite; }
|
|
3154
|
+
.animate-music-bar-3 { animation: music-bar-3 0.7s infinite; }
|
|
3155
|
+
` } })
|
|
3156
|
+
);
|
|
3157
|
+
};
|
|
3158
|
+
var TrackInfo = ({ track, className = "" }) => {
|
|
3159
|
+
return /* @__PURE__ */ React6__default.default.createElement("div", { className: `flex flex-col items-center text-center gap-2 ${className}` }, /* @__PURE__ */ React6__default.default.createElement("div", { className: "px-4 py-1.5 bg-black/40 backdrop-blur-md rounded-full border border-white/10 shadow-lg" }, /* @__PURE__ */ React6__default.default.createElement("h2", { className: "text-lg font-bold text-white tracking-wider truncate max-w-md" }, track.title)), /* @__PURE__ */ React6__default.default.createElement("p", { className: "text-sm font-medium text-white/60 drop-shadow-md" }, track.artist || "\u672A\u77E5\u827A\u672F\u5BB6"));
|
|
3160
|
+
};
|
|
3161
|
+
|
|
3162
|
+
// src/mmd/music-player/MMDMusicPlayer.tsx
|
|
3163
|
+
var MMDMusicPlayer = React6.forwardRef(
|
|
3164
|
+
({
|
|
3165
|
+
config,
|
|
3166
|
+
stage,
|
|
3167
|
+
mobileOptimization,
|
|
3168
|
+
initialTrackIndex = 0,
|
|
3169
|
+
onTrackChange,
|
|
3170
|
+
onPlayPause,
|
|
3171
|
+
onProgress,
|
|
3172
|
+
onError,
|
|
3173
|
+
className,
|
|
3174
|
+
style
|
|
3175
|
+
}, ref) => {
|
|
3176
|
+
const { tracks, autoPlay = false, defaultLoopMode = "list" } = config;
|
|
3177
|
+
const [currentIndex, setCurrentIndex] = React6.useState(initialTrackIndex);
|
|
3178
|
+
const [isPlaying, setIsPlaying] = React6.useState(autoPlay);
|
|
3179
|
+
const [isLoading, setIsLoading] = React6.useState(true);
|
|
3180
|
+
const [isTransitioning, setIsTransitioning] = React6.useState(false);
|
|
3181
|
+
const [currentTime, setCurrentTime] = React6.useState(0);
|
|
3182
|
+
const [duration, setDuration] = React6.useState(0);
|
|
3183
|
+
const [loopMode, setLoopMode] = React6.useState(defaultLoopMode);
|
|
3184
|
+
const [showPlaylist, setShowPlaylist] = React6.useState(false);
|
|
3185
|
+
const [isUIVisible, setIsUIVisible] = React6.useState(true);
|
|
3186
|
+
const playerRef = React6.useRef(null);
|
|
3187
|
+
const containerRef = React6.useRef(null);
|
|
3188
|
+
const isStartedRef = React6.useRef(autoPlay);
|
|
3189
|
+
const uiTimeoutRef = React6.useRef(null);
|
|
3190
|
+
const currentTrack = tracks[currentIndex];
|
|
3191
|
+
const goToTrack = React6.useCallback(
|
|
3192
|
+
(index) => {
|
|
3193
|
+
if (index < 0 || index >= tracks.length) return;
|
|
3194
|
+
if (isTransitioning) return;
|
|
3195
|
+
const track = tracks[index];
|
|
3196
|
+
if (!track) return;
|
|
3197
|
+
console.log(`[MMDMusicPlayer] Transitioning to track ${index}: ${track.title}`);
|
|
3198
|
+
setIsTransitioning(true);
|
|
3199
|
+
setIsLoading(true);
|
|
3200
|
+
const wasPlaying = isPlaying;
|
|
3201
|
+
setIsPlaying(false);
|
|
3202
|
+
setTimeout(() => {
|
|
3203
|
+
setCurrentIndex(index);
|
|
3204
|
+
setCurrentTime(0);
|
|
3205
|
+
setDuration(0);
|
|
3206
|
+
onTrackChange?.(track, index);
|
|
3207
|
+
setTimeout(() => {
|
|
3208
|
+
setIsTransitioning(false);
|
|
3209
|
+
if (wasPlaying) {
|
|
3210
|
+
isStartedRef.current = true;
|
|
3211
|
+
}
|
|
3212
|
+
}, 100);
|
|
3213
|
+
}, 300);
|
|
3214
|
+
},
|
|
3215
|
+
[tracks, isTransitioning, isPlaying, onTrackChange]
|
|
3216
|
+
);
|
|
3217
|
+
const next = React6.useCallback(() => {
|
|
3218
|
+
let nextIndex = currentIndex + 1;
|
|
3219
|
+
if (loopMode === "shuffle") {
|
|
3220
|
+
nextIndex = Math.floor(Math.random() * tracks.length);
|
|
3221
|
+
} else if (nextIndex >= tracks.length) {
|
|
3222
|
+
nextIndex = 0;
|
|
3223
|
+
}
|
|
3224
|
+
goToTrack(nextIndex);
|
|
3225
|
+
}, [currentIndex, tracks.length, loopMode, goToTrack]);
|
|
3226
|
+
const previous = React6.useCallback(() => {
|
|
3227
|
+
let prevIndex = currentIndex - 1;
|
|
3228
|
+
if (prevIndex < 0) {
|
|
3229
|
+
prevIndex = tracks.length - 1;
|
|
3230
|
+
}
|
|
3231
|
+
goToTrack(prevIndex);
|
|
3232
|
+
}, [currentIndex, tracks.length, goToTrack]);
|
|
3233
|
+
React6.useImperativeHandle(
|
|
3234
|
+
ref,
|
|
3235
|
+
() => ({
|
|
3236
|
+
play: () => {
|
|
3237
|
+
setIsPlaying(true);
|
|
3238
|
+
isStartedRef.current = true;
|
|
3239
|
+
playerRef.current?.play();
|
|
3240
|
+
},
|
|
3241
|
+
pause: () => {
|
|
3242
|
+
setIsPlaying(false);
|
|
3243
|
+
isStartedRef.current = false;
|
|
3244
|
+
playerRef.current?.pause();
|
|
3245
|
+
},
|
|
3246
|
+
next,
|
|
3247
|
+
previous,
|
|
3248
|
+
goToTrack,
|
|
3249
|
+
setLoopMode,
|
|
3250
|
+
getState: () => ({
|
|
3251
|
+
currentIndex,
|
|
3252
|
+
isPlaying,
|
|
3253
|
+
currentTime,
|
|
3254
|
+
duration,
|
|
3255
|
+
loopMode
|
|
3256
|
+
})
|
|
3257
|
+
}),
|
|
3258
|
+
[next, previous, goToTrack, currentIndex, isPlaying, currentTime, duration, loopMode]
|
|
3259
|
+
);
|
|
3260
|
+
const handleEnded = React6.useCallback(() => {
|
|
3261
|
+
if (loopMode === "single") {
|
|
3262
|
+
playerRef.current?.seek(0);
|
|
3263
|
+
playerRef.current?.play();
|
|
3264
|
+
} else {
|
|
3265
|
+
next();
|
|
3266
|
+
}
|
|
3267
|
+
}, [loopMode, next]);
|
|
3268
|
+
const handleTimeUpdate = React6.useCallback((time) => {
|
|
3269
|
+
setCurrentTime(time);
|
|
3270
|
+
if (playerRef.current) {
|
|
3271
|
+
const total = playerRef.current.getDuration();
|
|
3272
|
+
setDuration(total);
|
|
3273
|
+
onProgress?.(time, total);
|
|
3274
|
+
}
|
|
3275
|
+
}, [onProgress]);
|
|
3276
|
+
const resetUITimeout = React6.useCallback(() => {
|
|
3277
|
+
setIsUIVisible(true);
|
|
3278
|
+
if (uiTimeoutRef.current) clearTimeout(uiTimeoutRef.current);
|
|
3279
|
+
if (isPlaying) {
|
|
3280
|
+
uiTimeoutRef.current = setTimeout(() => {
|
|
3281
|
+
if (!showPlaylist) setIsUIVisible(false);
|
|
3282
|
+
}, 5e3);
|
|
3283
|
+
}
|
|
3284
|
+
}, [isPlaying, showPlaylist]);
|
|
3285
|
+
React6.useEffect(() => {
|
|
3286
|
+
resetUITimeout();
|
|
3287
|
+
return () => {
|
|
3288
|
+
if (uiTimeoutRef.current) clearTimeout(uiTimeoutRef.current);
|
|
3289
|
+
};
|
|
3290
|
+
}, [resetUITimeout]);
|
|
3291
|
+
if (!currentTrack) {
|
|
3292
|
+
return /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex h-full w-full items-center justify-center bg-black text-white" }, "\u64AD\u653E\u5217\u8868\u4E3A\u7A7A");
|
|
3293
|
+
}
|
|
3294
|
+
return /* @__PURE__ */ React6__default.default.createElement(
|
|
3295
|
+
"div",
|
|
3296
|
+
{
|
|
3297
|
+
ref: containerRef,
|
|
3298
|
+
className: `relative bg-black group ${className}`,
|
|
3299
|
+
style: { width: "100%", height: "100%", overflow: "hidden", ...style },
|
|
3300
|
+
onMouseMove: resetUITimeout,
|
|
3301
|
+
onClick: resetUITimeout
|
|
3302
|
+
},
|
|
3303
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
3304
|
+
"div",
|
|
3305
|
+
{
|
|
3306
|
+
className: "absolute inset-0 w-full h-full",
|
|
3307
|
+
style: {
|
|
3308
|
+
zIndex: 0,
|
|
3309
|
+
opacity: isLoading || isTransitioning ? 0 : 1,
|
|
3310
|
+
transition: "opacity 0.5s ease-in-out"
|
|
3311
|
+
}
|
|
3312
|
+
},
|
|
3313
|
+
!isTransitioning && /* @__PURE__ */ React6__default.default.createElement(
|
|
3314
|
+
MMDPlayerBase,
|
|
3315
|
+
{
|
|
3316
|
+
key: currentTrack.id,
|
|
3317
|
+
ref: playerRef,
|
|
3318
|
+
resources: currentTrack.resources,
|
|
3319
|
+
stage,
|
|
3320
|
+
autoPlay: isStartedRef.current,
|
|
3321
|
+
loop: loopMode === "single",
|
|
3322
|
+
mobileOptimization,
|
|
3323
|
+
onLoad: () => {
|
|
3324
|
+
console.log("[MMDMusicPlayer] Track loaded");
|
|
3325
|
+
setIsLoading(false);
|
|
3326
|
+
if (isStartedRef.current) {
|
|
3327
|
+
playerRef.current?.play();
|
|
3328
|
+
setIsPlaying(true);
|
|
3329
|
+
}
|
|
3330
|
+
},
|
|
3331
|
+
onPlay: () => {
|
|
3332
|
+
setIsPlaying(true);
|
|
3333
|
+
onPlayPause?.(true);
|
|
3334
|
+
},
|
|
3335
|
+
onPause: () => {
|
|
3336
|
+
setIsPlaying(false);
|
|
3337
|
+
onPlayPause?.(false);
|
|
3338
|
+
},
|
|
3339
|
+
onTimeUpdate: handleTimeUpdate,
|
|
3340
|
+
onEnded: handleEnded,
|
|
3341
|
+
onError
|
|
3342
|
+
}
|
|
3343
|
+
)
|
|
3344
|
+
),
|
|
3345
|
+
(isLoading || isTransitioning) && /* @__PURE__ */ React6__default.default.createElement("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-md" }, /* @__PURE__ */ React6__default.default.createElement("div", { className: "flex flex-col items-center gap-4" }, /* @__PURE__ */ React6__default.default.createElement("div", { className: "h-12 w-12 animate-spin rounded-full border-4 border-white/20 border-t-blue-500" }), /* @__PURE__ */ React6__default.default.createElement("div", { className: "text-white font-medium" }, isTransitioning ? "\u51C6\u5907\u4E0B\u4E00\u9996..." : "\u6B63\u5728\u52A0\u8F7D\u821E\u53F0..."))),
|
|
3346
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
3347
|
+
"div",
|
|
3348
|
+
{
|
|
3349
|
+
className: `absolute inset-0 z-10 flex flex-col justify-between transition-opacity duration-700 pointer-events-none ${isUIVisible ? "opacity-100" : "opacity-0"}`
|
|
3350
|
+
},
|
|
3351
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "pt-12 px-8 flex justify-center" }, /* @__PURE__ */ React6__default.default.createElement(TrackInfo, { track: currentTrack })),
|
|
3352
|
+
/* @__PURE__ */ React6__default.default.createElement("div", { className: "pb-12 px-8" }, /* @__PURE__ */ React6__default.default.createElement(
|
|
3353
|
+
MusicControls,
|
|
3354
|
+
{
|
|
3355
|
+
isPlaying,
|
|
3356
|
+
currentTime,
|
|
3357
|
+
duration,
|
|
3358
|
+
loopMode,
|
|
3359
|
+
onPlayPause: () => isPlaying ? playerRef.current?.pause() : playerRef.current?.play(),
|
|
3360
|
+
onNext: next,
|
|
3361
|
+
onPrevious: previous,
|
|
3362
|
+
onSeek: (time) => playerRef.current?.seek(time),
|
|
3363
|
+
onToggleLoop: () => {
|
|
3364
|
+
const modes = ["list", "single", "shuffle"];
|
|
3365
|
+
const nextMode = modes[(modes.indexOf(loopMode) + 1) % modes.length];
|
|
3366
|
+
setLoopMode(nextMode);
|
|
3367
|
+
},
|
|
3368
|
+
onTogglePlaylist: () => setShowPlaylist(!showPlaylist)
|
|
3369
|
+
}
|
|
3370
|
+
))
|
|
3371
|
+
),
|
|
3372
|
+
/* @__PURE__ */ React6__default.default.createElement(
|
|
3373
|
+
PlaylistPanel,
|
|
3374
|
+
{
|
|
3375
|
+
tracks,
|
|
3376
|
+
currentIndex,
|
|
3377
|
+
isOpen: showPlaylist,
|
|
3378
|
+
onClose: () => setShowPlaylist(false),
|
|
3379
|
+
onSelectTrack: (index) => {
|
|
3380
|
+
goToTrack(index);
|
|
3381
|
+
setShowPlaylist(false);
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
)
|
|
3385
|
+
);
|
|
3386
|
+
}
|
|
3387
|
+
);
|
|
3388
|
+
MMDMusicPlayer.displayName = "MMDMusicPlayer";
|
|
2911
3389
|
|
|
2912
3390
|
exports.DialogueBox = DialogueBox;
|
|
2913
3391
|
exports.HistoryPanel = HistoryPanel;
|
|
2914
3392
|
exports.LoadingOverlay = LoadingOverlay;
|
|
2915
3393
|
exports.LoadingScreen = LoadingScreen;
|
|
3394
|
+
exports.MMDMusicPlayer = MMDMusicPlayer;
|
|
2916
3395
|
exports.MMDPlayerBase = MMDPlayerBase;
|
|
2917
3396
|
exports.MMDPlayerEnhanced = MMDPlayerEnhanced;
|
|
2918
3397
|
exports.MMDPlayerEnhancedDebugInfo = MMDPlayerEnhancedDebugInfo;
|
|
2919
3398
|
exports.MMDPlaylist = MMDPlaylist;
|
|
2920
3399
|
exports.MMDPlaylistDebugInfo = MMDPlaylistDebugInfo;
|
|
2921
3400
|
exports.MMDVisualNovel = MMDVisualNovel;
|
|
3401
|
+
exports.MusicControls = MusicControls;
|
|
3402
|
+
exports.PlaylistPanel = PlaylistPanel;
|
|
2922
3403
|
exports.StartScreen = StartScreen;
|
|
3404
|
+
exports.TrackInfo = TrackInfo;
|
|
2923
3405
|
exports.loadAmmo = loadAmmo;
|
|
2924
3406
|
//# sourceMappingURL=index.js.map
|
|
2925
3407
|
//# sourceMappingURL=index.js.map
|