MagicBullets commited on
Commit
364fb61
·
verified ·
1 Parent(s): b4aea91

Create a photorealistic 3D Earth globe visualization with the following specifications: Visual Requirements: - Ultra-realistic Earth rendering that fills 90% of the screen - High-resolution satellite imagery texture showing actual Earth surface details - Accurate continental landmasses with visible topography (mountains, valleys, deserts) - Realistic ocean colors with depth variations (deep blue to turquoise near shores) - Dynamic cloud layer with semi-transparent, moving cloud formations - Atmospheric glow around the edges (thin blue atmosphere layer) - Subtle city lights visible on the night side of Earth - Realistic lighting with sun illumination from one side creating day/night terminator Interactive Features: - Smooth rotation animation (0.2 degrees per frame) - Mouse/touch controlled rotation in all directions - Zoom capability (scroll wheel) from full globe view to continent level - Click on cities to highlight with red pulsing markers - City labels appear on hover (white text with black outline) - Smooth camera transitions when zooming to specific locations Technical Details: - WebGL-based rendering for smooth performance - Sphere geometry with 128x64 segments for smoothness - Multiple texture layers: base map (8K resolution), cloud layer, night lights - Specular mapping for ocean reflections - Normal mapping for terrain elevation - Real-time shadows on cloud layer Style Reference: Similar to Google Earth's photorealism but optimized for web performance. The globe should look like you're viewing Earth from space through a high-quality telescope - every detail crisp and believable, not stylized or cartoon-like. - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +489 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Rotating Earth
3
- emoji: 🌖
4
- colorFrom: green
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: rotating-earth
3
+ emoji: 🐳
4
+ colorFrom: pink
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,489 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Photorealistic Earth Globe</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.min.js"></script>
11
+ <style>
12
+ body, html {
13
+ margin: 0;
14
+ padding: 0;
15
+ overflow: hidden;
16
+ height: 100%;
17
+ background: linear-gradient(to bottom, #000428, #004e92);
18
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
19
+ }
20
+
21
+ #globe-container {
22
+ position: absolute;
23
+ top: 0;
24
+ left: 0;
25
+ width: 100%;
26
+ height: 100%;
27
+ }
28
+
29
+ .info-panel {
30
+ position: absolute;
31
+ bottom: 20px;
32
+ left: 20px;
33
+ background: rgba(0, 0, 30, 0.7);
34
+ color: white;
35
+ padding: 15px;
36
+ border-radius: 10px;
37
+ max-width: 300px;
38
+ backdrop-filter: blur(5px);
39
+ border: 1px solid rgba(100, 150, 255, 0.3);
40
+ }
41
+
42
+ .controls {
43
+ position: absolute;
44
+ top: 20px;
45
+ right: 20px;
46
+ display: flex;
47
+ flex-direction: column;
48
+ gap: 10px;
49
+ }
50
+
51
+ .control-btn {
52
+ background: rgba(0, 0, 30, 0.7);
53
+ color: white;
54
+ border: 1px solid rgba(100, 150, 255, 0.3);
55
+ border-radius: 5px;
56
+ padding: 8px 15px;
57
+ cursor: pointer;
58
+ backdrop-filter: blur(5px);
59
+ transition: all 0.3s ease;
60
+ }
61
+
62
+ .control-btn:hover {
63
+ background: rgba(20, 50, 100, 0.8);
64
+ transform: translateY(-2px);
65
+ }
66
+
67
+ .city-label {
68
+ position: absolute;
69
+ background: rgba(0, 0, 0, 0.7);
70
+ color: white;
71
+ padding: 5px 10px;
72
+ border-radius: 4px;
73
+ font-size: 12px;
74
+ pointer-events: none;
75
+ opacity: 0;
76
+ transition: opacity 0.3s;
77
+ text-shadow: 0 0 3px black;
78
+ border: 1px solid rgba(255, 255, 255, 0.2);
79
+ }
80
+
81
+ .loading-screen {
82
+ position: absolute;
83
+ top: 0;
84
+ left: 0;
85
+ width: 100%;
86
+ height: 100%;
87
+ background: rgba(0, 10, 30, 0.95);
88
+ display: flex;
89
+ flex-direction: column;
90
+ justify-content: center;
91
+ align-items: center;
92
+ z-index: 100;
93
+ transition: opacity 1s ease-out;
94
+ }
95
+
96
+ .loading-spinner {
97
+ width: 50px;
98
+ height: 50px;
99
+ border: 5px solid rgba(100, 150, 255, 0.3);
100
+ border-top: 5px solid #4d9df0;
101
+ border-radius: 50%;
102
+ animation: spin 1s linear infinite;
103
+ margin-bottom: 20px;
104
+ }
105
+
106
+ @keyframes spin {
107
+ 0% { transform: rotate(0deg); }
108
+ 100% { transform: rotate(360deg); }
109
+ }
110
+
111
+ .pulse {
112
+ display: block;
113
+ width: 10px;
114
+ height: 10px;
115
+ border-radius: 50%;
116
+ background: #ff3366;
117
+ box-shadow: 0 0 0 0 rgba(255, 51, 102, 0.7);
118
+ animation: pulse 2s infinite;
119
+ }
120
+
121
+ @keyframes pulse {
122
+ 0% {
123
+ transform: scale(0.8);
124
+ box-shadow: 0 0 0 0 rgba(255, 51, 102, 0.7);
125
+ }
126
+ 70% {
127
+ transform: scale(1);
128
+ box-shadow: 0 0 0 10px rgba(255, 51, 102, 0);
129
+ }
130
+ 100% {
131
+ transform: scale(0.8);
132
+ box-shadow: 0 0 0 0 rgba(255, 51, 102, 0);
133
+ }
134
+ }
135
+
136
+ .title {
137
+ position: absolute;
138
+ top: 20px;
139
+ left: 20px;
140
+ color: white;
141
+ font-size: 24px;
142
+ font-weight: 300;
143
+ text-shadow: 0 0 10px rgba(0, 100, 255, 0.7);
144
+ }
145
+
146
+ .title span {
147
+ color: #4d9df0;
148
+ font-weight: 600;
149
+ }
150
+ </style>
151
+ </head>
152
+ <body>
153
+ <div class="loading-screen" id="loading-screen">
154
+ <div class="loading-spinner"></div>
155
+ <div class="text-white text-xl">Loading Earth Visualization...</div>
156
+ <div class="text-blue-300 mt-4">Loading high-resolution textures</div>
157
+ </div>
158
+
159
+ <div class="title">Photorealistic <span>Earth</span> Globe</div>
160
+
161
+ <div id="globe-container"></div>
162
+
163
+ <div class="info-panel">
164
+ <h3 class="text-lg font-semibold mb-2">Earth Visualization</h3>
165
+ <p class="text-sm opacity-80">High-resolution photorealistic globe with:</p>
166
+ <ul class="text-xs mt-2 space-y-1">
167
+ <li>• Satellite imagery texture</li>
168
+ <li>• Dynamic cloud layer</li>
169
+ <li>• Atmospheric glow effect</li>
170
+ <li>• Night-side city lights</li>
171
+ <li>• Interactive controls</li>
172
+ </ul>
173
+ </div>
174
+
175
+ <div class="controls">
176
+ <button class="control-btn" id="reset-view">Reset View</button>
177
+ <button class="control-btn" id="toggle-rotation">Pause Rotation</button>
178
+ <button class="control-btn" id="toggle-clouds">Clouds: On</button>
179
+ <button class="control-btn" id="toggle-atmosphere">Atmosphere: On</button>
180
+ </div>
181
+
182
+ <script>
183
+ // Main Three.js script
184
+ document.addEventListener('DOMContentLoaded', () => {
185
+ // Scene setup
186
+ const scene = new THREE.Scene();
187
+ scene.background = new THREE.Color(0x000011);
188
+ scene.fog = new THREE.Fog(0x000022, 10, 20);
189
+
190
+ // Camera setup
191
+ const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
192
+ camera.position.z = 15;
193
+
194
+ // Renderer setup
195
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
196
+ renderer.setSize(window.innerWidth, window.innerHeight);
197
+ renderer.setPixelRatio(window.devicePixelRatio);
198
+ document.getElementById('globe-container').appendChild(renderer.domElement);
199
+
200
+ // Add stars background
201
+ const starGeometry = new THREE.BufferGeometry();
202
+ const starVertices = [];
203
+ for (let i = 0; i < 10000; i++) {
204
+ const x = (Math.random() - 0.5) * 2000;
205
+ const y = (Math.random() - 0.5) * 2000;
206
+ const z = (Math.random() - 0.5) * 2000;
207
+ starVertices.push(x, y, z);
208
+ }
209
+ starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starVertices, 3));
210
+ const starMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 0.7 });
211
+ const stars = new THREE.Points(starGeometry, starMaterial);
212
+ scene.add(stars);
213
+
214
+ // Create Earth group
215
+ const earthGroup = new THREE.Group();
216
+ scene.add(earthGroup);
217
+
218
+ // Earth parameters
219
+ const earthRadius = 5;
220
+ const earthSegments = 128;
221
+
222
+ // Create Earth geometry
223
+ const earthGeometry = new THREE.SphereGeometry(earthRadius, earthSegments, earthSegments / 2);
224
+
225
+ // Earth material with textures
226
+ const earthMaterial = new THREE.MeshPhongMaterial({
227
+ specular: 0x333333,
228
+ shininess: 5,
229
+ map: new THREE.TextureLoader().load('https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/planets/earth_atmos_2048.jpg', () => {
230
+ document.getElementById('loading-screen').style.opacity = '0';
231
+ setTimeout(() => {
232
+ document.getElementById('loading-screen').style.display = 'none';
233
+ }, 1000);
234
+ }),
235
+ specularMap: new THREE.TextureLoader().load('https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/planets/earth_specular_2048.jpg'),
236
+ normalMap: new THREE.TextureLoader().load('https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/planets/earth_normal_2048.jpg'),
237
+ normalScale: new THREE.Vector2(0.85, 0.85)
238
+ });
239
+
240
+ // Create Earth mesh
241
+ const earth = new THREE.Mesh(earthGeometry, earthMaterial);
242
+ earthGroup.add(earth);
243
+
244
+ // Create clouds
245
+ const cloudGeometry = new THREE.SphereGeometry(earthRadius * 1.005, earthSegments, earthSegments / 2);
246
+ const cloudMaterial = new THREE.MeshPhongMaterial({
247
+ map: new THREE.TextureLoader().load('https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/planets/earth_clouds_2048.png'),
248
+ transparent: true,
249
+ opacity: 0.8
250
+ });
251
+
252
+ const clouds = new THREE.Mesh(cloudGeometry, cloudMaterial);
253
+ earthGroup.add(clouds);
254
+
255
+ // Create atmosphere
256
+ const atmosphereGeometry = new THREE.SphereGeometry(earthRadius * 1.02, earthSegments, earthSegments / 2);
257
+ const atmosphereMaterial = new THREE.MeshPhongMaterial({
258
+ color: 0x3399ff,
259
+ transparent: true,
260
+ opacity: 0.15,
261
+ side: THREE.BackSide
262
+ });
263
+
264
+ const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
265
+ earthGroup.add(atmosphere);
266
+
267
+ // Create night lights
268
+ const lightsGeometry = new THREE.SphereGeometry(earthRadius * 0.999, earthSegments, earthSegments / 2);
269
+ const lightsMaterial = new THREE.MeshBasicMaterial({
270
+ map: new THREE.TextureLoader().load('https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/planets/earth_lights_2048.jpg'),
271
+ blending: THREE.AdditiveBlending,
272
+ transparent: true
273
+ });
274
+
275
+ const nightLights = new THREE.Mesh(lightsGeometry, lightsMaterial);
276
+ earthGroup.add(nightLights);
277
+
278
+ // Add lighting
279
+ const ambientLight = new THREE.AmbientLight(0x333333);
280
+ scene.add(ambientLight);
281
+
282
+ const sunLight = new THREE.DirectionalLight(0xffffff, 1.2);
283
+ sunLight.position.set(10, 5, 7);
284
+ scene.add(sunLight);
285
+
286
+ // Add hemisphere light for more natural illumination
287
+ const hemiLight = new THREE.HemisphereLight(0x5577dd, 0x224422, 0.1);
288
+ scene.add(hemiLight);
289
+
290
+ // Add orbit controls
291
+ const controls = new THREE.OrbitControls(camera, renderer.domElement);
292
+ controls.enableDamping = true;
293
+ controls.dampingFactor = 0.05;
294
+ controls.minDistance = 6;
295
+ controls.maxDistance = 30;
296
+
297
+ // City data
298
+ const cities = [
299
+ { name: "New York", lat: 40.7128, lon: -74.0060 },
300
+ { name: "London", lat: 51.5074, lon: -0.1278 },
301
+ { name: "Tokyo", lat: 35.6895, lon: 139.6917 },
302
+ { name: "Sydney", lat: -33.8688, lon: 151.2093 },
303
+ { name: "Rio de Janeiro", lat: -22.9068, lon: -43.1729 },
304
+ { name: "Cairo", lat: 30.0444, lon: 31.2357 },
305
+ { name: "Moscow", lat: 55.7558, lon: 37.6173 },
306
+ { name: "Beijing", lat: 39.9042, lon: 116.4074 }
307
+ ];
308
+
309
+ // Create city markers
310
+ const cityMarkers = [];
311
+ const markerGroup = new THREE.Group();
312
+ earthGroup.add(markerGroup);
313
+
314
+ cities.forEach(city => {
315
+ const marker = new THREE.Mesh(
316
+ new THREE.SphereGeometry(0.05, 16, 16),
317
+ new THREE.MeshBasicMaterial({ color: 0xff3366 })
318
+ );
319
+
320
+ // Convert lat/lon to 3D position
321
+ const phi = (90 - city.lat) * Math.PI / 180;
322
+ const theta = (city.lon + 180) * Math.PI / 180;
323
+
324
+ marker.position.x = -(earthRadius * 1.01) * Math.sin(phi) * Math.cos(theta);
325
+ marker.position.y = (earthRadius * 1.01) * Math.cos(phi);
326
+ marker.position.z = (earthRadius * 1.01) * Math.sin(phi) * Math.sin(theta);
327
+
328
+ marker.userData = { name: city.name };
329
+ markerGroup.add(marker);
330
+ cityMarkers.push(marker);
331
+
332
+ // Create label element
333
+ const label = document.createElement('div');
334
+ label.className = 'city-label';
335
+ label.textContent = city.name;
336
+ document.body.appendChild(label);
337
+ marker.userData.label = label;
338
+ });
339
+
340
+ // Raycaster for interaction
341
+ const raycaster = new THREE.Raycaster();
342
+ const mouse = new THREE.Vector2();
343
+
344
+ // Handle mouse events
345
+ let highlightedMarker = null;
346
+
347
+ function onMouseMove(event) {
348
+ // Calculate mouse position in normalized device coordinates
349
+ mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
350
+ mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
351
+
352
+ // Update the picking ray with the camera and mouse position
353
+ raycaster.setFromCamera(mouse, camera);
354
+
355
+ // Calculate objects intersecting the picking ray
356
+ const intersects = raycaster.intersectObjects(cityMarkers);
357
+
358
+ // Reset all labels
359
+ cityMarkers.forEach(marker => {
360
+ marker.material.color.set(0xff3366);
361
+ marker.userData.label.style.opacity = '0';
362
+ });
363
+
364
+ if (intersects.length > 0) {
365
+ const marker = intersects[0].object;
366
+ marker.material.color.set(0xffff00);
367
+ marker.userData.label.style.opacity = '1';
368
+
369
+ // Position label
370
+ const vector = new THREE.Vector3();
371
+ vector.setFromMatrixPosition(marker.matrixWorld);
372
+ vector.project(camera);
373
+
374
+ const x = (vector.x * 0.5 + 0.5) * window.innerWidth;
375
+ const y = (-vector.y * 0.5 + 0.5) * window.innerHeight;
376
+
377
+ marker.userData.label.style.left = `${x}px`;
378
+ marker.userData.label.style.top = `${y}px`;
379
+ }
380
+ }
381
+
382
+ function onMouseClick(event) {
383
+ raycaster.setFromCamera(mouse, camera);
384
+ const intersects = raycaster.intersectObjects(cityMarkers);
385
+
386
+ if (intersects.length > 0) {
387
+ const marker = intersects[0].object;
388
+
389
+ // Reset previously highlighted marker
390
+ if (highlightedMarker) {
391
+ highlightedMarker.scale.set(1, 1, 1);
392
+ }
393
+
394
+ // Highlight clicked marker
395
+ marker.scale.set(1.5, 1.5, 1.5);
396
+ highlightedMarker = marker;
397
+
398
+ // Create pulse effect
399
+ const pulse = document.createElement('div');
400
+ pulse.className = 'pulse';
401
+ document.body.appendChild(pulse);
402
+
403
+ // Position pulse
404
+ const vector = new THREE.Vector3();
405
+ vector.setFromMatrixPosition(marker.matrixWorld);
406
+ vector.project(camera);
407
+
408
+ const x = (vector.x * 0.5 + 0.5) * window.innerWidth;
409
+ const y = (-vector.y * 0.5 + 0.5) * window.innerHeight;
410
+
411
+ pulse.style.position = 'absolute';
412
+ pulse.style.left = `${x - 5}px`;
413
+ pulse.style.top = `${y - 5}px`;
414
+
415
+ // Remove pulse after animation
416
+ setTimeout(() => {
417
+ document.body.removeChild(pulse);
418
+ }, 2000);
419
+ }
420
+ }
421
+
422
+ // Add event listeners
423
+ window.addEventListener('mousemove', onMouseMove, false);
424
+ window.addEventListener('click', onMouseClick, false);
425
+
426
+ // Handle window resize
427
+ function onWindowResize() {
428
+ camera.aspect = window.innerWidth / window.innerHeight;
429
+ camera.updateProjectionMatrix();
430
+ renderer.setSize(window.innerWidth, window.innerHeight);
431
+ }
432
+
433
+ window.addEventListener('resize', onWindowResize, false);
434
+
435
+ // Animation variables
436
+ let autoRotate = true;
437
+ let cloudsVisible = true;
438
+ let atmosphereVisible = true;
439
+
440
+ // Control buttons
441
+ document.getElementById('reset-view').addEventListener('click', () => {
442
+ controls.reset();
443
+ });
444
+
445
+ document.getElementById('toggle-rotation').addEventListener('click', () => {
446
+ autoRotate = !autoRotate;
447
+ document.getElementById('toggle-rotation').textContent =
448
+ autoRotate ? 'Pause Rotation' : 'Resume Rotation';
449
+ });
450
+
451
+ document.getElementById('toggle-clouds').addEventListener('click', () => {
452
+ cloudsVisible = !cloudsVisible;
453
+ clouds.visible = cloudsVisible;
454
+ document.getElementById('toggle-clouds').textContent =
455
+ `Clouds: ${cloudsVisible ? 'On' : 'Off'}`;
456
+ });
457
+
458
+ document.getElementById('toggle-atmosphere').addEventListener('click', () => {
459
+ atmosphereVisible = !atmosphereVisible;
460
+ atmosphere.visible = atmosphereVisible;
461
+ document.getElementById('toggle-atmosphere').textContent =
462
+ `Atmosphere: ${atmosphereVisible ? 'On' : 'Off'}`;
463
+ });
464
+
465
+ // Animation loop
466
+ function animate() {
467
+ requestAnimationFrame(animate);
468
+
469
+ // Auto-rotate Earth
470
+ if (autoRotate) {
471
+ earthGroup.rotation.y += 0.002;
472
+ }
473
+
474
+ // Rotate clouds slightly faster than Earth
475
+ clouds.rotation.y += 0.0005;
476
+
477
+ // Update controls
478
+ controls.update();
479
+
480
+ // Render scene
481
+ renderer.render(scene, camera);
482
+ }
483
+
484
+ // Start animation
485
+ animate();
486
+ });
487
+ </script>
488
+ <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=MagicBullets/rotating-earth" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
489
+ </html>