sa2kit 1.6.18 → 1.6.19
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/analytics/index.js +1 -1
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +1 -1
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/auth/components/index.js +1 -1
- package/dist/auth/components/index.js.map +1 -1
- package/dist/auth/components/index.mjs +1 -1
- package/dist/auth/components/index.mjs.map +1 -1
- package/dist/calendar/index.js +10 -10
- package/dist/calendar/index.js.map +1 -1
- package/dist/calendar/index.mjs +3 -3
- package/dist/calendar/index.mjs.map +1 -1
- package/dist/{chunk-FDHCX2BY.mjs → chunk-NQ4JDU24.mjs} +3 -3
- package/dist/chunk-NQ4JDU24.mjs.map +1 -0
- package/dist/{chunk-ASL3QC22.js → chunk-PXVELWYK.js} +3 -3
- package/dist/chunk-PXVELWYK.js.map +1 -0
- package/dist/index.js +114 -114
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -7
- package/dist/index.mjs.map +1 -1
- package/dist/mmd/index.d.mts +8 -11
- package/dist/mmd/index.d.ts +8 -11
- package/dist/mmd/index.js +562 -464
- package/dist/mmd/index.js.map +1 -1
- package/dist/mmd/index.mjs +563 -466
- package/dist/mmd/index.mjs.map +1 -1
- package/dist/universalExport/index.js +4 -4
- package/dist/universalExport/index.js.map +1 -1
- package/dist/universalExport/index.mjs +4 -4
- package/dist/universalExport/index.mjs.map +1 -1
- package/dist/universalFile/index.js +2 -2
- package/dist/universalFile/index.js.map +1 -1
- package/dist/universalFile/index.mjs +2 -2
- package/dist/universalFile/index.mjs.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-ASL3QC22.js.map +0 -1
- package/dist/chunk-FDHCX2BY.mjs.map +0 -1
package/dist/mmd/index.js
CHANGED
|
@@ -9,6 +9,7 @@ var THREE2 = require('three');
|
|
|
9
9
|
var threeStdlib = require('three-stdlib');
|
|
10
10
|
var lucideReact = require('lucide-react');
|
|
11
11
|
var reactDom = require('react-dom');
|
|
12
|
+
var Script = require('next/script');
|
|
12
13
|
|
|
13
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
15
|
|
|
@@ -32,6 +33,7 @@ function _interopNamespace(e) {
|
|
|
32
33
|
|
|
33
34
|
var React10__default = /*#__PURE__*/_interopDefault(React10);
|
|
34
35
|
var THREE2__namespace = /*#__PURE__*/_interopNamespace(THREE2);
|
|
36
|
+
var Script__default = /*#__PURE__*/_interopDefault(Script);
|
|
35
37
|
|
|
36
38
|
// src/mmd/pmx/editor/PMXEditor.ts
|
|
37
39
|
var PMXEditor = class {
|
|
@@ -4413,7 +4415,7 @@ var VNModal = ({ title, show, onClose, children }) => {
|
|
|
4413
4415
|
return /* @__PURE__ */ React10__default.default.createElement(
|
|
4414
4416
|
"div",
|
|
4415
4417
|
{
|
|
4416
|
-
className: "fixed inset-0 flex items-center justify-center backdrop-blur-xl z-[
|
|
4418
|
+
className: "fixed inset-0 flex items-center justify-center backdrop-blur-xl z-[1000] pointer-events-auto transition-all animate-in fade-in zoom-in-95 duration-300 px-4",
|
|
4417
4419
|
style: { background: "rgba(100, 116, 139, 0.3)" },
|
|
4418
4420
|
onClick: onClose
|
|
4419
4421
|
},
|
|
@@ -6336,499 +6338,595 @@ var MMDMusicPlayer = React10.forwardRef(
|
|
|
6336
6338
|
}
|
|
6337
6339
|
);
|
|
6338
6340
|
MMDMusicPlayer.displayName = "MMDMusicPlayer";
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
var ARMode = /* @__PURE__ */ ((ARMode2) => {
|
|
6342
|
-
ARMode2["Overlay"] = "overlay";
|
|
6343
|
-
ARMode2["WorldFixed"] = "world-fixed";
|
|
6344
|
-
return ARMode2;
|
|
6345
|
-
})(ARMode || {});
|
|
6346
|
-
function Select({
|
|
6347
|
-
label,
|
|
6348
|
-
options,
|
|
6349
|
-
value,
|
|
6350
|
-
onChange,
|
|
6351
|
-
placeholder = "\u8BF7\u9009\u62E9...",
|
|
6352
|
-
allowEmpty = false,
|
|
6353
|
-
emptyLabel = "\u65E0"
|
|
6354
|
-
}) {
|
|
6355
|
-
const selectedOption = options.find((opt) => opt.id === value);
|
|
6356
|
-
const showPlaceholder = !selectedOption && !allowEmpty && value !== "";
|
|
6357
|
-
return /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs font-medium text-white/50 ml-1 uppercase tracking-wider" }, label), /* @__PURE__ */ React10__default.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6358
|
-
"select",
|
|
6359
|
-
{
|
|
6360
|
-
value,
|
|
6361
|
-
onChange: (e) => onChange(e.target.value),
|
|
6362
|
-
className: "w-full appearance-none bg-white/5 border border-white/10 rounded-xl px-4 py-3 pr-10 text-sm text-white focus:outline-none focus:border-cyan-500/50 transition-colors cursor-pointer hover:bg-white/10"
|
|
6363
|
-
},
|
|
6364
|
-
showPlaceholder && /* @__PURE__ */ React10__default.default.createElement("option", { value: "", disabled: true, className: "bg-gray-900 text-white/50" }, placeholder),
|
|
6365
|
-
allowEmpty && /* @__PURE__ */ React10__default.default.createElement("option", { value: "", className: "bg-gray-900 text-white/60" }, emptyLabel),
|
|
6366
|
-
options.map((option) => /* @__PURE__ */ React10__default.default.createElement(
|
|
6367
|
-
"option",
|
|
6368
|
-
{
|
|
6369
|
-
key: option.id,
|
|
6370
|
-
value: option.id,
|
|
6371
|
-
className: "bg-gray-900 text-white"
|
|
6372
|
-
},
|
|
6373
|
-
option.name
|
|
6374
|
-
))
|
|
6375
|
-
), /* @__PURE__ */ React10__default.default.createElement(lucideReact.ChevronDown, { className: "absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-white/40 pointer-events-none" })));
|
|
6376
|
-
}
|
|
6377
|
-
function ARModeSwitch({ mode, onChange, gyroSupported }) {
|
|
6378
|
-
return /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-xs font-medium text-white/50 ml-1 uppercase tracking-wider" }, "AR \u6A21\u5F0F"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "grid grid-cols-2 gap-2" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6379
|
-
"button",
|
|
6380
|
-
{
|
|
6381
|
-
onClick: () => onChange("overlay" /* Overlay */),
|
|
6382
|
-
className: `p-3 rounded-xl border transition-all flex flex-col items-center gap-1.5 ${mode === "overlay" /* Overlay */ ? "bg-cyan-500/20 border-cyan-500/50 text-cyan-400" : "bg-white/5 border-white/10 text-white/60 hover:bg-white/10"}`
|
|
6383
|
-
},
|
|
6384
|
-
/* @__PURE__ */ React10__default.default.createElement(lucideReact.Layers, { className: "w-5 h-5" }),
|
|
6385
|
-
/* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs font-medium" }, "\u53E0\u52A0\u6A21\u5F0F")
|
|
6386
|
-
), /* @__PURE__ */ React10__default.default.createElement(
|
|
6387
|
-
"button",
|
|
6388
|
-
{
|
|
6389
|
-
onClick: () => gyroSupported && onChange("world-fixed" /* WorldFixed */),
|
|
6390
|
-
disabled: !gyroSupported,
|
|
6391
|
-
className: `p-3 rounded-xl border transition-all flex flex-col items-center gap-1.5 ${mode === "world-fixed" /* WorldFixed */ ? "bg-purple-500/20 border-purple-500/50 text-purple-400" : gyroSupported ? "bg-white/5 border-white/10 text-white/60 hover:bg-white/10" : "bg-white/5 border-white/10 text-white/30 cursor-not-allowed"}`,
|
|
6392
|
-
title: gyroSupported ? "\u4E16\u754C\u56FA\u5B9A\u6A21\u5F0F" : "\u8BBE\u5907\u4E0D\u652F\u6301\u9640\u87BA\u4EEA"
|
|
6393
|
-
},
|
|
6394
|
-
/* @__PURE__ */ React10__default.default.createElement(lucideReact.Compass, { className: "w-5 h-5" }),
|
|
6395
|
-
/* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs font-medium" }, "\u4E16\u754C\u56FA\u5B9A"),
|
|
6396
|
-
!gyroSupported && /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-[10px] text-red-400" }, "\u4E0D\u652F\u6301")
|
|
6397
|
-
)), /* @__PURE__ */ React10__default.default.createElement("p", { className: "text-[10px] text-white/40 ml-1 mt-1" }, mode === "overlay" /* Overlay */ ? "\u6A21\u578B\u56FA\u5B9A\u5728\u5C4F\u5E55\u4E0A" : "\u6A21\u578B\u56FA\u5B9A\u5728\u4E16\u754C\u7A7A\u95F4\uFF0C\u79FB\u52A8\u8BBE\u5907\u67E5\u770B"));
|
|
6341
|
+
if (typeof window !== "undefined") {
|
|
6342
|
+
window.THREE = THREE2__namespace;
|
|
6398
6343
|
}
|
|
6399
|
-
var MMDARPlayer = React10.forwardRef((
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
showSettings = true,
|
|
6406
|
-
modelPresets,
|
|
6407
|
-
motionPresets,
|
|
6408
|
-
audioPresets = [],
|
|
6409
|
-
defaultModelId,
|
|
6410
|
-
defaultMotionId,
|
|
6411
|
-
defaultAudioId,
|
|
6412
|
-
initialModelVisible = false,
|
|
6413
|
-
placementText = "TOUCH!",
|
|
6414
|
-
defaultARMode = "overlay" /* Overlay */,
|
|
6415
|
-
autoPlay = true,
|
|
6416
|
-
loop = true,
|
|
6417
|
-
onCameraReady,
|
|
6418
|
-
onCameraError,
|
|
6419
|
-
onResourcesChange,
|
|
6420
|
-
onModelPlaced,
|
|
6421
|
-
onARModeChange,
|
|
6422
|
-
onLoad,
|
|
6423
|
-
onError,
|
|
6424
|
-
className,
|
|
6425
|
-
style
|
|
6426
|
-
} = props;
|
|
6427
|
-
const initialModelId = defaultModelId || modelPresets[0]?.id || "";
|
|
6428
|
-
const initialMotionId = defaultMotionId || motionPresets[0]?.id || "";
|
|
6429
|
-
const initialAudioId = defaultAudioId || audioPresets[0]?.id || "";
|
|
6430
|
-
const videoRef = React10.useRef(null);
|
|
6431
|
-
const playerRef = React10.useRef(null);
|
|
6432
|
-
const streamRef = React10.useRef(null);
|
|
6344
|
+
var MMDARPlayer = React10.forwardRef(({
|
|
6345
|
+
width = 800,
|
|
6346
|
+
height = 600,
|
|
6347
|
+
onReady,
|
|
6348
|
+
onError
|
|
6349
|
+
}, ref) => {
|
|
6433
6350
|
const containerRef = React10.useRef(null);
|
|
6351
|
+
const canvasRef = React10.useRef(null);
|
|
6352
|
+
const sceneRef = React10.useRef();
|
|
6353
|
+
const cameraRef = React10.useRef();
|
|
6354
|
+
const rendererRef = React10.useRef();
|
|
6355
|
+
const arToolkitSourceRef = React10.useRef();
|
|
6356
|
+
const arToolkitContextRef = React10.useRef();
|
|
6357
|
+
const markerRootRef = React10.useRef();
|
|
6358
|
+
const markerControlsRef = React10.useRef();
|
|
6359
|
+
const modelRootRef = React10.useRef();
|
|
6360
|
+
const modelRef = React10.useRef();
|
|
6361
|
+
const [state, setState] = React10.useState({
|
|
6362
|
+
isLoading: true,
|
|
6363
|
+
cameraReady: false,
|
|
6364
|
+
arReady: false,
|
|
6365
|
+
error: null,
|
|
6366
|
+
showSettings: false,
|
|
6367
|
+
modelPlaced: false,
|
|
6368
|
+
markerDetected: false,
|
|
6369
|
+
selectedModel: "sphere",
|
|
6370
|
+
selectedMotion: "idle",
|
|
6371
|
+
selectedAudio: "none",
|
|
6372
|
+
cameraFacing: "environment",
|
|
6373
|
+
markerType: "barcode",
|
|
6374
|
+
showWireframe: false,
|
|
6375
|
+
lightingEnabled: true,
|
|
6376
|
+
quality: "medium"
|
|
6377
|
+
});
|
|
6434
6378
|
const gyroDataRef = React10.useRef({ alpha: 0, beta: 0, gamma: 0 });
|
|
6435
|
-
const
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
if (typeof window === "undefined") return;
|
|
6464
|
-
if (!("DeviceOrientationEvent" in window)) {
|
|
6465
|
-
setGyroSupported(false);
|
|
6466
|
-
return;
|
|
6379
|
+
const initializeThreeJS = React10.useCallback(() => {
|
|
6380
|
+
try {
|
|
6381
|
+
const scene = new THREE2__namespace.Scene();
|
|
6382
|
+
sceneRef.current = scene;
|
|
6383
|
+
const camera = new THREE2__namespace.Camera();
|
|
6384
|
+
cameraRef.current = camera;
|
|
6385
|
+
scene.add(camera);
|
|
6386
|
+
const renderer = new THREE2__namespace.WebGLRenderer({
|
|
6387
|
+
canvas: canvasRef.current,
|
|
6388
|
+
antialias: true,
|
|
6389
|
+
alpha: true
|
|
6390
|
+
});
|
|
6391
|
+
renderer.setSize(width, height);
|
|
6392
|
+
renderer.setClearColor(0, 0);
|
|
6393
|
+
rendererRef.current = renderer;
|
|
6394
|
+
console.log("Three.js initialized successfully");
|
|
6395
|
+
return true;
|
|
6396
|
+
} catch (error) {
|
|
6397
|
+
console.error("Failed to initialize Three.js:", error);
|
|
6398
|
+
setState((prev) => ({ ...prev, error: "Three.js \u521D\u59CB\u5316\u5931\u8D25" }));
|
|
6399
|
+
return false;
|
|
6400
|
+
}
|
|
6401
|
+
}, [width, height]);
|
|
6402
|
+
const requestCameraPermission = React10.useCallback(async () => {
|
|
6403
|
+
try {
|
|
6404
|
+
console.log("Checking camera support...");
|
|
6405
|
+
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
6406
|
+
throw new Error("\u60A8\u7684\u6D4F\u89C8\u5668\u4E0D\u652F\u6301\u6444\u50CF\u5934\u8BBF\u95EE");
|
|
6467
6407
|
}
|
|
6468
|
-
|
|
6408
|
+
console.log("Camera API supported, checking permissions...");
|
|
6409
|
+
if (navigator.permissions) {
|
|
6469
6410
|
try {
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6411
|
+
console.log("Querying camera permission status...");
|
|
6412
|
+
const permissionPromise = navigator.permissions.query({ name: "camera" });
|
|
6413
|
+
const timeoutPromise2 = new Promise((_, reject) => {
|
|
6414
|
+
setTimeout(() => reject(new Error("Permission query timeout")), 5e3);
|
|
6415
|
+
});
|
|
6416
|
+
const permissionStatus = await Promise.race([permissionPromise, timeoutPromise2]);
|
|
6417
|
+
console.log("Permission status:", permissionStatus.state);
|
|
6418
|
+
if (permissionStatus.state === "denied") {
|
|
6419
|
+
throw new Error("\u6444\u50CF\u5934\u6743\u9650\u5DF2\u88AB\u62D2\u7EDD\uFF0C\u8BF7\u5728\u6D4F\u89C8\u5668\u8BBE\u7F6E\u4E2D\u5141\u8BB8\u8BBF\u95EE\u6444\u50CF\u5934");
|
|
6420
|
+
}
|
|
6421
|
+
} catch (permissionError) {
|
|
6422
|
+
console.warn("Permission query failed or timed out, proceeding with getUserMedia:", permissionError);
|
|
6475
6423
|
}
|
|
6476
|
-
} else {
|
|
6477
|
-
setGyroSupported(true);
|
|
6478
6424
|
}
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
if (!initialOrientationRef.current) {
|
|
6488
|
-
initialOrientationRef.current = { alpha, beta, gamma };
|
|
6489
|
-
}
|
|
6490
|
-
const initial = initialOrientationRef.current;
|
|
6491
|
-
const deltaAlpha = alpha - initial.alpha;
|
|
6492
|
-
const deltaBeta = beta - initial.beta;
|
|
6493
|
-
const deltaGamma = gamma - initial.gamma;
|
|
6494
|
-
gyroDataRef.current = { alpha: deltaAlpha, beta: deltaBeta, gamma: deltaGamma };
|
|
6495
|
-
setModelRotation({
|
|
6496
|
-
x: -deltaBeta * (Math.PI / 180) * 0.5,
|
|
6497
|
-
// 俯仰
|
|
6498
|
-
y: -deltaAlpha * (Math.PI / 180) * 0.5,
|
|
6499
|
-
// 偏航
|
|
6500
|
-
z: deltaGamma * (Math.PI / 180) * 0.3
|
|
6501
|
-
// 翻滚
|
|
6425
|
+
console.log("Requesting camera access...");
|
|
6426
|
+
const cameraPromise = navigator.mediaDevices.getUserMedia({
|
|
6427
|
+
video: {
|
|
6428
|
+
width: { ideal: width },
|
|
6429
|
+
height: { ideal: height },
|
|
6430
|
+
facingMode: "environment"
|
|
6431
|
+
// 优先使用后置摄像头
|
|
6432
|
+
}
|
|
6502
6433
|
});
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6434
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
6435
|
+
setTimeout(() => reject(new Error("Camera access timeout - \u8BF7\u68C0\u67E5\u6444\u50CF\u5934\u6743\u9650")), 1e4);
|
|
6436
|
+
});
|
|
6437
|
+
const testStream = await Promise.race([cameraPromise, timeoutPromise]);
|
|
6438
|
+
console.log("Camera access granted, stopping test stream...");
|
|
6439
|
+
testStream.getTracks().forEach((track) => track.stop());
|
|
6440
|
+
console.log("Camera permission granted successfully");
|
|
6441
|
+
return true;
|
|
6442
|
+
} catch (error) {
|
|
6443
|
+
console.error("Camera permission denied:", error);
|
|
6444
|
+
const errorMessage = error instanceof Error ? error.message : "\u65E0\u6CD5\u8BBF\u95EE\u6444\u50CF\u5934";
|
|
6445
|
+
setState((prev) => ({ ...prev, error: errorMessage, isLoading: false }));
|
|
6446
|
+
onError?.(errorMessage);
|
|
6447
|
+
return false;
|
|
6448
|
+
}
|
|
6449
|
+
}, [width, height, onError]);
|
|
6450
|
+
const createModel = React10.useCallback((modelType) => {
|
|
6451
|
+
let geometry;
|
|
6452
|
+
let material;
|
|
6453
|
+
let mesh;
|
|
6454
|
+
switch (modelType) {
|
|
6455
|
+
case "sphere":
|
|
6456
|
+
geometry = new THREE2__namespace.SphereGeometry(0.5, 32, 32);
|
|
6457
|
+
material = new THREE2__namespace.MeshPhongMaterial({
|
|
6458
|
+
color: 16738740,
|
|
6459
|
+
shininess: 100,
|
|
6460
|
+
specular: 1118481
|
|
6461
|
+
});
|
|
6462
|
+
mesh = new THREE2__namespace.Mesh(geometry, material);
|
|
6463
|
+
break;
|
|
6464
|
+
case "cube":
|
|
6465
|
+
geometry = new THREE2__namespace.BoxGeometry(0.8, 0.8, 0.8);
|
|
6466
|
+
material = new THREE2__namespace.MeshPhongMaterial({
|
|
6467
|
+
color: 65407,
|
|
6468
|
+
shininess: 100,
|
|
6469
|
+
specular: 1118481
|
|
6470
|
+
});
|
|
6471
|
+
mesh = new THREE2__namespace.Mesh(geometry, material);
|
|
6472
|
+
break;
|
|
6473
|
+
case "torus":
|
|
6474
|
+
geometry = new THREE2__namespace.TorusGeometry(0.4, 0.2, 16, 100);
|
|
6475
|
+
material = new THREE2__namespace.MeshPhongMaterial({
|
|
6476
|
+
color: 16753920,
|
|
6477
|
+
shininess: 100,
|
|
6478
|
+
specular: 1118481
|
|
6479
|
+
});
|
|
6480
|
+
mesh = new THREE2__namespace.Mesh(geometry, material);
|
|
6481
|
+
break;
|
|
6482
|
+
default:
|
|
6483
|
+
geometry = new THREE2__namespace.SphereGeometry(0.5, 32, 32);
|
|
6484
|
+
material = new THREE2__namespace.MeshPhongMaterial({
|
|
6485
|
+
color: 16738740,
|
|
6486
|
+
shininess: 100,
|
|
6487
|
+
specular: 1118481
|
|
6488
|
+
});
|
|
6489
|
+
mesh = new THREE2__namespace.Mesh(geometry, material);
|
|
6519
6490
|
}
|
|
6520
|
-
|
|
6491
|
+
mesh.rotation.x = Math.PI / 4;
|
|
6492
|
+
mesh.rotation.y = Math.PI / 4;
|
|
6493
|
+
return mesh;
|
|
6521
6494
|
}, []);
|
|
6522
|
-
const setARMode = React10.useCallback(async (mode) => {
|
|
6523
|
-
if (mode === "world-fixed" /* WorldFixed */) {
|
|
6524
|
-
const hasPermission = await requestGyroPermission();
|
|
6525
|
-
if (!hasPermission) {
|
|
6526
|
-
console.warn("[MMDARPlayer] Gyro permission denied, staying in Overlay mode");
|
|
6527
|
-
return;
|
|
6528
|
-
}
|
|
6529
|
-
initialOrientationRef.current = null;
|
|
6530
|
-
}
|
|
6531
|
-
setARModeState(mode);
|
|
6532
|
-
onARModeChange?.(mode);
|
|
6533
|
-
}, [requestGyroPermission, onARModeChange]);
|
|
6534
6495
|
const placeModel = React10.useCallback(() => {
|
|
6535
|
-
if (
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
initialOrientationRef.current = null;
|
|
6539
|
-
setTimeout(() => {
|
|
6540
|
-
setIsModelPlaced(true);
|
|
6541
|
-
setPlacementAnimation(false);
|
|
6542
|
-
onModelPlaced?.();
|
|
6543
|
-
}, 300);
|
|
6544
|
-
}, [isModelPlaced, onModelPlaced]);
|
|
6545
|
-
const removeModel = React10.useCallback(() => {
|
|
6546
|
-
setIsModelPlaced(false);
|
|
6547
|
-
setIsLoading(false);
|
|
6548
|
-
initialOrientationRef.current = null;
|
|
6549
|
-
}, []);
|
|
6550
|
-
const switchModel = React10.useCallback((newResources) => {
|
|
6551
|
-
const matchedModel = modelPresets.find((m) => m.modelPath === newResources.modelPath);
|
|
6552
|
-
const matchedMotion = motionPresets.find((m) => m.motionPath === newResources.motionPath);
|
|
6553
|
-
const matchedAudio = audioPresets.find((a) => a.audioPath === newResources.audioPath);
|
|
6554
|
-
if (matchedModel) setSelectedModelId(matchedModel.id);
|
|
6555
|
-
if (matchedMotion) setSelectedMotionId(matchedMotion.id);
|
|
6556
|
-
if (matchedAudio) setSelectedAudioId(matchedAudio.id);
|
|
6557
|
-
onResourcesChange?.(newResources);
|
|
6558
|
-
if (isModelPlaced) {
|
|
6559
|
-
setIsLoading(true);
|
|
6560
|
-
}
|
|
6561
|
-
}, [isModelPlaced, onResourcesChange, modelPresets, motionPresets, audioPresets]);
|
|
6562
|
-
const applySettings = React10.useCallback(() => {
|
|
6563
|
-
onResourcesChange?.(currentResources);
|
|
6564
|
-
setIsSettingsOpen(false);
|
|
6565
|
-
if (isModelPlaced) {
|
|
6566
|
-
setIsLoading(true);
|
|
6496
|
+
if (!markerRootRef.current || !modelRootRef.current || !sceneRef.current) {
|
|
6497
|
+
console.error("Cannot place model: missing required references");
|
|
6498
|
+
return;
|
|
6567
6499
|
}
|
|
6568
|
-
}, [currentResources, isModelPlaced, onResourcesChange]);
|
|
6569
|
-
const resetPosition = React10.useCallback(() => {
|
|
6570
|
-
setIsModelPlaced(false);
|
|
6571
|
-
setIsLoading(false);
|
|
6572
|
-
setIsSettingsOpen(false);
|
|
6573
|
-
initialOrientationRef.current = null;
|
|
6574
|
-
setModelRotation({ x: 0, y: 0, z: 0 });
|
|
6575
|
-
}, []);
|
|
6576
|
-
const startCamera = React10.useCallback(async (mode = facingMode) => {
|
|
6577
6500
|
try {
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
if (videoRef.current) {
|
|
6593
|
-
videoRef.current.srcObject = stream;
|
|
6594
|
-
await videoRef.current.play();
|
|
6595
|
-
}
|
|
6596
|
-
setIsCameraStarted(true);
|
|
6597
|
-
setFacingMode(mode);
|
|
6598
|
-
onCameraReady?.(stream);
|
|
6599
|
-
} catch (err) {
|
|
6600
|
-
console.error("[MMDARPlayer] Camera access error:", err);
|
|
6601
|
-
const errorMsg = err.name === "NotAllowedError" ? "\u6444\u50CF\u5934\u6743\u9650\u88AB\u62D2\u7EDD" : `\u65E0\u6CD5\u8BBF\u95EE\u6444\u50CF\u5934: ${err.message}`;
|
|
6602
|
-
setCameraError(errorMsg);
|
|
6603
|
-
onCameraError?.(err instanceof Error ? err : new Error(errorMsg));
|
|
6604
|
-
}
|
|
6605
|
-
}, [facingMode, cameraConfig, onCameraReady, onCameraError]);
|
|
6606
|
-
const stopCamera = React10.useCallback(() => {
|
|
6607
|
-
if (streamRef.current) {
|
|
6608
|
-
streamRef.current.getTracks().forEach((track) => track.stop());
|
|
6609
|
-
streamRef.current = null;
|
|
6501
|
+
if (modelRef.current) {
|
|
6502
|
+
modelRootRef.current.remove(modelRef.current);
|
|
6503
|
+
}
|
|
6504
|
+
const model = createModel(state.selectedModel);
|
|
6505
|
+
modelRef.current = model;
|
|
6506
|
+
modelRootRef.current.position.copy(markerRootRef.current.position);
|
|
6507
|
+
modelRootRef.current.quaternion.copy(markerRootRef.current.quaternion);
|
|
6508
|
+
modelRootRef.current.add(model);
|
|
6509
|
+
modelRootRef.current.visible = true;
|
|
6510
|
+
setState((prev) => ({ ...prev, modelPlaced: true }));
|
|
6511
|
+
console.log("Model placed successfully at marker position");
|
|
6512
|
+
} catch (error) {
|
|
6513
|
+
console.error("Failed to place model:", error);
|
|
6514
|
+
setState((prev) => ({ ...prev, error: "\u653E\u7F6E\u6A21\u578B\u5931\u8D25" }));
|
|
6610
6515
|
}
|
|
6611
|
-
|
|
6612
|
-
|
|
6516
|
+
}, [state.selectedModel, createModel]);
|
|
6517
|
+
const handleARSettingChange = React10.useCallback((setting, value) => {
|
|
6518
|
+
setState((prev) => ({ ...prev, [setting]: value }));
|
|
6519
|
+
if (setting === "cameraFacing" || setting === "markerType" || setting === "quality") {
|
|
6520
|
+
setTimeout(() => {
|
|
6521
|
+
alert("\u6B64\u8BBE\u7F6E\u53D8\u66F4\u9700\u8981\u91CD\u65B0\u542F\u52A8 AR \u7CFB\u7EDF\u3002\u8BF7\u5237\u65B0\u9875\u9762\u4EE5\u5E94\u7528\u65B0\u8BBE\u7F6E\u3002");
|
|
6522
|
+
}, 100);
|
|
6613
6523
|
}
|
|
6614
|
-
setIsCameraStarted(false);
|
|
6615
6524
|
}, []);
|
|
6616
|
-
const
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
const snapshot = React10.useCallback(async () => {
|
|
6621
|
-
if (!videoRef.current || !playerRef.current) return "";
|
|
6622
|
-
const canvas = document.createElement("canvas");
|
|
6623
|
-
const video = videoRef.current;
|
|
6624
|
-
canvas.width = video.videoWidth;
|
|
6625
|
-
canvas.height = video.videoHeight;
|
|
6626
|
-
const ctx = canvas.getContext("2d");
|
|
6627
|
-
if (!ctx) return "";
|
|
6628
|
-
if (shouldMirror) {
|
|
6629
|
-
ctx.translate(canvas.width, 0);
|
|
6630
|
-
ctx.scale(-1, 1);
|
|
6631
|
-
}
|
|
6632
|
-
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
6633
|
-
if (shouldMirror) {
|
|
6634
|
-
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
6635
|
-
}
|
|
6636
|
-
if (isModelPlaced) {
|
|
6637
|
-
const mmdBase64 = playerRef.current.snapshot();
|
|
6638
|
-
const mmdImg = new Image();
|
|
6639
|
-
mmdImg.src = mmdBase64;
|
|
6640
|
-
await new Promise((resolve) => {
|
|
6641
|
-
mmdImg.onload = () => {
|
|
6642
|
-
ctx.drawImage(mmdImg, 0, 0, canvas.width, canvas.height);
|
|
6643
|
-
resolve(null);
|
|
6644
|
-
};
|
|
6645
|
-
});
|
|
6525
|
+
const takePhoto = React10.useCallback(() => {
|
|
6526
|
+
if (!rendererRef.current || !sceneRef.current || !cameraRef.current) {
|
|
6527
|
+
console.error("Cannot take photo: missing required references");
|
|
6528
|
+
return;
|
|
6646
6529
|
}
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6530
|
+
try {
|
|
6531
|
+
const canvas = document.createElement("canvas");
|
|
6532
|
+
const context = canvas.getContext("2d");
|
|
6533
|
+
if (!context) {
|
|
6534
|
+
throw new Error("Cannot create canvas context");
|
|
6535
|
+
}
|
|
6536
|
+
canvas.width = width;
|
|
6537
|
+
canvas.height = height;
|
|
6538
|
+
rendererRef.current.render(sceneRef.current, cameraRef.current);
|
|
6539
|
+
const rendererCanvas = rendererRef.current.domElement;
|
|
6540
|
+
context.drawImage(rendererCanvas, 0, 0, width, height);
|
|
6541
|
+
if (arToolkitSourceRef.current && arToolkitSourceRef.current.domElement) {
|
|
6542
|
+
const videoElement = arToolkitSourceRef.current.domElement;
|
|
6543
|
+
context.globalCompositeOperation = "source-over";
|
|
6544
|
+
context.drawImage(videoElement, 0, 0, width, height);
|
|
6545
|
+
}
|
|
6546
|
+
canvas.toBlob((blob) => {
|
|
6547
|
+
if (blob) {
|
|
6548
|
+
const url = URL.createObjectURL(blob);
|
|
6549
|
+
const a = document.createElement("a");
|
|
6550
|
+
a.href = url;
|
|
6551
|
+
a.download = `ar-photo-${Date.now()}.png`;
|
|
6552
|
+
document.body.appendChild(a);
|
|
6553
|
+
a.click();
|
|
6554
|
+
document.body.removeChild(a);
|
|
6555
|
+
URL.revokeObjectURL(url);
|
|
6556
|
+
console.log("Photo saved successfully");
|
|
6557
|
+
}
|
|
6558
|
+
}, "image/png");
|
|
6559
|
+
} catch (error) {
|
|
6560
|
+
console.error("Failed to take photo:", error);
|
|
6561
|
+
setState((prev) => ({ ...prev, error: "\u62CD\u7167\u5931\u8D25" }));
|
|
6663
6562
|
}
|
|
6664
|
-
|
|
6665
|
-
|
|
6563
|
+
}, [width, height]);
|
|
6564
|
+
const initializeAR = React10.useCallback(async () => {
|
|
6565
|
+
try {
|
|
6566
|
+
console.log("Starting AR initialization...");
|
|
6567
|
+
if (!window.__arjs_ready) {
|
|
6568
|
+
console.log("Waiting for AR.js initialization...");
|
|
6569
|
+
await new Promise((resolve, reject) => {
|
|
6570
|
+
const check = setInterval(() => {
|
|
6571
|
+
if (window.__arjs_ready) {
|
|
6572
|
+
clearInterval(check);
|
|
6573
|
+
console.log("AR.js initialization complete!");
|
|
6574
|
+
resolve();
|
|
6575
|
+
}
|
|
6576
|
+
}, 50);
|
|
6577
|
+
setTimeout(() => {
|
|
6578
|
+
clearInterval(check);
|
|
6579
|
+
reject(new Error("AR.js initialization timeout"));
|
|
6580
|
+
}, 15e3);
|
|
6581
|
+
});
|
|
6582
|
+
}
|
|
6583
|
+
console.log("Getting THREEx...");
|
|
6584
|
+
const THREEx = window.THREEx;
|
|
6585
|
+
if (!THREEx) {
|
|
6586
|
+
console.error("THREEx not found, available window properties:", Object.keys(window).filter((key) => key.toLowerCase().includes("ar") || key.toLowerCase().includes("three")));
|
|
6587
|
+
throw new Error("THREEx not found after AR.js loaded");
|
|
6588
|
+
}
|
|
6589
|
+
console.log("THREEx loaded successfully:", Object.keys(THREEx));
|
|
6590
|
+
console.log("THREEx loaded, requesting camera permission...");
|
|
6591
|
+
const hasPermission = await requestCameraPermission();
|
|
6592
|
+
if (!hasPermission) {
|
|
6593
|
+
console.log("Camera permission denied");
|
|
6594
|
+
return false;
|
|
6595
|
+
}
|
|
6596
|
+
console.log("Camera permission granted, initializing AR Toolkit Source...");
|
|
6597
|
+
const arToolkitSource = new THREEx.ArToolkitSource({
|
|
6598
|
+
sourceType: "webcam",
|
|
6599
|
+
sourceWidth: width,
|
|
6600
|
+
sourceHeight: height,
|
|
6601
|
+
// 使用用户选择的摄像头朝向
|
|
6602
|
+
...state.cameraFacing && { facingMode: state.cameraFacing }
|
|
6603
|
+
});
|
|
6604
|
+
arToolkitSourceRef.current = arToolkitSource;
|
|
6605
|
+
const arToolkitContext = new THREEx.ArToolkitContext({
|
|
6606
|
+
cameraParametersUrl: "data/camera_para.dat",
|
|
6607
|
+
// 使用内建相机参数
|
|
6608
|
+
detectionMode: "mono",
|
|
6609
|
+
// 根据质量设置调整检测参数
|
|
6610
|
+
...state.quality && {
|
|
6611
|
+
maxDetectionRate: state.quality === "high" ? 60 : state.quality === "medium" ? 30 : 15
|
|
6612
|
+
}
|
|
6613
|
+
});
|
|
6614
|
+
arToolkitContextRef.current = arToolkitContext;
|
|
6615
|
+
arToolkitContext.init(() => {
|
|
6616
|
+
cameraRef.current.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
|
|
6617
|
+
const markerRoot = new THREE2__namespace.Group();
|
|
6618
|
+
sceneRef.current.add(markerRoot);
|
|
6619
|
+
markerRootRef.current = markerRoot;
|
|
6620
|
+
const markerGeometry = new THREE2__namespace.BoxGeometry(1, 1, 0.1);
|
|
6621
|
+
const markerMaterial = new THREE2__namespace.MeshBasicMaterial({
|
|
6622
|
+
color: 65280,
|
|
6623
|
+
transparent: true,
|
|
6624
|
+
opacity: 0.7,
|
|
6625
|
+
wireframe: state.showWireframe
|
|
6626
|
+
// 根据设置显示线框
|
|
6627
|
+
});
|
|
6628
|
+
const markerMesh = new THREE2__namespace.Mesh(markerGeometry, markerMaterial);
|
|
6629
|
+
markerMesh.position.set(0, 0, 0);
|
|
6630
|
+
markerRoot.add(markerMesh);
|
|
6631
|
+
if (!state.showWireframe) {
|
|
6632
|
+
const edges = new THREE2__namespace.EdgesGeometry(markerGeometry);
|
|
6633
|
+
const lineMaterial = new THREE2__namespace.LineBasicMaterial({ color: 16777215 });
|
|
6634
|
+
const wireframe = new THREE2__namespace.LineSegments(edges, lineMaterial);
|
|
6635
|
+
markerRoot.add(wireframe);
|
|
6636
|
+
}
|
|
6637
|
+
const markerControls = new THREEx.ArMarkerControls(arToolkitContext, markerRoot, {
|
|
6638
|
+
type: state.markerType,
|
|
6639
|
+
...state.markerType === "barcode" ? { barcodeValue: 0 } : { patternUrl: "data/patt.hiro" }
|
|
6640
|
+
});
|
|
6641
|
+
markerControlsRef.current = markerControls;
|
|
6642
|
+
if (state.lightingEnabled) {
|
|
6643
|
+
const ambientLight = new THREE2__namespace.AmbientLight(4210752, 0.6);
|
|
6644
|
+
sceneRef.current.add(ambientLight);
|
|
6645
|
+
const directionalLight = new THREE2__namespace.DirectionalLight(16777215, 0.8);
|
|
6646
|
+
directionalLight.position.set(1, 1, 1);
|
|
6647
|
+
sceneRef.current.add(directionalLight);
|
|
6648
|
+
}
|
|
6649
|
+
const modelRoot = new THREE2__namespace.Group();
|
|
6650
|
+
modelRoot.visible = false;
|
|
6651
|
+
sceneRef.current.add(modelRoot);
|
|
6652
|
+
modelRootRef.current = modelRoot;
|
|
6653
|
+
setState((prev) => ({
|
|
6654
|
+
...prev,
|
|
6655
|
+
arReady: true,
|
|
6656
|
+
isLoading: false
|
|
6657
|
+
}));
|
|
6658
|
+
onReady?.();
|
|
6659
|
+
console.log("AR.js and marker system initialized successfully");
|
|
6660
|
+
});
|
|
6661
|
+
arToolkitSource.init(() => {
|
|
6662
|
+
arToolkitSource.domElement.style.display = "none";
|
|
6663
|
+
setState((prev) => ({ ...prev, cameraReady: true }));
|
|
6664
|
+
console.log("Camera initialized successfully");
|
|
6665
|
+
});
|
|
6666
|
+
return true;
|
|
6667
|
+
} catch (error) {
|
|
6668
|
+
console.error("Failed to initialize AR.js:", error);
|
|
6669
|
+
const errorMessage = error instanceof Error ? error.message : "AR.js \u521D\u59CB\u5316\u5931\u8D25";
|
|
6670
|
+
setState((prev) => ({
|
|
6671
|
+
...prev,
|
|
6672
|
+
error: errorMessage,
|
|
6673
|
+
isLoading: false
|
|
6674
|
+
}));
|
|
6675
|
+
onError?.(errorMessage);
|
|
6676
|
+
return false;
|
|
6677
|
+
}
|
|
6678
|
+
}, [width, height, requestCameraPermission, onReady, onError]);
|
|
6679
|
+
const render = React10.useCallback(() => {
|
|
6680
|
+
if (!rendererRef.current || !sceneRef.current || !cameraRef.current) return;
|
|
6681
|
+
requestAnimationFrame(render);
|
|
6682
|
+
if (arToolkitSourceRef.current && arToolkitSourceRef.current.ready) {
|
|
6683
|
+
arToolkitContextRef.current.update(arToolkitSourceRef.current.domElement);
|
|
6684
|
+
if (markerRootRef.current && markerRootRef.current.visible !== state.markerDetected) {
|
|
6685
|
+
setState((prev) => ({ ...prev, markerDetected: markerRootRef.current.visible }));
|
|
6686
|
+
}
|
|
6687
|
+
}
|
|
6688
|
+
if (modelRef.current && state.modelPlaced) {
|
|
6689
|
+
modelRef.current.rotation.y += 0.01;
|
|
6690
|
+
}
|
|
6691
|
+
rendererRef.current.render(sceneRef.current, cameraRef.current);
|
|
6692
|
+
}, [state.markerDetected]);
|
|
6666
6693
|
React10.useEffect(() => {
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6694
|
+
const initialize = async () => {
|
|
6695
|
+
try {
|
|
6696
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
6697
|
+
if (!initializeThreeJS()) return;
|
|
6698
|
+
await initializeAR();
|
|
6699
|
+
if (window.DeviceOrientationEvent) {
|
|
6700
|
+
const handleOrientation = (event) => {
|
|
6701
|
+
gyroDataRef.current = {
|
|
6702
|
+
alpha: event.alpha || 0,
|
|
6703
|
+
beta: event.beta || 0,
|
|
6704
|
+
gamma: event.gamma || 0
|
|
6705
|
+
};
|
|
6706
|
+
if (state.modelPlaced && modelRef.current) {
|
|
6707
|
+
}
|
|
6708
|
+
};
|
|
6709
|
+
window.addEventListener("deviceorientation", handleOrientation);
|
|
6710
|
+
const cleanupGyro = () => {
|
|
6711
|
+
window.removeEventListener("deviceorientation", handleOrientation);
|
|
6712
|
+
};
|
|
6713
|
+
window.__gyroCleanup = cleanupGyro;
|
|
6714
|
+
}
|
|
6715
|
+
render();
|
|
6716
|
+
} catch (error) {
|
|
6717
|
+
console.error("Initialization failed:", error);
|
|
6718
|
+
setState((prev) => ({
|
|
6719
|
+
...prev,
|
|
6720
|
+
error: "\u7EC4\u4EF6\u521D\u59CB\u5316\u5931\u8D25",
|
|
6721
|
+
isLoading: false
|
|
6722
|
+
}));
|
|
6723
|
+
onError?.("\u7EC4\u4EF6\u521D\u59CB\u5316\u5931\u8D25");
|
|
6724
|
+
}
|
|
6675
6725
|
};
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
ref: containerRef,
|
|
6681
|
-
className: `relative w-full h-full bg-black overflow-hidden ${className}`,
|
|
6682
|
-
style
|
|
6683
|
-
},
|
|
6684
|
-
/* @__PURE__ */ React10__default.default.createElement(
|
|
6685
|
-
"video",
|
|
6686
|
-
{
|
|
6687
|
-
ref: videoRef,
|
|
6688
|
-
autoPlay: true,
|
|
6689
|
-
playsInline: true,
|
|
6690
|
-
muted: true,
|
|
6691
|
-
className: `absolute inset-0 w-full h-full object-cover transition-transform duration-500 ${shouldMirror ? "scale-x-[-1]" : ""}`,
|
|
6692
|
-
style: { zIndex: 0 }
|
|
6726
|
+
initialize();
|
|
6727
|
+
return () => {
|
|
6728
|
+
if (rendererRef.current) {
|
|
6729
|
+
rendererRef.current.dispose();
|
|
6693
6730
|
}
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
className: `absolute inset-0 w-full h-full transition-all duration-500 ${placementAnimation ? "scale-110 opacity-0" : "scale-100 opacity-100"}`,
|
|
6699
|
-
style: {
|
|
6700
|
-
zIndex: 1,
|
|
6701
|
-
...modelContainerStyle
|
|
6702
|
-
}
|
|
6703
|
-
},
|
|
6704
|
-
/* @__PURE__ */ React10__default.default.createElement(
|
|
6705
|
-
MMDPlayerBase,
|
|
6706
|
-
{
|
|
6707
|
-
key: `${selectedModelId}-${selectedMotionId}-${selectedAudioId}-${arMode}`,
|
|
6708
|
-
ref: playerRef,
|
|
6709
|
-
resources: currentResources,
|
|
6710
|
-
stage: {
|
|
6711
|
-
...stage,
|
|
6712
|
-
backgroundColor: "transparent",
|
|
6713
|
-
cameraPosition: stage.cameraPosition || { x: 0, y: 15, z: 40 }
|
|
6714
|
-
},
|
|
6715
|
-
mobileOptimization,
|
|
6716
|
-
autoPlay: true,
|
|
6717
|
-
loop,
|
|
6718
|
-
onLoad: () => {
|
|
6719
|
-
setIsLoading(false);
|
|
6720
|
-
onLoad?.();
|
|
6721
|
-
},
|
|
6722
|
-
onError
|
|
6731
|
+
if (arToolkitSourceRef.current) {
|
|
6732
|
+
if (arToolkitSourceRef.current.domElement?.srcObject) {
|
|
6733
|
+
const stream = arToolkitSourceRef.current.domElement.srcObject;
|
|
6734
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
6723
6735
|
}
|
|
6724
|
-
|
|
6725
|
-
),
|
|
6726
|
-
!isModelPlaced && isCameraStarted && /* @__PURE__ */ React10__default.default.createElement(
|
|
6727
|
-
"div",
|
|
6728
|
-
{
|
|
6729
|
-
className: "absolute inset-0 z-5 flex items-center justify-center",
|
|
6730
|
-
onClick: placeModel
|
|
6731
|
-
},
|
|
6732
|
-
/* @__PURE__ */ React10__default.default.createElement(
|
|
6733
|
-
"button",
|
|
6734
|
-
{
|
|
6735
|
-
onClick: placeModel,
|
|
6736
|
-
className: `
|
|
6737
|
-
relative group cursor-pointer
|
|
6738
|
-
transition-all duration-300 ease-out
|
|
6739
|
-
hover:scale-110 active:scale-95
|
|
6740
|
-
${placementAnimation ? "scale-150 opacity-0" : "scale-100 opacity-100"}
|
|
6741
|
-
`
|
|
6742
|
-
},
|
|
6743
|
-
/* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 -m-4 rounded-2xl bg-cyan-400/20 animate-ping" }),
|
|
6744
|
-
/* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 -m-2 rounded-xl bg-cyan-400/30 animate-pulse" }),
|
|
6745
|
-
/* @__PURE__ */ React10__default.default.createElement("div", { className: "relative bg-gradient-to-br from-cyan-400 via-blue-500 to-purple-600 p-1 rounded-2xl shadow-2xl shadow-cyan-500/50" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "bg-black/80 backdrop-blur-xl px-8 py-6 rounded-xl flex flex-col items-center gap-3" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Sparkles, { className: "w-10 h-10 text-cyan-400 animate-pulse" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 w-10 h-10 bg-cyan-400/30 blur-xl" })), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-2xl font-black text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-purple-400 tracking-widest" }, placementText), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-xs text-white/50 font-medium" }, arMode === "world-fixed" /* WorldFixed */ ? "\u70B9\u51FB\u653E\u7F6E\u5230\u4E16\u754C\u7A7A\u95F4 \u{1F30D}" : "\u70B9\u51FB\u53EC\u5524 Miku \u2728"))),
|
|
6746
|
-
/* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute -top-2 -right-2 w-4 h-4 bg-yellow-400 rounded-full animate-bounce shadow-lg shadow-yellow-400/50" }),
|
|
6747
|
-
/* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute -bottom-1 -left-1 w-3 h-3 bg-pink-400 rounded-full animate-bounce delay-100 shadow-lg shadow-pink-400/50" })
|
|
6748
|
-
)
|
|
6749
|
-
),
|
|
6750
|
-
/* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 z-10 pointer-events-none flex flex-col justify-between p-6" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex justify-between items-start pointer-events-auto" }, cameraError ? /* @__PURE__ */ React10__default.default.createElement("div", { className: "bg-red-500/80 backdrop-blur-md text-white px-4 py-2 rounded-full flex items-center gap-2 text-sm" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.AlertCircle, { className: "w-4 h-4" }), cameraError, /* @__PURE__ */ React10__default.default.createElement("button", { onClick: () => startCamera(), className: "ml-2 underline" }, "\u91CD\u8BD5")) : /* @__PURE__ */ React10__default.default.createElement("div", { className: `backdrop-blur-md text-white px-4 py-2 rounded-full flex items-center gap-2 text-sm ${arMode === "world-fixed" /* WorldFixed */ ? "bg-purple-500/40" : "bg-black/40"}` }, arMode === "world-fixed" /* WorldFixed */ ? /* @__PURE__ */ React10__default.default.createElement(lucideReact.Compass, { className: "w-4 h-4 text-purple-400" }) : /* @__PURE__ */ React10__default.default.createElement(lucideReact.Camera, { className: "w-4 h-4 text-green-400" }), isCameraStarted ? isModelPlaced ? arMode === "world-fixed" /* WorldFixed */ ? "\u4E16\u754C\u56FA\u5B9A AR" : "\u53E0\u52A0 AR \u6A21\u5F0F" : "\u70B9\u51FB\u653E\u7F6E\u6A21\u578B" : "\u7B49\u5F85\u6444\u50CF\u5934..."), /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex flex-col gap-2" }, showSettings && /* @__PURE__ */ React10__default.default.createElement(
|
|
6751
|
-
"button",
|
|
6752
|
-
{
|
|
6753
|
-
onClick: () => setIsSettingsOpen(!isSettingsOpen),
|
|
6754
|
-
className: `p-3 backdrop-blur-md rounded-full text-white transition-all active:scale-95 ${isSettingsOpen ? "bg-cyan-500" : "bg-white/10 hover:bg-white/20"}`
|
|
6755
|
-
},
|
|
6756
|
-
/* @__PURE__ */ React10__default.default.createElement(lucideReact.Settings, { className: "w-5 h-5" })
|
|
6757
|
-
), /* @__PURE__ */ React10__default.default.createElement(
|
|
6758
|
-
"button",
|
|
6759
|
-
{
|
|
6760
|
-
onClick: switchCamera,
|
|
6761
|
-
className: "p-3 bg-white/10 hover:bg-white/20 backdrop-blur-md rounded-full text-white transition-all active:scale-95"
|
|
6762
|
-
},
|
|
6763
|
-
/* @__PURE__ */ React10__default.default.createElement(lucideReact.RefreshCw, { className: "w-5 h-5" })
|
|
6764
|
-
), /* @__PURE__ */ React10__default.default.createElement(
|
|
6765
|
-
"button",
|
|
6766
|
-
{
|
|
6767
|
-
onClick: isCameraStarted ? stopCamera : () => startCamera(),
|
|
6768
|
-
className: `p-3 backdrop-blur-md rounded-full text-white transition-all active:scale-95 ${isCameraStarted ? "bg-red-500/20 hover:bg-red-500/40" : "bg-green-500/20 hover:bg-green-500/40"}`
|
|
6769
|
-
},
|
|
6770
|
-
isCameraStarted ? /* @__PURE__ */ React10__default.default.createElement(lucideReact.CameraOff, { className: "w-5 h-5" }) : /* @__PURE__ */ React10__default.default.createElement(lucideReact.Camera, { className: "w-5 h-5" })
|
|
6771
|
-
))), isSettingsOpen && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-20 right-6 w-72 max-h-[75vh] overflow-y-auto bg-black/90 backdrop-blur-xl border border-white/10 rounded-2xl p-5 pointer-events-auto shadow-2xl animate-in slide-in-from-right-4 duration-300" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "flex items-center justify-between mb-5" }, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "text-white font-bold flex items-center gap-2" }, /* @__PURE__ */ React10__default.default.createElement(lucideReact.Settings, { className: "w-4 h-4 text-cyan-400" }), "AR \u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement(
|
|
6772
|
-
"button",
|
|
6773
|
-
{
|
|
6774
|
-
onClick: () => setIsSettingsOpen(false),
|
|
6775
|
-
className: "p-1.5 hover:bg-white/10 rounded-full transition-colors text-white/60"
|
|
6776
|
-
},
|
|
6777
|
-
/* @__PURE__ */ React10__default.default.createElement(lucideReact.X, { className: "w-4 h-4" })
|
|
6778
|
-
)), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6779
|
-
ARModeSwitch,
|
|
6780
|
-
{
|
|
6781
|
-
mode: arMode,
|
|
6782
|
-
onChange: setARMode,
|
|
6783
|
-
gyroSupported
|
|
6736
|
+
arToolkitSourceRef.current.domElement?.remove();
|
|
6784
6737
|
}
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
{
|
|
6788
|
-
label: "\u9009\u62E9\u6A21\u578B",
|
|
6789
|
-
options: modelPresets,
|
|
6790
|
-
value: selectedModelId,
|
|
6791
|
-
onChange: setSelectedModelId
|
|
6738
|
+
if (window.__gyroCleanup) {
|
|
6739
|
+
window.__gyroCleanup();
|
|
6792
6740
|
}
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6741
|
+
};
|
|
6742
|
+
}, [initializeThreeJS, initializeAR, render, onError]);
|
|
6743
|
+
return /* @__PURE__ */ React10__default.default.createElement("div", { ref: containerRef, className: "relative w-full h-full bg-gray-900 overflow-hidden" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6744
|
+
Script__default.default,
|
|
6745
|
+
{
|
|
6746
|
+
src: "https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js",
|
|
6747
|
+
strategy: "afterInteractive",
|
|
6748
|
+
onLoad: () => {
|
|
6749
|
+
console.log("AR.js script loaded, checking THREEx...");
|
|
6750
|
+
const checkTHREEx = () => {
|
|
6751
|
+
if (window.THREEx) {
|
|
6752
|
+
console.log("THREEx found! Properties:", Object.keys(window.THREEx));
|
|
6753
|
+
window.__arjs_ready = true;
|
|
6754
|
+
console.log("AR.js and THREEx ready!");
|
|
6755
|
+
} else {
|
|
6756
|
+
console.log("THREEx not ready yet, checking window object:", Object.keys(window).filter((key) => key.includes("THREEx") || key.includes("AR")));
|
|
6757
|
+
setTimeout(checkTHREEx, 100);
|
|
6758
|
+
}
|
|
6759
|
+
};
|
|
6760
|
+
checkTHREEx();
|
|
6761
|
+
},
|
|
6762
|
+
onError: (error) => {
|
|
6763
|
+
console.error("Failed to load AR.js:", error);
|
|
6764
|
+
setState((prev) => ({
|
|
6765
|
+
...prev,
|
|
6766
|
+
error: "AR.js \u52A0\u8F7D\u5931\u8D25",
|
|
6767
|
+
isLoading: false
|
|
6768
|
+
}));
|
|
6800
6769
|
}
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6770
|
+
}
|
|
6771
|
+
), /* @__PURE__ */ React10__default.default.createElement(
|
|
6772
|
+
"canvas",
|
|
6773
|
+
{
|
|
6774
|
+
ref: canvasRef,
|
|
6775
|
+
className: "absolute inset-0 w-full h-full",
|
|
6776
|
+
style: { display: state.arReady ? "block" : "none" }
|
|
6777
|
+
}
|
|
6778
|
+
), state.isLoading && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center bg-gray-900 text-white" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-white mx-auto mb-4" }), /* @__PURE__ */ React10__default.default.createElement("p", null, "\u6B63\u5728\u521D\u59CB\u5316 AR \u73AF\u5883..."))), state.error && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute inset-0 flex items-center justify-center bg-red-900 text-white" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "text-center max-w-md" }, /* @__PURE__ */ React10__default.default.createElement("h2", { className: "text-xl font-bold mb-4" }, "\u521D\u59CB\u5316\u5931\u8D25"), /* @__PURE__ */ React10__default.default.createElement("p", { className: "text-red-200 mb-4" }, state.error), /* @__PURE__ */ React10__default.default.createElement(
|
|
6779
|
+
"button",
|
|
6780
|
+
{
|
|
6781
|
+
onClick: () => window.location.reload(),
|
|
6782
|
+
className: "px-4 py-2 bg-red-600 hover:bg-red-700 rounded-lg transition-colors"
|
|
6783
|
+
},
|
|
6784
|
+
"\u91CD\u65B0\u52A0\u8F7D"
|
|
6785
|
+
))), state.arReady && !state.error && /* @__PURE__ */ React10__default.default.createElement(React10__default.default.Fragment, null, !state.modelPlaced && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 left-4 right-4 bg-black/70 text-white p-4 rounded-lg" }, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "font-bold mb-2" }, "AR \u653E\u7F6E\u8BF4\u660E"), /* @__PURE__ */ React10__default.default.createElement("p", { className: "text-sm text-gray-300" }, "1. \u5141\u8BB8\u6444\u50CF\u5934\u8BBF\u95EE\u6743\u9650", /* @__PURE__ */ React10__default.default.createElement("br", null), "2. \u51C6\u5907\u4E00\u4E2A\u6761\u7801\u6807\u8BB0 (\u503C: 0) \u6216 Hiro \u6807\u8BB0\u56FE\u6848", /* @__PURE__ */ React10__default.default.createElement("br", null), "3. \u5C06\u6444\u50CF\u5934\u5BF9\u51C6\u6807\u8BB0\uFF0C\u7EFF\u8272\u7ACB\u65B9\u4F53\u5C06\u51FA\u73B0\u5728\u6807\u8BB0\u4F4D\u7F6E", /* @__PURE__ */ React10__default.default.createElement("br", null), state.markerDetected ? /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-green-400 font-bold" }, "\u2713 \u6807\u8BB0\u5DF2\u68C0\u6D4B\u5230\uFF01") : /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-yellow-400" }, "\u7B49\u5F85\u6807\u8BB0\u68C0\u6D4B..."), /* @__PURE__ */ React10__default.default.createElement("br", null), '4. \u70B9\u51FB"\u653E\u7F6E\u6A21\u578B"\u6309\u94AE\u56FA\u5B9A\u6A21\u578B\u4F4D\u7F6E')), state.showSettings && /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 right-4 bg-black/90 text-white p-4 rounded-lg min-w-80 max-w-sm max-h-96 overflow-y-auto" }, /* @__PURE__ */ React10__default.default.createElement("h3", { className: "font-bold mb-4 text-lg" }, "\u2699\uFE0F \u8BBE\u7F6E\u9762\u677F"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-blue-300" }, "\u{1F4F7} \u6444\u50CF\u5934\u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u6444\u50CF\u5934\u671D\u5411"), /* @__PURE__ */ React10__default.default.createElement(
|
|
6786
|
+
"select",
|
|
6787
|
+
{
|
|
6788
|
+
value: state.cameraFacing,
|
|
6789
|
+
onChange: (e) => handleARSettingChange("cameraFacing", e.target.value),
|
|
6790
|
+
className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
|
|
6791
|
+
},
|
|
6792
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "environment" }, "\u540E\u7F6E\u6444\u50CF\u5934"),
|
|
6793
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "user" }, "\u524D\u7F6E\u6444\u50CF\u5934")
|
|
6794
|
+
))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-green-300" }, "\u{1F3AF} AR \u68C0\u6D4B\u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u6807\u8BB0\u7C7B\u578B"), /* @__PURE__ */ React10__default.default.createElement(
|
|
6795
|
+
"select",
|
|
6796
|
+
{
|
|
6797
|
+
value: state.markerType,
|
|
6798
|
+
onChange: (e) => handleARSettingChange("markerType", e.target.value),
|
|
6799
|
+
className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
|
|
6800
|
+
},
|
|
6801
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "barcode" }, "\u6761\u7801 (Barcode)"),
|
|
6802
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "pattern" }, "\u56FE\u6848 (Hiro)")
|
|
6803
|
+
)), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u68C0\u6D4B\u8D28\u91CF"), /* @__PURE__ */ React10__default.default.createElement(
|
|
6804
|
+
"select",
|
|
6805
|
+
{
|
|
6806
|
+
value: state.quality,
|
|
6807
|
+
onChange: (e) => handleARSettingChange("quality", e.target.value),
|
|
6808
|
+
className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
|
|
6809
|
+
},
|
|
6810
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "low" }, "\u4F4E\u8D28\u91CF (15fps)"),
|
|
6811
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "medium" }, "\u4E2D\u7B49\u8D28\u91CF (30fps)"),
|
|
6812
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "high" }, "\u9AD8\u8D28\u91CF (60fps)")
|
|
6813
|
+
)))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-purple-300" }, "\u{1F441}\uFE0F \u89C6\u89C9\u8BBE\u7F6E"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement("label", { className: "flex items-center" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6814
|
+
"input",
|
|
6815
|
+
{
|
|
6816
|
+
type: "checkbox",
|
|
6817
|
+
checked: state.showWireframe,
|
|
6818
|
+
onChange: (e) => setState((prev) => ({ ...prev, showWireframe: e.target.checked })),
|
|
6819
|
+
className: "mr-2"
|
|
6820
|
+
}
|
|
6821
|
+
), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-sm" }, "\u663E\u793A\u7EBF\u6846")), /* @__PURE__ */ React10__default.default.createElement("label", { className: "flex items-center" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6822
|
+
"input",
|
|
6823
|
+
{
|
|
6824
|
+
type: "checkbox",
|
|
6825
|
+
checked: state.lightingEnabled,
|
|
6826
|
+
onChange: (e) => setState((prev) => ({ ...prev, lightingEnabled: e.target.checked })),
|
|
6827
|
+
className: "mr-2"
|
|
6828
|
+
}
|
|
6829
|
+
), /* @__PURE__ */ React10__default.default.createElement("span", { className: "text-sm" }, "\u542F\u7528\u5149\u7167")))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "border-b border-gray-600 pb-3" }, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-orange-300" }, "\u{1F3AD} \u6A21\u578B\u4E0E\u52A8\u753B"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u6A21\u578B\u9009\u62E9"), /* @__PURE__ */ React10__default.default.createElement(
|
|
6830
|
+
"select",
|
|
6831
|
+
{
|
|
6832
|
+
value: state.selectedModel,
|
|
6833
|
+
onChange: (e) => setState((prev) => ({ ...prev, selectedModel: e.target.value })),
|
|
6834
|
+
className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
|
|
6835
|
+
},
|
|
6836
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "sphere" }, "\u{1F310} \u7403\u4F53"),
|
|
6837
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "cube" }, "\u2B1C \u7ACB\u65B9\u4F53"),
|
|
6838
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "torus" }, "\u2B55 \u5706\u73AF")
|
|
6839
|
+
)), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u52A8\u4F5C\u9009\u62E9"), /* @__PURE__ */ React10__default.default.createElement(
|
|
6840
|
+
"select",
|
|
6841
|
+
{
|
|
6842
|
+
value: state.selectedMotion,
|
|
6843
|
+
onChange: (e) => setState((prev) => ({ ...prev, selectedMotion: e.target.value })),
|
|
6844
|
+
className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
|
|
6845
|
+
},
|
|
6846
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "idle" }, "\u{1F9D8} \u5F85\u673A"),
|
|
6847
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "dance" }, "\u{1F483} \u821E\u8E48"),
|
|
6848
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "wave" }, "\u{1F44B} \u6325\u624B")
|
|
6849
|
+
)), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("label", { className: "block text-sm font-medium mb-1" }, "\u97F3\u4E50\u9009\u62E9"), /* @__PURE__ */ React10__default.default.createElement(
|
|
6850
|
+
"select",
|
|
6851
|
+
{
|
|
6852
|
+
value: state.selectedAudio,
|
|
6853
|
+
onChange: (e) => setState((prev) => ({ ...prev, selectedAudio: e.target.value })),
|
|
6854
|
+
className: "w-full px-3 py-2 bg-gray-700 rounded border border-gray-600 text-sm"
|
|
6855
|
+
},
|
|
6856
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "none" }, "\u{1F507} \u65E0\u97F3\u4E50"),
|
|
6857
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "bgm1" }, "\u{1F3B5} \u80CC\u666F\u97F3\u4E50 1"),
|
|
6858
|
+
/* @__PURE__ */ React10__default.default.createElement("option", { value: "bgm2" }, "\u{1F3B6} \u80CC\u666F\u97F3\u4E50 2")
|
|
6859
|
+
)))), /* @__PURE__ */ React10__default.default.createElement("div", null, /* @__PURE__ */ React10__default.default.createElement("h4", { className: "font-semibold mb-2 text-red-300" }, "\u{1F3AE} \u63A7\u5236\u64CD\u4F5C"), /* @__PURE__ */ React10__default.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6860
|
+
"button",
|
|
6861
|
+
{
|
|
6862
|
+
onClick: () => {
|
|
6863
|
+
if (modelRootRef.current) {
|
|
6864
|
+
modelRootRef.current.visible = false;
|
|
6865
|
+
}
|
|
6866
|
+
if (markerRootRef.current) {
|
|
6867
|
+
markerRootRef.current.visible = true;
|
|
6868
|
+
}
|
|
6869
|
+
setState((prev) => ({ ...prev, modelPlaced: false, markerDetected: false }));
|
|
6816
6870
|
},
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6871
|
+
className: "w-full px-3 py-2 bg-blue-600 hover:bg-blue-700 rounded transition-colors text-sm"
|
|
6872
|
+
},
|
|
6873
|
+
"\u{1F504} \u91CD\u65B0\u8BBE\u7F6E\u6807\u8BB0\u70B9"
|
|
6874
|
+
), /* @__PURE__ */ React10__default.default.createElement(
|
|
6875
|
+
"button",
|
|
6876
|
+
{
|
|
6877
|
+
onClick: () => {
|
|
6878
|
+
if (modelRootRef.current) {
|
|
6879
|
+
modelRootRef.current.clear();
|
|
6880
|
+
modelRootRef.current.visible = false;
|
|
6881
|
+
}
|
|
6882
|
+
if (markerRootRef.current) {
|
|
6883
|
+
markerRootRef.current.visible = true;
|
|
6884
|
+
}
|
|
6885
|
+
setState((prev) => ({
|
|
6886
|
+
...prev,
|
|
6887
|
+
modelPlaced: false,
|
|
6888
|
+
markerDetected: false,
|
|
6889
|
+
selectedModel: "sphere",
|
|
6890
|
+
selectedMotion: "idle",
|
|
6891
|
+
selectedAudio: "none"
|
|
6892
|
+
}));
|
|
6824
6893
|
},
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
)
|
|
6894
|
+
className: "w-full px-3 py-2 bg-red-600 hover:bg-red-700 rounded transition-colors text-sm"
|
|
6895
|
+
},
|
|
6896
|
+
"\u{1F5D1}\uFE0F \u6E05\u9664\u6240\u6709"
|
|
6897
|
+
))))), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute bottom-4 left-4 right-4 flex justify-center space-x-4" }, /* @__PURE__ */ React10__default.default.createElement(
|
|
6898
|
+
"button",
|
|
6899
|
+
{
|
|
6900
|
+
onClick: () => setState((prev) => ({ ...prev, showSettings: !prev.showSettings })),
|
|
6901
|
+
className: "px-4 py-2 bg-gray-700 hover:bg-gray-600 text-white rounded-lg transition-colors"
|
|
6902
|
+
},
|
|
6903
|
+
"\u2699\uFE0F \u8BBE\u7F6E"
|
|
6904
|
+
), !state.modelPlaced && /* @__PURE__ */ React10__default.default.createElement(
|
|
6905
|
+
"button",
|
|
6906
|
+
{
|
|
6907
|
+
onClick: placeModel,
|
|
6908
|
+
disabled: !state.markerDetected,
|
|
6909
|
+
className: `px-6 py-2 rounded-lg transition-colors ${state.markerDetected ? "bg-green-600 hover:bg-green-700 text-white" : "bg-gray-500 text-gray-300 cursor-not-allowed"}`
|
|
6910
|
+
},
|
|
6911
|
+
"\u{1F4CD} \u653E\u7F6E\u6A21\u578B"
|
|
6912
|
+
), state.modelPlaced && /* @__PURE__ */ React10__default.default.createElement(
|
|
6913
|
+
"button",
|
|
6914
|
+
{
|
|
6915
|
+
onClick: takePhoto,
|
|
6916
|
+
className: "px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
|
6917
|
+
},
|
|
6918
|
+
"\u{1F4F8} \u62CD\u7167"
|
|
6919
|
+
)), /* @__PURE__ */ React10__default.default.createElement("div", { className: "absolute top-4 right-4 flex space-x-2" }, /* @__PURE__ */ React10__default.default.createElement("div", { className: `w-3 h-3 rounded-full ${state.cameraReady ? "bg-green-400" : "bg-red-400"}`, title: "\u6444\u50CF\u5934" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: `w-3 h-3 rounded-full ${state.arReady ? "bg-green-400" : "bg-red-400"}`, title: "AR" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: `w-3 h-3 rounded-full ${window.DeviceOrientationEvent ? "bg-purple-400" : "bg-gray-400"}`, title: "\u9640\u87BA\u4EEA" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: `w-3 h-3 rounded-full ${state.markerDetected ? "bg-blue-400" : "bg-gray-400"}`, title: "\u6807\u8BB0\u68C0\u6D4B" }), /* @__PURE__ */ React10__default.default.createElement("div", { className: `w-3 h-3 rounded-full ${state.modelPlaced && modelRootRef.current?.visible ? "bg-green-400" : "bg-yellow-400"}`, title: "\u6A21\u578B" }))));
|
|
6829
6920
|
});
|
|
6830
6921
|
MMDARPlayer.displayName = "MMDARPlayer";
|
|
6831
6922
|
|
|
6923
|
+
// src/mmd/ar/types.ts
|
|
6924
|
+
var ARMode = /* @__PURE__ */ ((ARMode2) => {
|
|
6925
|
+
ARMode2["Overlay"] = "overlay";
|
|
6926
|
+
ARMode2["WorldFixed"] = "world-fixed";
|
|
6927
|
+
return ARMode2;
|
|
6928
|
+
})(ARMode || {});
|
|
6929
|
+
|
|
6832
6930
|
// src/mmd/fx/HLSLToGLSLConverter.ts
|
|
6833
6931
|
var HLSLToGLSLConverter = class {
|
|
6834
6932
|
constructor() {
|