<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>フルダイブVR - 仮想世界体験</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
.vr-container {
width: 95vw;
height: 95vh;
background: #000;
border-radius: 20px;
position: relative;
overflow: hidden;
box-shadow: 0 20px 50px rgba(0,0,0,0.3);
}
.boot-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, #0f0f23, #1a1a2e);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 100;
transition: opacity 1s ease-out;
}
.boot-screen.hidden {
opacity: 0;
pointer-events: none;
}
.logo {
font-size: 3rem;
color: #00d4ff;
margin-bottom: 30px;
text-shadow: 0 0 20px #00d4ff;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.loading-bar {
width: 300px;
height: 4px;
background: #333;
border-radius: 2px;
overflow: hidden;
margin-bottom: 20px;
}
.loading-progress {
height: 100%;
background: linear-gradient(90deg, #00d4ff, #ff006e);
width: 0%;
animation: loading 3s ease-out forwards;
}
@keyframes loading {
to { width: 100%; }
}
.boot-text {
color: #00d4ff;
font-size: 1.2rem;
margin-top: 20px;
}
#canvas {
width: 100%;
height: 100%;
display: block;
}
.hud {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 10;
}
.status-panel {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 212, 255, 0.1);
border: 1px solid #00d4ff;
border-radius: 10px;
padding: 15px;
color: #00d4ff;
font-family: 'Courier New', monospace;
backdrop-filter: blur(10px);
}
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 15px;
pointer-events: all;
}
.control-btn {
background: rgba(0, 212, 255, 0.2);
border: 2px solid #00d4ff;
color: #00d4ff;
padding: 12px 20px;
border-radius: 25px;
cursor: pointer;
font-size: 14px;
font-weight: bold;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.control-btn:hover {
background: rgba(0, 212, 255, 0.4);
box-shadow: 0 0 20px rgba(0, 212, 255, 0.5);
transform: translateY(-2px);
}
.neural-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle at center, transparent 30%, rgba(0, 212, 255, 0.05) 100%);
pointer-events: none;
z-index: 5;
}
.dive-complete {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #00d4ff;
font-size: 2rem;
text-align: center;
opacity: 0;
animation: fadeInOut 4s ease-in-out;
z-index: 50;
text-shadow: 0 0 20px #00d4ff;
}
@keyframes fadeInOut {
0%, 100% { opacity: 0; }
20%, 80% { opacity: 1; }
}
</style>
</head>
<body>
<div class="vr-container">
<div class="boot-screen" id="bootScreen">
<div class="logo">NeuroLink VR</div>
<div class="loading-bar">
<div class="loading-progress"></div>
</div>
<div class="boot-text">Neural Interface Initializing...</div>
</div>
<canvas id="canvas"></canvas>
<div class="neural-overlay"></div>
<div class="hud">
<div class="status-panel">
<div>Neural Sync: <span id="sync">98.7%</span></div>
<div>Reality Index: <span id="reality">VIRTUAL</span></div>
<div>Immersion Level: <span id="immersion">MAXIMUM</span></div>
<div>Connected Users: <span id="users">1,247</span></div>
</div>
</div>
<div class="controls">
<button class="control-btn" onclick="changeWorld('cyber')">サイバー都市</button>
<button class="control-btn" onclick="changeWorld('forest')">森林世界</button>
<button class="control-btn" onclick="changeWorld('space')">宇宙ステーション</button>
<button class="control-btn" onclick="disconnect()">ログアウト</button>
</div>
<div class="dive-complete" id="diveComplete">
フルダイブ完了<br>
<small>仮想世界へようこそ</small>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
let scene, camera, renderer, world = 'cyber';
let particles = [];
let buildings = [];
let stars = [];
let trees = [];
// 起動シーケンス
setTimeout(() => {
document.getElementById('bootScreen').classList.add('hidden');
initVR();
setTimeout(() => {
document.getElementById('diveComplete').style.display = 'block';
}, 1000);
}, 3500);
function initVR() {
// Three.js セットアップ
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('canvas'), antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x000011);
// 初期世界を構築
buildCyberWorld();
// カメラ位置
camera.position.set(0, 5, 10);
// アニメーションループ
animate();
// HUD更新
updateHUD();
}
function buildCyberWorld() {
// クリア
clearWorld();
scene.fog = new THREE.Fog(0x000033, 10, 100);
// ネオンビル群
for (let i = 0; i < 50; i++) {
const height = Math.random() * 20 + 5;
const geometry = new THREE.BoxGeometry(
Math.random() * 3 + 1,
height,
Math.random() * 3 + 1
);
const material = new THREE.MeshBasicMaterial({
color: Math.random() > 0.5 ? 0x00ffff : 0xff00ff,
transparent: true,
opacity: 0.8
});
const building = new THREE.Mesh(geometry, material);
building.position.set(
(Math.random() - 0.5) * 100,
height / 2,
(Math.random() - 0.5) * 100
);
scene.add(building);
buildings.push(building);
}
// パーティクル効果
createParticles(0x00ffff);
// 地面
const floorGeometry = new THREE.PlaneGeometry(200, 200);
const floorMaterial = new THREE.MeshBasicMaterial({
color: 0x001122,
transparent: true,
opacity: 0.5
});
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);
}
function buildForestWorld() {
clearWorld();
scene.fog = new THREE.Fog(0x228B22, 5, 50);
// 木々
for (let i = 0; i < 100; i++) {
// 幹
const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, 8);
const trunkMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
// 葉
const leavesGeometry = new THREE.SphereGeometry(3);
const leavesMaterial = new THREE.MeshBasicMaterial({ color: 0x228B22 });
const leaves = new THREE.Mesh(leavesGeometry, leavesMaterial);
leaves.position.y = 6;
const tree = new THREE.Group();
tree.add(trunk);
tree.add(leaves);
tree.position.set(
(Math.random() - 0.5) * 80,
4,
(Math.random() - 0.5) * 80
);
scene.add(tree);
trees.push(tree);
}
createParticles(0x90EE90);
// 地面
const floorGeometry = new THREE.PlaneGeometry(200, 200);
const floorMaterial = new THREE.MeshBasicMaterial({ color: 0x2F4F2F });
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI / 2;
scene.add(floor);
}
function buildSpaceWorld() {
clearWorld();
scene.fog = null;
renderer.setClearColor(0x000000);
// 星々
for (let i = 0; i < 1000; i++) {
const starGeometry = new THREE.SphereGeometry(0.1);
const starMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
const star = new THREE.Mesh(starGeometry, starMaterial);
star.position.set(
(Math.random() - 0.5) * 200,
(Math.random() - 0.5) * 200,
(Math.random() - 0.5) * 200
);
scene.add(star);
stars.push(star);
}
// 宇宙ステーション
const stationGeometry = new THREE.TorusGeometry(10, 3, 8, 20);
const stationMaterial = new THREE.MeshBasicMaterial({
color: 0x888888,
wireframe: true
});
const station = new THREE.Mesh(stationGeometry, stationMaterial);
station.position.set(0, 0, -20);
scene.add(station);
createParticles(0xffffff);
}
function createParticles(color) {
for (let i = 0; i < 200; i++) {
const particleGeometry = new THREE.SphereGeometry(0.05);
const particleMaterial = new THREE.MeshBasicMaterial({
color: color,
transparent: true,
opacity: 0.6
});
const particle = new THREE.Mesh(particleGeometry, particleMaterial);
particle.position.set(
(Math.random() - 0.5) * 50,
Math.random() * 20,
(Math.random() - 0.5) * 50
);
particle.velocity = {
x: (Math.random() - 0.5) * 0.02,
y: Math.random() * 0.01,
z: (Math.random() - 0.5) * 0.02
};
scene.add(particle);
particles.push(particle);
}
}
function clearWorld() {
buildings.forEach(b => scene.remove(b));
trees.forEach(t => scene.remove(t));
stars.forEach(s => scene.remove(s));
particles.forEach(p => scene.remove(p));
buildings = [];
trees = [];
stars = [];
particles = [];
// シーン全体をクリア
while(scene.children.length > 0) {
scene.remove(scene.children[0]);
}
}
function animate() {
requestAnimationFrame(animate);
// カメラの自動回転
const time = Date.now() * 0.0005;
camera.position.x = Math.cos(time) * 20;
camera.position.z = Math.sin(time) * 20;
camera.lookAt(scene.position);
// パーティクルアニメーション
particles.forEach(particle => {
particle.position.add(particle.velocity);
if (particle.position.y > 25) {
particle.position.y = -5;
}
if (particle.position.x > 25) particle.position.x = -25;
if (particle.position.x < -25) particle.position.x = 25;
if (particle.position.z > 25) particle.position.z = -25;
if (particle.position.z < -25) particle.position.z = 25;
});
// ビルの光る効果
buildings.forEach(building => {
if (Math.random() > 0.98) {
building.material.opacity = Math.random() * 0.5 + 0.5;
}
});
renderer.render(scene, camera);
}
function changeWorld(newWorld) {
world = newWorld;
switch(world) {
case 'cyber':
buildCyberWorld();
break;
case 'forest':
buildForestWorld();
break;
case 'space':
buildSpaceWorld();
break;
}
}
function updateHUD() {
setInterval(() => {
document.getElementById('sync').textContent = (98 + Math.random() * 2).toFixed(1) + '%';
document.getElementById('users').textContent = (1200 + Math.floor(Math.random() * 100)).toLocaleString();
}, 2000);
}
function disconnect() {
document.querySelector('.vr-container').style.opacity = '0';
setTimeout(() => {
document.body.innerHTML = `
<div style="display: flex; justify-content: center; align-items: center; height: 100vh; color: #00d4ff; font-size: 2rem; text-align: center;">
<div>
<div>Neural Link Disconnected</div>
<div style="font-size: 1rem; margin-top: 20px; opacity: 0.7;">現実世界へ戻りました</div>
</div>
</div>
`;
}, 1000);
}
// リサイズ対応
window.addEventListener('resize', () => {
if (camera && renderer) {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
});
</script>
</body>
</html>