Spaces:
Running
Running
Update index.html
Browse files- index.html +194 -19
index.html
CHANGED
@@ -1,19 +1,194 @@
|
|
1 |
-
<!
|
2 |
-
<html>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>WebGPU Three.js Spaceship Fly-Through</title>
|
7 |
+
<style>
|
8 |
+
body { margin: 0; overflow: hidden; }
|
9 |
+
canvas { display: block; }
|
10 |
+
</style>
|
11 |
+
</head>
|
12 |
+
<body>
|
13 |
+
<script type="importmap">
|
14 |
+
{
|
15 |
+
"imports": {
|
16 |
+
"three": "https://unpkg.com/[email protected]/build/three.module.js",
|
17 |
+
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
|
18 |
+
}
|
19 |
+
}
|
20 |
+
</script>
|
21 |
+
<script type="module">
|
22 |
+
import * as THREE from 'three';
|
23 |
+
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
24 |
+
import { WebGPURenderer } from 'three/addons/renderers/webgpu/WebGPURenderer.js';
|
25 |
+
|
26 |
+
// Scene setup
|
27 |
+
const scene = new THREE.Scene();
|
28 |
+
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
29 |
+
camera.position.set(0, 5, 10);
|
30 |
+
|
31 |
+
const renderer = new WebGPURenderer({ antialias: true });
|
32 |
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
33 |
+
renderer.setPixelRatio(window.devicePixelRatio);
|
34 |
+
document.body.appendChild(renderer.domElement);
|
35 |
+
|
36 |
+
// Lighting
|
37 |
+
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
|
38 |
+
scene.add(ambientLight);
|
39 |
+
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
40 |
+
directionalLight.position.set(1, 1, 1);
|
41 |
+
scene.add(directionalLight);
|
42 |
+
|
43 |
+
// Spaceship (simple geometry)
|
44 |
+
const shipGeometry = new THREE.ConeGeometry(0.5, 2, 32);
|
45 |
+
const shipMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00, metalness: 0.8, roughness: 0.2 });
|
46 |
+
const spaceship = new THREE.Mesh(shipGeometry, shipMaterial);
|
47 |
+
spaceship.position.set(0, 0, 0);
|
48 |
+
scene.add(spaceship);
|
49 |
+
|
50 |
+
// Particle system for buildings
|
51 |
+
const buildingCount = 100;
|
52 |
+
const buildingGeometry = new THREE.BufferGeometry();
|
53 |
+
const buildingPositions = new Float32Array(buildingCount * 3);
|
54 |
+
const buildingColors = new Float32Array(buildingCount * 3);
|
55 |
+
const buildingSizes = new Float32Array(buildingCount);
|
56 |
+
|
57 |
+
for (let i = 0; i < buildingCount; i++) {
|
58 |
+
buildingPositions[i * 3] = (Math.random() - 0.5) * 200;
|
59 |
+
buildingPositions[i * 3 + 1] = Math.random() * 10;
|
60 |
+
buildingPositions[i * 3 + 2] = (Math.random() - 0.5) * 200;
|
61 |
+
buildingColors[i * 3] = 0.2;
|
62 |
+
buildingColors[i * 3 + 1] = 0.6;
|
63 |
+
buildingColors[i * 3 + 2] = 1.0;
|
64 |
+
buildingSizes[i] = Math.random() * 2 + 1;
|
65 |
+
}
|
66 |
+
|
67 |
+
buildingGeometry.setAttribute('position', new THREE.BufferAttribute(buildingPositions, 3));
|
68 |
+
buildingGeometry.setAttribute('color', new THREE.BufferAttribute(buildingColors, 3));
|
69 |
+
buildingGeometry.setAttribute('size', new THREE.BufferAttribute(buildingSizes, 1));
|
70 |
+
|
71 |
+
const buildingMaterial = new THREE.PointsMaterial({
|
72 |
+
size: 2,
|
73 |
+
vertexColors: true,
|
74 |
+
transparent: true,
|
75 |
+
opacity: 0.7,
|
76 |
+
sizeAttenuation: true
|
77 |
+
});
|
78 |
+
|
79 |
+
const buildings = new THREE.Points(buildingGeometry, buildingMaterial);
|
80 |
+
scene.add(buildings);
|
81 |
+
|
82 |
+
// Particle system for people
|
83 |
+
const peopleCount = 200;
|
84 |
+
const peopleGeometry = new THREE.BufferGeometry();
|
85 |
+
const peoplePositions = new Float32Array(peopleCount * 3);
|
86 |
+
const peopleColors = new Float32Array(peopleCount * 3);
|
87 |
+
const peopleSizes = new Float32Array(peopleCount);
|
88 |
+
|
89 |
+
for (let i = 0; i < peopleCount; i++) {
|
90 |
+
peoplePositions[i * 3] = (Math.random() - 0.5) * 150;
|
91 |
+
peoplePositions[i * 3 + 1] = Math.random() * 5;
|
92 |
+
peoplePositions[i * 3 + 2] = (Math.random() - 0.5) * 150;
|
93 |
+
peopleColors[i * 3] = 1.0;
|
94 |
+
peopleColors[i * 3 + 1] = 0.8;
|
95 |
+
peopleColors[i * 3 + 2] = 0.8;
|
96 |
+
peopleSizes[i] = Math.random() * 0.5 + 0.2;
|
97 |
+
}
|
98 |
+
|
99 |
+
peopleGeometry.setAttribute('position', new THREE.BufferAttribute(peoplePositions, 3));
|
100 |
+
peopleGeometry.setAttribute('color', new THREE.BufferAttribute(peopleColors, 3));
|
101 |
+
peopleGeometry.setAttribute('size', new THREE.BufferAttribute(peopleSizes, 1));
|
102 |
+
|
103 |
+
const peopleMaterial = new THREE.PointsMaterial({
|
104 |
+
size: 0.5,
|
105 |
+
vertexColors: true,
|
106 |
+
transparent: true,
|
107 |
+
opacity: 0.6,
|
108 |
+
sizeAttenuation: true
|
109 |
+
});
|
110 |
+
|
111 |
+
const people = new THREE.Points(peopleGeometry, peopleMaterial);
|
112 |
+
scene.add(people);
|
113 |
+
|
114 |
+
// Instanced geometry for repeating objects (cubes)
|
115 |
+
const cubeCount = 50;
|
116 |
+
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
|
117 |
+
const cubeMaterial = new THREE.MeshStandardMaterial({ color: 0xff00ff, metalness: 0.5, roughness: 0.4 });
|
118 |
+
const cubeMesh = new THREE.InstancedMesh(cubeGeometry, cubeMaterial, cubeCount);
|
119 |
+
|
120 |
+
const dummy = new THREE.Object3D();
|
121 |
+
for (let i = 0; i < cubeCount; i++) {
|
122 |
+
dummy.position.set(
|
123 |
+
(Math.random() - 0.5) * 100,
|
124 |
+
Math.random() * 10,
|
125 |
+
(Math.random() - 0.5) * 100
|
126 |
+
);
|
127 |
+
dummy.scale.setScalar(Math.random() * 0.5 + 0.5);
|
128 |
+
dummy.updateMatrix();
|
129 |
+
cubeMesh.setMatrixAt(i, dummy.matrix);
|
130 |
+
}
|
131 |
+
scene.add(cubeMesh);
|
132 |
+
|
133 |
+
// Camera movement
|
134 |
+
let time = 0;
|
135 |
+
function updateCamera() {
|
136 |
+
time += 0.01;
|
137 |
+
camera.position.z -= 0.5; // Continuous forward movement
|
138 |
+
camera.position.x = Math.sin(time * 0.5) * 5; // Gentle side-to-side
|
139 |
+
camera.position.y = Math.cos(time * 0.3) * 2 + 5; // Up and down
|
140 |
+
camera.lookAt(new THREE.Vector3(0, 0, camera.position.z - 100));
|
141 |
+
}
|
142 |
+
|
143 |
+
// Parallax and repetition
|
144 |
+
function updateObjects() {
|
145 |
+
const positions = buildings.geometry.attributes.position.array;
|
146 |
+
for (let i = 0; i < buildingCount; i++) {
|
147 |
+
positions[i * 3 + 2] += 0.5; // Move towards camera
|
148 |
+
if (positions[i * 3 + 2] > camera.position.z + 100) {
|
149 |
+
positions[i * 3 + 2] -= 200; // Reset to back
|
150 |
+
}
|
151 |
+
}
|
152 |
+
buildings.geometry.attributes.position.needsUpdate = true;
|
153 |
+
|
154 |
+
const peoplePos = people.geometry.attributes.position.array;
|
155 |
+
for (let i = 0; i < peopleCount; i++) {
|
156 |
+
peoplePos[i * 3 + 2] += 0.7; // Faster movement for parallax
|
157 |
+
if (peoplePos[i * 3 + 2] > camera.position.z + 100) {
|
158 |
+
peoplePos[i * 3 + 2] -= 200;
|
159 |
+
}
|
160 |
+
}
|
161 |
+
people.geometry.attributes.position.needsUpdate = true;
|
162 |
+
|
163 |
+
for (let i = 0; i < cubeCount; i++) {
|
164 |
+
cubeMesh.getMatrixAt(i, dummy.matrix);
|
165 |
+
dummy.matrix.decompose(dummy.position, dummy.quaternion, dummy.scale);
|
166 |
+
dummy.position.z += 0.6;
|
167 |
+
if (dummy.position.z > camera.position.z + 100) {
|
168 |
+
dummy.position.z -= 200;
|
169 |
+
}
|
170 |
+
dummy.updateMatrix();
|
171 |
+
cubeMesh.setMatrixAt(i, dummy.matrix);
|
172 |
+
}
|
173 |
+
cubeMesh.instanceMatrix.needsUpdate = true;
|
174 |
+
}
|
175 |
+
|
176 |
+
// Animation loop
|
177 |
+
function animate() {
|
178 |
+
requestAnimationFrame(animate);
|
179 |
+
updateCamera();
|
180 |
+
updateObjects();
|
181 |
+
renderer.render(scene, camera);
|
182 |
+
}
|
183 |
+
|
184 |
+
animate();
|
185 |
+
|
186 |
+
// Handle window resize
|
187 |
+
window.addEventListener('resize', () => {
|
188 |
+
camera.aspect = window.innerWidth / window.innerHeight;
|
189 |
+
camera.updateProjectionMatrix();
|
190 |
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
191 |
+
});
|
192 |
+
</script>
|
193 |
+
</body>
|
194 |
+
</html>
|