File size: 20,294 Bytes
d3d9660
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D Particle Galaxy</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #000;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        canvas {
            display: block;
        }
        .overlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
        }
        .title {
            position: absolute;
            top: 20px;
            left: 0;
            right: 0;
            text-align: center;
            font-size: 2.5rem;
            font-weight: 700;
            color: rgba(200, 220, 255, 0.8);
            text-shadow: 0 0 10px rgba(100, 150, 255, 0.5);
            letter-spacing: 2px;
        }
        .controls {
            position: absolute;
            bottom: 20px;
            left: 0;
            right: 0;
            text-align: center;
            color: rgba(180, 200, 255, 0.7);
            font-size: 0.9rem;
        }
        .loading {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: rgba(200, 220, 255, 0.8);
            font-size: 1.2rem;
            text-align: center;
        }
        .nebula-info {
            position: absolute;
            top: 80px;
            right: 20px;
            max-width: 300px;
            background: rgba(10, 15, 30, 0.6);
            border-radius: 10px;
            padding: 15px;
            backdrop-filter: blur(5px);
            border: 1px solid rgba(100, 150, 255, 0.2);
            pointer-events: auto;
        }
        .nebula-title {
            font-size: 1.2rem;
            color: #8bb4ff;
            margin-bottom: 8px;
        }
        .nebula-desc {
            font-size: 0.9rem;
            color: #a0c0ff;
            line-height: 1.4;
        }
        .stats {
            position: absolute;
            top: 20px;
            right: 20px;
            color: rgba(180, 200, 255, 0.7);
            font-size: 0.8rem;
        }
        .toggle-ui {
            position: absolute;
            bottom: 20px;
            right: 20px;
            background: rgba(10, 15, 30, 0.6);
            color: #a0c0ff;
            border: 1px solid rgba(100, 150, 255, 0.2);
            padding: 8px 15px;
            border-radius: 5px;
            cursor: pointer;
            pointer-events: auto;
            transition: all 0.3s ease;
        }
        .toggle-ui:hover {
            background: rgba(20, 40, 80, 0.7);
        }
    </style>
</head>
<body class="bg-black">
    <div class="overlay">
        <div class="title">COSMIC NEBULA EXPLORER</div>
        <div class="nebula-info">
            <div class="nebula-title">Orion Nebula</div>
            <div class="nebula-desc">A diffuse nebula situated in the Milky Way, being one of the brightest nebulae visible to the naked eye. This stellar nursery is 1,344 light-years away.</div>
        </div>
        <div class="stats">Particles: 25,000 | FPS: <span id="fps">60</span></div>
        <div class="controls">Drag to rotate | Scroll to zoom | Click to create supernova</div>
        <button class="toggle-ui" onclick="toggleUI()">Toggle UI</button>
    </div>
    <div class="loading" id="loading">Initializing cosmic simulation...</div>

    <script>
        // Main variables
        let scene, camera, renderer, controls;
        let particleSystem, nebulaSystem;
        let stars = [];
        let clock = new THREE.Clock();
        let uiVisible = true;
        
        // Configuration
        const config = {
            particleCount: 25000,
            nebulaCount: 8,
            galaxySize: 2000,
            rotationSpeed: 0.1,
            nebulaColors: [
                new THREE.Color(0.4, 0.2, 0.8), // Purple
                new THREE.Color(0.2, 0.5, 0.9), // Blue
                new THREE.Color(0.8, 0.3, 0.4), // Red
                new THREE.Color(0.3, 0.8, 0.5)  // Green
            ],
            starColors: [
                new THREE.Color(1.0, 0.9, 0.7), // Yellow
                new THREE.Color(0.9, 0.9, 1.0), // Blue-white
                new THREE.Color(1.0, 0.7, 0.7)  // Red
            ]
        };

        // Initialize the scene
        function init() {
            // Create scene
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x000010);
            scene.fog = new THREE.FogExp2(0x000020, 0.0008);

            // Create camera
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 3000);
            camera.position.z = 500;

            // Create renderer
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            document.body.appendChild(renderer.domElement);

            // Add orbit controls
            controls = new THREE.OrbitControls(camera, renderer.domElement);
            controls.enableDamping = true;
            controls.dampingFactor = 0.05;
            controls.rotateSpeed = 0.5;
            controls.zoomSpeed = 1.2;

            // Create galaxy
            createGalaxy();
            
            // Add ambient light
            const ambientLight = new THREE.AmbientLight(0x222244);
            scene.add(ambientLight);
            
            // Add directional light for stars
            const starLight = new THREE.DirectionalLight(0xffffff, 0.5);
            starLight.position.set(1, 1, 1);
            scene.add(starLight);
            
            // Add point lights for nebulas
            for (let i = 0; i < config.nebulaCount; i++) {
                const light = new THREE.PointLight(config.nebulaColors[Math.floor(Math.random() * config.nebulaColors.length)], 0.8, 500);
                light.position.set(
                    (Math.random() - 0.5) * config.galaxySize,
                    (Math.random() - 0.5) * config.galaxySize * 0.2,
                    (Math.random() - 0.5) * config.galaxySize
                );
                scene.add(light);
            }

            // Handle window resize
            window.addEventListener('resize', onWindowResize);
            
            // Handle mouse click for supernova
            renderer.domElement.addEventListener('click', createSupernova);
            
            // Hide loading screen
            document.getElementById('loading').style.display = 'none';
            
            // Start animation
            animate();
        }

        // Create galaxy with stars and nebulas
        function createGalaxy() {
            // Create star particles
            const starGeometry = new THREE.BufferGeometry();
            const starPositions = new Float32Array(config.particleCount * 3);
            const starColors = new Float32Array(config.particleCount * 3);
            const starSizes = new Float32Array(config.particleCount);
            
            // Create nebula particles
            const nebulaGeometry = new THREE.BufferGeometry();
            const nebulaPositions = new Float32Array(config.nebulaCount * 3);
            const nebulaColors = new Float32Array(config.nebulaCount * 3);
            const nebulaSizes = new Float32Array(config.nebulaCount);
            
            // Create star positions and attributes
            for (let i = 0; i < config.particleCount; i++) {
                const i3 = i * 3;
                
                // Position stars in a spiral galaxy pattern
                const radius = Math.random() * config.galaxySize;
                const angle = Math.random() * Math.PI * 2;
                const spiral = Math.random() * 0.4;
                const height = (Math.random() - 0.5) * config.galaxySize * 0.1;
                
                starPositions[i3] = Math.cos(angle + spiral * radius) * radius;
                starPositions[i3 + 1] = height;
                starPositions[i3 + 2] = Math.sin(angle + spiral * radius) * radius;
                
                // Assign star color based on position
                const colorIndex = Math.floor(Math.random() * config.starColors.length);
                const color = config.starColors[colorIndex];
                starColors[i3] = color.r;
                starColors[i3 + 1] = color.g;
                starColors[i3 + 2] = color.b;
                
                // Randomize star size
                starSizes[i] = Math.random() * 2.0 + 0.5;
                
                // Store star data for animation
                stars.push({
                    radius: radius,
                    angle: angle,
                    spiral: spiral,
                    height: height,
                    speed: 0.1 + Math.random() * 0.3
                });
            }
            
            // Create nebula positions and attributes
            for (let i = 0; i < config.nebulaCount; i++) {
                const i3 = i * 3;
                
                // Position nebulas randomly in the galaxy
                const radius = Math.random() * config.galaxySize * 0.7;
                const angle = Math.random() * Math.PI * 2;
                const height = (Math.random() - 0.5) * config.galaxySize * 0.05;
                
                nebulaPositions[i3] = Math.cos(angle) * radius;
                nebulaPositions[i3 + 1] = height;
                nebulaPositions[i3 + 2] = Math.sin(angle) * radius;
                
                // Assign nebula color
                const color = config.nebulaColors[Math.floor(Math.random() * config.nebulaColors.length)];
                nebulaColors[i3] = color.r;
                nebulaColors[i3 + 1] = color.g;
                nebulaColors[i3 + 2] = color.b;
                
                // Set nebula size
                nebulaSizes[i] = 50 + Math.random() * 100;
            }
            
            // Set star geometry attributes
            starGeometry.setAttribute('position', new THREE.BufferAttribute(starPositions, 3));
            starGeometry.setAttribute('color', new THREE.BufferAttribute(starColors, 3));
            starGeometry.setAttribute('size', new THREE.BufferAttribute(starSizes, 1));
            
            // Set nebula geometry attributes
            nebulaGeometry.setAttribute('position', new THREE.BufferAttribute(nebulaPositions, 3));
            nebulaGeometry.setAttribute('color', new THREE.BufferAttribute(nebulaColors, 3));
            nebulaGeometry.setAttribute('size', new THREE.BufferAttribute(nebulaSizes, 1));
            
            // Create star material
            const starMaterial = new THREE.PointsMaterial({
                size: 1.5,
                vertexColors: true,
                transparent: true,
                opacity: 0.9,
                sizeAttenuation: true
            });
            
            // Create nebula material
            const nebulaMaterial = new THREE.PointsMaterial({
                size: 1,
                vertexColors: true,
                transparent: true,
                opacity: 0.3,
                sizeAttenuation: true,
                blending: THREE.AdditiveBlending
            });
            
            // Create particle systems
            particleSystem = new THREE.Points(starGeometry, starMaterial);
            nebulaSystem = new THREE.Points(nebulaGeometry, nebulaMaterial);
            
            // Add to scene
            scene.add(particleSystem);
            scene.add(nebulaSystem);
        }

        // Animate the galaxy
        function animate() {
            requestAnimationFrame(animate);
            
            const delta = clock.getDelta();
            const elapsedTime = clock.getElapsedTime();
            
            // Update controls
            controls.update();
            
            // Animate stars
            const positions = particleSystem.geometry.attributes.position.array;
            for (let i = 0; i < config.particleCount; i++) {
                const i3 = i * 3;
                const star = stars[i];
                
                // Update angle based on radius and speed
                star.angle += delta * star.speed * (config.galaxySize / (star.radius + 1)) * 0.1;
                
                // Calculate new position
                positions[i3] = Math.cos(star.angle + star.spiral * star.radius) * star.radius;
                positions[i3 + 2] = Math.sin(star.angle + star.spiral * star.radius) * star.radius;
                
                // Add subtle vertical movement
                positions[i3 + 1] = star.height + Math.sin(elapsedTime * 0.3 + i) * 5;
            }
            
            // Mark position attribute as needing update
            particleSystem.geometry.attributes.position.needsUpdate = true;
            
            // Animate nebulas
            const nebulaPositions = nebulaSystem.geometry.attributes.position.array;
            for (let i = 0; i < config.nebulaCount; i++) {
                const i3 = i * 3;
                
                // Move nebulas in gentle swirling motion
                nebulaPositions[i3] += Math.sin(elapsedTime * 0.1 + i) * 0.3;
                nebulaPositions[i3 + 1] += Math.cos(elapsedTime * 0.15 + i) * 0.2;
                nebulaPositions[i3 + 2] += Math.sin(elapsedTime * 0.12 + i * 2) * 0.4;
            }
            nebulaSystem.geometry.attributes.position.needsUpdate = true;
            
            // Rotate entire galaxy
            particleSystem.rotation.y += delta * config.rotationSpeed * 0.05;
            nebulaSystem.rotation.y += delta * config.rotationSpeed * 0.03;
            
            // Update FPS counter
            updateFPS(delta);
            
            // Render the scene
            renderer.render(scene, camera);
        }

        // Create supernova effect on click
        function createSupernova(event) {
            // Calculate mouse position in normalized device coordinates
            const mouse = new THREE.Vector2();
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            
            // Create explosion at mouse position
            const explosionGeometry = new THREE.BufferGeometry();
            const explosionCount = 2000;
            const positions = new Float32Array(explosionCount * 3);
            const colors = new Float32Array(explosionCount * 3);
            const sizes = new Float32Array(explosionCount);
            
            // Get explosion position from mouse
            const raycaster = new THREE.Raycaster();
            raycaster.setFromCamera(mouse, camera);
            const intersects = raycaster.intersectObject(particleSystem);
            
            let explosionPosition;
            if (intersects.length > 0) {
                explosionPosition = intersects[0].point;
            } else {
                // If no intersection, create explosion in front of camera
                explosionPosition = new THREE.Vector3();
                raycaster.ray.at(500, explosionPosition);
            }
            
            // Create explosion particles
            const explosionColor = new THREE.Color(
                0.9 + Math.random() * 0.1,
                0.7 + Math.random() * 0.2,
                0.3 + Math.random() * 0.2
            );
            
            for (let i = 0; i < explosionCount; i++) {
                const i3 = i * 3;
                
                // Random direction
                const angle = Math.random() * Math.PI * 2;
                const elevation = Math.random() * Math.PI - Math.PI / 2;
                const distance = Math.random() * 50;
                
                positions[i3] = explosionPosition.x + Math.cos(angle) * Math.cos(elevation) * distance;
                positions[i3 + 1] = explosionPosition.y + Math.sin(elevation) * distance;
                positions[i3 + 2] = explosionPosition.z + Math.sin(angle) * Math.cos(elevation) * distance;
                
                colors[i3] = explosionColor.r;
                colors[i3 + 1] = explosionColor.g;
                colors[i3 + 2] = explosionColor.b;
                
                sizes[i] = Math.random() * 4 + 1;
            }
            
            explosionGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
            explosionGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
            explosionGeometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
            
            const explosionMaterial = new THREE.PointsMaterial({
                size: 2,
                vertexColors: true,
                transparent: true,
                opacity: 0.9,
                sizeAttenuation: true,
                blending: THREE.AdditiveBlending
            });
            
            const explosion = new THREE.Points(explosionGeometry, explosionMaterial);
            scene.add(explosion);
            
            // Animate and remove explosion
            let explosionTime = 0;
            const explosionDuration = 2.0;
            
            function updateExplosion() {
                explosionTime += 0.016;
                const progress = explosionTime / explosionDuration;
                
                if (progress > 1) {
                    scene.remove(explosion);
                    return;
                }
                
                // Fade out particles
                explosionMaterial.opacity = 1 - progress;
                
                // Expand particles
                const positions = explosion.geometry.attributes.position.array;
                for (let i = 0; i < explosionCount; i++) {
                    const i3 = i * 3;
                    positions[i3] *= 1.02;
                    positions[i3 + 1] *= 1.02;
                    positions[i3 + 2] *= 1.02;
                }
                explosion.geometry.attributes.position.needsUpdate = true;
                
                requestAnimationFrame(updateExplosion);
            }
            
            updateExplosion();
        }

        // Update FPS counter
        function updateFPS(delta) {
            const fpsElement = document.getElementById('fps');
            if (fpsElement) {
                const fps = Math.round(1 / delta);
                fpsElement.textContent = fps;
            }
        }

        // Handle window resize
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        // Toggle UI visibility
        function toggleUI() {
            uiVisible = !uiVisible;
            const overlay = document.querySelector('.overlay');
            overlay.style.opacity = uiVisible ? '1' : '0';
        }

        // Initialize when page loads
        window.onload = init;
    </script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=erdes/galaxy" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>