"use client"; /* eslint-disable @next/next/no-img-element */ import dynamic from "next/dynamic"; import { Box, Download, Loader2, RotateCcw } from "lucide-react"; import { useMemo, useState } from "react"; import { buildOpenClawArtifactProxyUrl, isOpenClawInteractive3DArtifact, type OpenClawArtifact, } from "@/lib/openclaw-chat/artifacts"; const Model3DViewer = dynamic( () => import("@/components/canvas/model3d/Model3DViewer").then( (module) => module.Model3DViewer ), { ssr: false, loading: () => (
), } ); function supportsWebGl() { try { const canvas = document.createElement("canvas"); return Boolean( canvas.getContext("webgl2") || canvas.getContext("webgl") || canvas.getContext("experimental-webgl") ); } catch { return false; } } export function OpenClawModel3DPreview({ artifacts, chatId, messageId, }: { artifacts: OpenClawArtifact[]; chatId: string; messageId: string; }) { const modelIndex = useMemo( () => artifacts.findIndex(isOpenClawInteractive3DArtifact), [artifacts] ); const model = modelIndex >= 0 ? artifacts[modelIndex] : null; const fallbackRole = model?.viewer?.fallbackArtifactRole || "cad_preview"; const previewIndex = artifacts.findIndex( (artifact) => artifact.artifactRole === fallbackRole ); const [isActive, setIsActive] = useState(false); const [webGlUnavailable, setWebGlUnavailable] = useState(false); const [resetViewToken, setResetViewToken] = useState(0); if (!model) return null; const modelUrl = buildOpenClawArtifactProxyUrl({ chatId, messageId, artifactIndex: modelIndex, }); const downloadUrl = buildOpenClawArtifactProxyUrl({ chatId, messageId, artifactIndex: modelIndex, download: true, }); const previewUrl = previewIndex >= 0 ? buildOpenClawArtifactProxyUrl({ chatId, messageId, artifactIndex: previewIndex, }) : null; const activateViewer = () => { if (!supportsWebGl()) { setWebGlUnavailable(true); return; } setWebGlUnavailable(false); setIsActive(true); }; return (
{model.displayName || model.filename || "3D 模型"} {model.viewer?.format || "glb"}
{isActive ? ( ) : null}
{isActive ? ( ) : (
{previewUrl ? ( {`${model.displayName ) : ( )}
)}
{webGlUnavailable ? (

当前浏览器无法启动3D预览,已保留静态预览和模型下载。

) : null}
); }