Ai_Assistant/client/_archive/index-VR.html
2026-05-24 13:31:30 +02:00

277 lines
8.8 KiB
HTML

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>VRM AI - WebXR</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Oxygen, Ubuntu, sans-serif;
background-color: #1a1a2e;
color: #eee;
overflow: hidden;
}
canvas {
display: block;
}
/* VR Button Styling Override */
#VRButton {
font-family: inherit !important;
font-weight: 600 !important;
letter-spacing: 0.5px !important;
border-radius: 8px !important;
transition: all 0.3s ease !important;
}
#VRButton:hover {
transform: translateX(-50%) scale(1.05) !important;
box-shadow: 0 4px 20px rgba(0, 150, 255, 0.4) !important;
}
/* Status Overlay */
#status-overlay {
position: fixed;
top: 10px;
left: 10px;
z-index: 1000;
background: rgba(0, 0, 0, 0.7);
padding: 10px 15px;
border-radius: 8px;
font-size: 12px;
pointer-events: none;
opacity: 0.8;
transition: opacity 0.3s;
}
#status-overlay:hover {
opacity: 1;
}
#status-overlay .status-item {
display: flex;
align-items: center;
margin: 4px 0;
}
#status-overlay .status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 8px;
}
#status-overlay .status-dot.connected {
background: #4caf50;
box-shadow: 0 0 6px #4caf50;
}
#status-overlay .status-dot.disconnected {
background: #f44336;
box-shadow: 0 0 6px #f44336;
}
#status-overlay .status-dot.recording {
background: #ff5722;
box-shadow: 0 0 6px #ff5722;
animation: pulse 0.8s infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
/* Instructions Panel */
#instructions {
position: fixed;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
z-index: 999;
background: rgba(0, 0, 0, 0.8);
padding: 15px 25px;
border-radius: 10px;
text-align: center;
font-size: 13px;
max-width: 400px;
opacity: 0.9;
transition: opacity 0.3s;
}
#instructions h3 {
margin: 0 0 10px 0;
font-size: 15px;
color: #64b5f6;
}
#instructions p {
margin: 5px 0;
line-height: 1.4;
}
#instructions .key {
display: inline-block;
background: #333;
padding: 2px 8px;
border-radius: 4px;
font-family: monospace;
margin: 0 2px;
}
/* Hide instructions when in VR (body gets class) */
body.vr-active #instructions,
body.vr-active #status-overlay {
display: none;
}
/* Loading Screen */
#loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #1a1a2e;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 2000;
transition: opacity 0.5s;
}
#loading.hidden {
opacity: 0;
pointer-events: none;
}
#loading .spinner {
width: 50px;
height: 50px;
border: 3px solid #333;
border-top-color: #64b5f6;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
#loading p {
margin-top: 20px;
font-size: 14px;
color: #888;
}
</style>
</head>
<body>
<!-- Loading Screen -->
<div id="loading">
<div class="spinner"></div>
<p>Loading VRM Model...</p>
</div>
<!-- Status Overlay -->
<div id="status-overlay">
<div class="status-item">
<span class="status-dot disconnected" id="ws-status"></span>
<span id="ws-text">WebSocket: Connecting...</span>
</div>
<div class="status-item">
<span class="status-dot disconnected" id="mic-status"></span>
<span id="mic-text">Microphone: Ready</span>
</div>
</div>
<!-- Instructions Panel -->
<div id="instructions">
<h3>🎮 VR Controls</h3>
<p></p>
<span class="key">Grip Button</span> Hold to talk (Push-to-Talk)
</p>
<p><span class="key">Trigger</span> Interact / Point</p>
<p>Click "Enter VR" to start your session</p>
</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/",
"@pixiv/three-vrm": "https://cdn.jsdelivr.net/npm/@pixiv/three-vrm@3.4.1/lib/three-vrm.module.js",
"@pixiv/three-vrm-animation": "https://cdn.jsdelivr.net/npm/@pixiv/three-vrm-animation@3.4.1/lib/three-vrm-animation.module.js"
}
}
</script>
<script type="module" src="./main-VR.js"></script>
<script>
// Simple status updates from main-VR.js events
window.addEventListener("vrm-loaded", () => {
document.getElementById("loading").classList.add("hidden");
});
window.addEventListener("ws-connected", () => {
document.getElementById("ws-status").className =
"status-dot connected";
document.getElementById("ws-text").textContent =
"WebSocket: Connected";
});
window.addEventListener("ws-disconnected", () => {
document.getElementById("ws-status").className =
"status-dot disconnected";
document.getElementById("ws-text").textContent =
"WebSocket: Disconnected";
});
window.addEventListener("recording-start", () => {
document.getElementById("mic-status").className =
"status-dot recording";
document.getElementById("mic-text").textContent =
"Microphone: Recording...";
});
window.addEventListener("recording-stop", () => {
document.getElementById("mic-status").className =
"status-dot connected";
document.getElementById("mic-text").textContent =
"Microphone: Ready";
});
// Handle VR session state
if (navigator.xr) {
navigator.xr
.isSessionSupported("immersive-vr")
.then((supported) => {
if (!supported) {
document.getElementById("instructions").innerHTML =
"<h3>⚠️ VR Not Supported</h3><p>WebXR is not available on this device/browser.</p><p>Try using a VR headset or compatible browser.</p>";
}
});
}
</script>
</body>
</html>