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