ItsMeDevRoland commited on
Commit
be44044
·
verified ·
1 Parent(s): 628dbae

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +839 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Se
3
- emoji: 🚀
4
- colorFrom: pink
5
  colorTo: pink
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: se
3
+ emoji: 🐳
4
+ colorFrom: gray
5
  colorTo: pink
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,839 @@
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>Solar System Sandbox</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ #canvas-container {
12
+ position: relative;
13
+ width: 100%;
14
+ height: 100vh;
15
+ background: radial-gradient(ellipse at center, #000000 0%, #1a1a2e 100%);
16
+ overflow: hidden;
17
+ }
18
+
19
+ #controls {
20
+ position: absolute;
21
+ top: 20px;
22
+ left: 20px;
23
+ background: rgba(0, 0, 0, 0.7);
24
+ padding: 15px;
25
+ border-radius: 10px;
26
+ color: white;
27
+ z-index: 100;
28
+ max-width: 300px;
29
+ }
30
+
31
+ #playback-controls {
32
+ position: absolute;
33
+ top: 20px;
34
+ right: 20px;
35
+ background: rgba(0, 0, 0, 0.7);
36
+ padding: 10px;
37
+ border-radius: 10px;
38
+ color: white;
39
+ z-index: 100;
40
+ display: flex;
41
+ gap: 8px;
42
+ }
43
+
44
+ .planet {
45
+ border-radius: 50%;
46
+ position: absolute;
47
+ box-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
48
+ }
49
+
50
+ .trail {
51
+ position: absolute;
52
+ border-radius: 50%;
53
+ background: rgba(255, 255, 255, 0.2);
54
+ pointer-events: none;
55
+ }
56
+
57
+ .info-panel {
58
+ position: absolute;
59
+ bottom: 20px;
60
+ left: 20px;
61
+ background: rgba(0, 0, 0, 0.7);
62
+ padding: 15px;
63
+ border-radius: 10px;
64
+ color: white;
65
+ z-index: 100;
66
+ max-width: 300px;
67
+ }
68
+
69
+ .gravity-line {
70
+ position: absolute;
71
+ background: rgba(255, 255, 255, 0.3);
72
+ height: 1px;
73
+ transform-origin: left center;
74
+ pointer-events: none;
75
+ }
76
+
77
+ .playback-btn {
78
+ background: rgba(255, 255, 255, 0.1);
79
+ border: none;
80
+ color: white;
81
+ width: 36px;
82
+ height: 36px;
83
+ border-radius: 50%;
84
+ display: flex;
85
+ align-items: center;
86
+ justify-content: center;
87
+ cursor: pointer;
88
+ transition: all 0.2s;
89
+ }
90
+
91
+ .playback-btn:hover {
92
+ background: rgba(255, 255, 255, 0.2);
93
+ transform: scale(1.1);
94
+ }
95
+
96
+ .playback-btn.active {
97
+ background: rgba(255, 255, 255, 0.3);
98
+ transform: scale(1.1);
99
+ }
100
+ </style>
101
+ </head>
102
+ <body class="bg-gray-900 text-white overflow-hidden">
103
+ <div id="canvas-container">
104
+ <div id="controls" class="space-y-4">
105
+ <h2 class="text-xl font-bold">Solar System Sandbox</h2>
106
+
107
+ <div class="space-y-2">
108
+ <h3 class="font-semibold">Add Celestial Body</h3>
109
+ <div class="flex space-x-2">
110
+ <button id="add-planet" class="bg-blue-600 hover:bg-blue-700 px-3 py-1 rounded">Planet</button>
111
+ <button id="add-star" class="bg-yellow-600 hover:bg-yellow-700 px-3 py-1 rounded">Star</button>
112
+ <button id="add-asteroid" class="bg-gray-600 hover:bg-gray-700 px-3 py-1 rounded">Asteroid</button>
113
+ </div>
114
+ </div>
115
+
116
+ <div class="space-y-2">
117
+ <h3 class="font-semibold">Physics Settings</h3>
118
+ <div class="flex items-center justify-between">
119
+ <label>Gravity:</label>
120
+ <input id="gravity-slider" type="range" min="0" max="2" step="0.1" value="0.5" class="w-32">
121
+ <span id="gravity-value">0.5</span>
122
+ </div>
123
+ <div class="flex items-center justify-between">
124
+ <label>Time Scale:</label>
125
+ <input id="time-scale-slider" type="range" min="0.1" max="5" step="0.1" value="1" class="w-32">
126
+ <span id="time-scale-value">1.0</span>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="space-y-2">
131
+ <h3 class="font-semibold">Visual Effects</h3>
132
+ <div class="flex items-center space-x-2">
133
+ <input id="show-trails" type="checkbox" checked>
134
+ <label for="show-trails">Show Trails</label>
135
+ </div>
136
+ <div class="flex items-center space-x-2">
137
+ <input id="show-gravity" type="checkbox">
138
+ <label for="show-gravity">Show Gravity</label>
139
+ </div>
140
+ </div>
141
+
142
+ <div>
143
+ <button id="clear-all" class="bg-red-600 hover:bg-red-700 px-3 py-1 rounded">Clear All</button>
144
+ </div>
145
+ </div>
146
+
147
+ <div id="playback-controls">
148
+ <button id="rewind-btn" class="playback-btn" title="Rewind (0.5x)">
149
+ <i class="fas fa-backward"></i>
150
+ </button>
151
+ <button id="play-btn" class="playback-btn active" title="Play">
152
+ <i class="fas fa-play"></i>
153
+ </button>
154
+ <button id="pause-btn" class="playback-btn" title="Pause">
155
+ <i class="fas fa-pause"></i>
156
+ </button>
157
+ <button id="fastforward-btn" class="playback-btn" title="Fast Forward (2x)">
158
+ <i class="fas fa-forward"></i>
159
+ </button>
160
+ </div>
161
+
162
+ <div id="info-panel" class="info-panel hidden">
163
+ <h3 class="font-semibold" id="selected-name">Selected Body</h3>
164
+ <div class="grid grid-cols-2 gap-2 mt-2">
165
+ <div>Mass:</div>
166
+ <div id="selected-mass">0</div>
167
+ <div>Radius:</div>
168
+ <div id="selected-radius">0</div>
169
+ <div>Velocity:</div>
170
+ <div id="selected-velocity">0</div>
171
+ <div>Position:</div>
172
+ <div id="selected-position">0, 0</div>
173
+ </div>
174
+ <div class="mt-2 flex space-x-2">
175
+ <button id="delete-body" class="bg-red-600 hover:bg-red-700 px-2 py-1 rounded text-sm">Delete</button>
176
+ <button id="freeze-body" class="bg-gray-600 hover:bg-gray-700 px-2 py-1 rounded text-sm">Freeze</button>
177
+ </div>
178
+ </div>
179
+ </div>
180
+
181
+ <script>
182
+ // Initialize Matter.js
183
+ const { Engine, Render, World, Bodies, Body, Vector, Composite, Mouse, MouseConstraint } = Matter;
184
+
185
+ // Create engine
186
+ const engine = Engine.create({
187
+ gravity: { x: 0, y: 0 },
188
+ enableSleeping: true
189
+ });
190
+
191
+ // Get container dimensions
192
+ const container = document.getElementById('canvas-container');
193
+ const width = container.clientWidth;
194
+ const height = container.clientHeight;
195
+
196
+ // Store celestial bodies and their visual elements
197
+ const bodies = [];
198
+ const visualElements = {};
199
+ const trails = [];
200
+ const gravityLines = [];
201
+
202
+ // Physics settings
203
+ let globalGravity = 0.5;
204
+ let timeScale = 1.0;
205
+ let showTrails = true;
206
+ let showGravity = false;
207
+ let selectedBody = null;
208
+
209
+ // Playback state
210
+ let isPlaying = true;
211
+ let playbackSpeed = 1.0;
212
+ let lastTimestamp = 0;
213
+
214
+ // Colors for different body types
215
+ const bodyColors = {
216
+ star: '#FDB813',
217
+ planet: '#4D8BFF',
218
+ asteroid: '#AAAAAA'
219
+ };
220
+
221
+ // Initialize UI controls
222
+ document.getElementById('gravity-slider').addEventListener('input', (e) => {
223
+ globalGravity = parseFloat(e.target.value);
224
+ document.getElementById('gravity-value').textContent = globalGravity;
225
+ });
226
+
227
+ document.getElementById('time-scale-slider').addEventListener('input', (e) => {
228
+ timeScale = parseFloat(e.target.value);
229
+ document.getElementById('time-scale-value').textContent = timeScale.toFixed(1);
230
+ });
231
+
232
+ document.getElementById('show-trails').addEventListener('change', (e) => {
233
+ showTrails = e.target.checked;
234
+ document.querySelectorAll('.trail').forEach(trail => {
235
+ trail.style.display = showTrails ? 'block' : 'none';
236
+ });
237
+ });
238
+
239
+ document.getElementById('show-gravity').addEventListener('change', (e) => {
240
+ showGravity = e.target.checked;
241
+ document.querySelectorAll('.gravity-line').forEach(line => {
242
+ line.style.display = showGravity ? 'block' : 'none';
243
+ });
244
+ });
245
+
246
+ document.getElementById('clear-all').addEventListener('click', () => {
247
+ // Remove all bodies
248
+ bodies.forEach(body => {
249
+ World.remove(engine.world, body);
250
+ });
251
+ bodies.length = 0;
252
+
253
+ // Remove all visual elements
254
+ Object.keys(visualElements).forEach(id => {
255
+ const element = visualElements[id];
256
+ if (element.parentNode) {
257
+ element.parentNode.removeChild(element);
258
+ }
259
+ });
260
+ Object.keys(visualElements).forEach(key => delete visualElements[key]);
261
+
262
+ // Clear trails
263
+ trails.forEach(trail => {
264
+ if (trail.parentNode) {
265
+ trail.parentNode.removeChild(trail);
266
+ }
267
+ });
268
+ trails.length = 0;
269
+
270
+ // Clear gravity lines
271
+ gravityLines.forEach(line => {
272
+ if (line.parentNode) {
273
+ line.parentNode.removeChild(line);
274
+ }
275
+ });
276
+ gravityLines.length = 0;
277
+
278
+ // Hide info panel
279
+ document.getElementById('info-panel').classList.add('hidden');
280
+ selectedBody = null;
281
+ });
282
+
283
+ // Playback controls
284
+ document.getElementById('play-btn').addEventListener('click', () => {
285
+ isPlaying = true;
286
+ playbackSpeed = 1.0;
287
+ updatePlaybackButtons();
288
+ lastTimestamp = performance.now(); // Reset timestamp when resuming
289
+ });
290
+
291
+ document.getElementById('pause-btn').addEventListener('click', () => {
292
+ isPlaying = false;
293
+ updatePlaybackButtons();
294
+ });
295
+
296
+ document.getElementById('rewind-btn').addEventListener('click', () => {
297
+ isPlaying = true;
298
+ playbackSpeed = 0.5;
299
+ updatePlaybackButtons();
300
+ lastTimestamp = performance.now(); // Reset timestamp when changing speed
301
+ });
302
+
303
+ document.getElementById('fastforward-btn').addEventListener('click', () => {
304
+ isPlaying = true;
305
+ playbackSpeed = 2.0;
306
+ updatePlaybackButtons();
307
+ lastTimestamp = performance.now(); // Reset timestamp when changing speed
308
+ });
309
+
310
+ function updatePlaybackButtons() {
311
+ // Reset all buttons
312
+ document.querySelectorAll('.playback-btn').forEach(btn => {
313
+ btn.classList.remove('active');
314
+ });
315
+
316
+ // Activate the appropriate button
317
+ if (!isPlaying) {
318
+ document.getElementById('pause-btn').classList.add('active');
319
+ } else {
320
+ if (playbackSpeed === 0.5) {
321
+ document.getElementById('rewind-btn').classList.add('active');
322
+ } else if (playbackSpeed === 2.0) {
323
+ document.getElementById('fastforward-btn').classList.add('active');
324
+ } else {
325
+ document.getElementById('play-btn').classList.add('active');
326
+ }
327
+ }
328
+ }
329
+
330
+ // Add body buttons
331
+ document.getElementById('add-planet').addEventListener('click', () => {
332
+ addCelestialBody('planet', width / 2, height / 2);
333
+ });
334
+
335
+ document.getElementById('add-star').addEventListener('click', () => {
336
+ addCelestialBody('star', width / 2, height / 2);
337
+ });
338
+
339
+ document.getElementById('add-asteroid').addEventListener('click', () => {
340
+ addCelestialBody('asteroid', width / 2, height / 2);
341
+ });
342
+
343
+ // Body interaction buttons
344
+ document.getElementById('delete-body').addEventListener('click', () => {
345
+ if (selectedBody) {
346
+ deleteBody(selectedBody);
347
+ document.getElementById('info-panel').classList.add('hidden');
348
+ selectedBody = null;
349
+ }
350
+ });
351
+
352
+ document.getElementById('freeze-body').addEventListener('click', () => {
353
+ if (selectedBody) {
354
+ selectedBody.isStatic = !selectedBody.isStatic;
355
+ Body.setStatic(selectedBody, selectedBody.isStatic);
356
+ document.getElementById('freeze-body').textContent =
357
+ selectedBody.isStatic ? 'Unfreeze' : 'Freeze';
358
+ }
359
+ });
360
+
361
+ // Add a celestial body to the simulation
362
+ function addCelestialBody(type, x, y) {
363
+ let radius, mass, options = {};
364
+
365
+ switch (type) {
366
+ case 'star':
367
+ radius = 30 + Math.random() * 20;
368
+ mass = radius * 100;
369
+ options = {
370
+ render: {
371
+ fillStyle: bodyColors.star,
372
+ strokeStyle: '#FFD700',
373
+ lineWidth: 2
374
+ },
375
+ friction: 0,
376
+ frictionAir: 0,
377
+ frictionStatic: 0,
378
+ restitution: 0.9
379
+ };
380
+ break;
381
+
382
+ case 'planet':
383
+ radius = 10 + Math.random() * 15;
384
+ mass = radius * 20;
385
+ options = {
386
+ render: {
387
+ fillStyle: bodyColors.planet,
388
+ strokeStyle: '#7FB2FF',
389
+ lineWidth: 1
390
+ },
391
+ friction: 0,
392
+ frictionAir: 0.01,
393
+ frictionStatic: 0,
394
+ restitution: 0.7
395
+ };
396
+ break;
397
+
398
+ case 'asteroid':
399
+ radius = 3 + Math.random() * 7;
400
+ mass = radius * 5;
401
+ options = {
402
+ render: {
403
+ fillStyle: bodies.asteroid,
404
+ strokeStyle: '#DDDDDD',
405
+ lineWidth: 1
406
+ },
407
+ friction: 0,
408
+ frictionAir: 0.02,
409
+ frictionStatic: 0,
410
+ restitution: 0.5
411
+ };
412
+ break;
413
+ }
414
+
415
+ // Create physics body
416
+ const body = Bodies.circle(x, y, radius, options);
417
+ body.mass = mass;
418
+ body.type = type;
419
+ body.name = `${type.charAt(0).toUpperCase() + type.slice(1)}-${bodies.length + 1}`;
420
+
421
+ // Add some initial velocity if not a star
422
+ if (type !== 'star') {
423
+ const angle = Math.random() * Math.PI * 2;
424
+ const speed = 1 + Math.random() * 3;
425
+ Body.setVelocity(body, {
426
+ x: Math.cos(angle) * speed,
427
+ y: Math.sin(angle) * speed
428
+ });
429
+ } else {
430
+ body.isStatic = true;
431
+ }
432
+
433
+ // Add to world
434
+ World.add(engine.world, body);
435
+ bodies.push(body);
436
+
437
+ // Create visual element
438
+ createVisualElement(body);
439
+
440
+ return body;
441
+ }
442
+
443
+ // Create a visual representation of a body
444
+ function createVisualElement(body) {
445
+ const element = document.createElement('div');
446
+ element.className = 'planet';
447
+ element.style.width = `${body.circleRadius * 2}px`;
448
+ element.style.height = `${body.circleRadius * 2}px`;
449
+ element.style.left = `${body.position.x - body.circleRadius}px`;
450
+ element.style.top = `${body.position.y - body.circleRadius}px`;
451
+
452
+ // Set color based on type
453
+ element.style.backgroundColor = bodyColors[body.type];
454
+
455
+ // Add glow effect for stars
456
+ if (body.type === 'star') {
457
+ element.style.boxShadow = `0 0 ${body.circleRadius * 2}px ${bodyColors.star}`;
458
+ }
459
+
460
+ // Add click event
461
+ element.addEventListener('click', (e) => {
462
+ e.stopPropagation();
463
+ selectBody(body);
464
+ });
465
+
466
+ // Add drag event
467
+ element.addEventListener('mousedown', startDrag);
468
+
469
+ container.appendChild(element);
470
+ visualElements[body.id] = element;
471
+ }
472
+
473
+ // Select a body and show its info
474
+ function selectBody(body) {
475
+ selectedBody = body;
476
+
477
+ // Update info panel
478
+ document.getElementById('selected-name').textContent = body.name;
479
+ document.getElementById('selected-mass').textContent = body.mass.toFixed(2);
480
+ document.getElementById('selected-radius').textContent = body.circleRadius.toFixed(2);
481
+
482
+ const velocity = Vector.magnitude(body.velocity);
483
+ document.getElementById('selected-velocity').textContent = velocity.toFixed(2);
484
+
485
+ document.getElementById('selected-position').textContent =
486
+ `${body.position.x.toFixed(0)}, ${body.position.y.toFixed(0)}`;
487
+
488
+ document.getElementById('freeze-body').textContent =
489
+ body.isStatic ? 'Unfreeze' : 'Freeze';
490
+
491
+ document.getElementById('info-panel').classList.remove('hidden');
492
+ }
493
+
494
+ // Delete a body
495
+ function deleteBody(body) {
496
+ // Remove from physics world
497
+ World.remove(engine.world, body);
498
+
499
+ // Remove from bodies array
500
+ const index = bodies.indexOf(body);
501
+ if (index > -1) {
502
+ bodies.splice(index, 1);
503
+ }
504
+
505
+ // Remove visual element
506
+ const element = visualElements[body.id];
507
+ if (element && element.parentNode) {
508
+ element.parentNode.removeChild(element);
509
+ }
510
+ delete visualElements[body.id];
511
+
512
+ // Remove any trails associated with this body
513
+ const bodyTrails = trails.filter(t => t.dataset.bodyId === body.id.toString());
514
+ bodyTrails.forEach(trail => {
515
+ if (trail.parentNode) {
516
+ trail.parentNode.removeChild(trail);
517
+ }
518
+ const trailIndex = trails.indexOf(trail);
519
+ if (trailIndex > -1) {
520
+ trails.splice(trailIndex, 1);
521
+ }
522
+ });
523
+ }
524
+
525
+ // Start dragging a body
526
+ function startDrag(e) {
527
+ e.preventDefault();
528
+ e.stopPropagation();
529
+
530
+ const element = e.target;
531
+ const bodyId = Object.keys(visualElements).find(id => visualElements[id] === element);
532
+ const body = bodies.find(b => b.id.toString() === bodyId);
533
+
534
+ if (!body) return;
535
+
536
+ selectBody(body);
537
+
538
+ // Calculate offset from mouse to body center
539
+ const rect = element.getBoundingClientRect();
540
+ const offsetX = e.clientX - rect.left - body.circleRadius;
541
+ const offsetY = e.clientY - rect.top - body.circleRadius;
542
+
543
+ // Set body to static while dragging
544
+ const wasStatic = body.isStatic;
545
+ Body.setStatic(body, true);
546
+
547
+ function moveBody(e) {
548
+ const x = e.clientX - offsetX;
549
+ const y = e.clientY - offsetY;
550
+
551
+ Body.setPosition(body, { x, y });
552
+
553
+ // Update visual element
554
+ const visual = visualElements[body.id];
555
+ if (visual) {
556
+ visual.style.left = `${x - body.circleRadius}px`;
557
+ visual.style.top = `${y - body.circleRadius}px`;
558
+ }
559
+ }
560
+
561
+ function endDrag(e) {
562
+ document.removeEventListener('mousemove', moveBody);
563
+ document.removeEventListener('mouseup', endDrag);
564
+
565
+ // Restore static state
566
+ Body.setStatic(body, wasStatic);
567
+
568
+ // If not static, set velocity based on drag speed
569
+ if (!wasStatic) {
570
+ const x = e.clientX - offsetX;
571
+ const y = e.clientY - offsetY;
572
+
573
+ const deltaX = x - body.position.x;
574
+ const deltaY = y - body.position.y;
575
+
576
+ Body.setVelocity(body, {
577
+ x: deltaX * 0.5,
578
+ y: deltaY * 0.5
579
+ });
580
+ }
581
+ }
582
+
583
+ document.addEventListener('mousemove', moveBody);
584
+ document.addEventListener('mouseup', endDrag);
585
+ }
586
+
587
+ // Click on empty space to deselect
588
+ container.addEventListener('click', (e) => {
589
+ if (e.target === container) {
590
+ document.getElementById('info-panel').classList.add('hidden');
591
+ selectedBody = null;
592
+ }
593
+ });
594
+
595
+ // Add mouse control for creating gravity wells
596
+ const mouse = Mouse.create(container);
597
+ const mouseConstraint = MouseConstraint.create(engine, {
598
+ mouse: mouse,
599
+ constraint: {
600
+ stiffness: 0.2,
601
+ render: {
602
+ visible: false
603
+ }
604
+ }
605
+ });
606
+
607
+ World.add(engine.world, mouseConstraint);
608
+
609
+ // Add asteroids on right click
610
+ container.addEventListener('contextmenu', (e) => {
611
+ e.preventDefault();
612
+ addCelestialBody('asteroid', e.clientX, e.clientY);
613
+ });
614
+
615
+ // Main animation loop
616
+ function run(timestamp) {
617
+ if (!lastTimestamp) {
618
+ lastTimestamp = timestamp;
619
+ }
620
+
621
+ const deltaTime = timestamp - lastTimestamp;
622
+ lastTimestamp = timestamp;
623
+
624
+ if (isPlaying) {
625
+ // Calculate the time step based on playback speed and time scale
626
+ const timeStep = deltaTime * 0.06 * playbackSpeed * timeScale;
627
+
628
+ // Update physics
629
+ Engine.update(engine, timeStep);
630
+
631
+ // Apply custom gravity between bodies
632
+ applyGravity();
633
+
634
+ // Update visual elements
635
+ updateVisuals();
636
+
637
+ // Add trails
638
+ if (showTrails) {
639
+ addTrails();
640
+ }
641
+
642
+ // Add gravity visualization
643
+ if (showGravity) {
644
+ visualizeGravity();
645
+ }
646
+ }
647
+
648
+ requestAnimationFrame(run);
649
+ }
650
+
651
+ // Apply gravity between all bodies
652
+ function applyGravity() {
653
+ for (let i = 0; i < bodies.length; i++) {
654
+ const bodyA = bodies[i];
655
+
656
+ for (let j = i + 1; j < bodies.length; j++) {
657
+ const bodyB = bodies[j];
658
+
659
+ // Skip if either body is static
660
+ if (bodyA.isStatic && bodyB.isStatic) continue;
661
+
662
+ // Calculate distance between bodies
663
+ const direction = Vector.sub(bodyB.position, bodyA.position);
664
+ const distance = Vector.magnitude(direction);
665
+ const minDistance = bodyA.circleRadius + bodyB.circleRadius;
666
+
667
+ // Skip if bodies are too close (to prevent extreme forces)
668
+ if (distance < minDistance) continue;
669
+
670
+ // Calculate gravitational force (Newton's law of universal gravitation)
671
+ const forceMagnitude = globalGravity * bodyA.mass * bodyB.mass / (distance * distance);
672
+ const force = Vector.normalise(direction);
673
+ Vector.mult(force, forceMagnitude);
674
+
675
+ // Apply forces to both bodies
676
+ if (!bodyA.isStatic) {
677
+ Body.applyForce(bodyA, bodyA.position, {
678
+ x: force.x * 0.5,
679
+ y: force.y * 0.5
680
+ });
681
+ }
682
+
683
+ if (!bodyB.isStatic) {
684
+ Body.applyForce(bodyB, bodyB.position, {
685
+ x: -force.x * 0.5,
686
+ y: -force.y * 0.5
687
+ });
688
+ }
689
+ }
690
+ }
691
+ }
692
+
693
+ // Update positions of visual elements
694
+ function updateVisuals() {
695
+ bodies.forEach(body => {
696
+ const element = visualElements[body.id];
697
+ if (element) {
698
+ element.style.left = `${body.position.x - body.circleRadius}px`;
699
+ element.style.top = `${body.position.y - body.circleRadius}px`;
700
+
701
+ // Rotate planets slightly for visual effect
702
+ if (body.type === 'planet') {
703
+ const rotation = (body.angle * 180 / Math.PI) % 360;
704
+ element.style.transform = `rotate(${rotation}deg)`;
705
+ }
706
+ }
707
+ });
708
+
709
+ // Update info panel if a body is selected
710
+ if (selectedBody) {
711
+ document.getElementById('selected-velocity').textContent =
712
+ Vector.magnitude(selectedBody.velocity).toFixed(2);
713
+ document.getElementById('selected-position').textContent =
714
+ `${selectedBody.position.x.toFixed(0)}, ${selectedBody.position.y.toFixed(0)}`;
715
+ }
716
+ }
717
+
718
+ // Add motion trails behind moving bodies
719
+ function addTrails() {
720
+ bodies.forEach(body => {
721
+ // Skip static bodies
722
+ if (body.isStatic) return;
723
+
724
+ // Skip if velocity is very low
725
+ if (Vector.magnitude(body.velocity) < 0.1) return;
726
+
727
+ // Create a trail element
728
+ const trail = document.createElement('div');
729
+ trail.className = 'trail';
730
+ trail.style.width = `${body.circleRadius * 0.5}px`;
731
+ trail.style.height = `${body.circleRadius * 0.5}px`;
732
+ trail.style.left = `${body.position.x - body.circleRadius * 0.25}px`;
733
+ trail.style.top = `${body.position.y - body.circleRadius * 0.25}px`;
734
+ trail.dataset.bodyId = body.id;
735
+
736
+ // Set color based on body type
737
+ trail.style.backgroundColor = bodyColors[body.type];
738
+
739
+ container.appendChild(trail);
740
+ trails.push(trail);
741
+
742
+ // Fade out and remove old trails
743
+ if (trails.length > 100) {
744
+ const oldTrail = trails.shift();
745
+ if (oldTrail.parentNode) {
746
+ oldTrail.parentNode.removeChild(oldTrail);
747
+ }
748
+ }
749
+ });
750
+ }
751
+
752
+ // Visualize gravity between bodies
753
+ function visualizeGravity() {
754
+ // Clear old gravity lines
755
+ gravityLines.forEach(line => {
756
+ if (line.parentNode) {
757
+ line.parentNode.removeChild(line);
758
+ }
759
+ });
760
+ gravityLines.length = 0;
761
+
762
+ // Create new gravity lines between close bodies
763
+ for (let i = 0; i < bodies.length; i++) {
764
+ const bodyA = bodies[i];
765
+
766
+ for (let j = i + 1; j < bodies.length; j++) {
767
+ const bodyB = bodies[j];
768
+
769
+ // Calculate distance
770
+ const direction = Vector.sub(bodyB.position, bodyA.position);
771
+ const distance = Vector.magnitude(direction);
772
+ const maxDistance = Math.min(width, height) * 0.4;
773
+
774
+ // Only draw lines for relatively close bodies
775
+ if (distance < maxDistance) {
776
+ const line = document.createElement('div');
777
+ line.className = 'gravity-line';
778
+ line.style.width = `${distance}px`;
779
+ line.style.left = `${bodyA.position.x}px`;
780
+ line.style.top = `${bodyA.position.y}px`;
781
+
782
+ // Calculate angle
783
+ const angle = Math.atan2(bodyB.position.y - bodyA.position.y,
784
+ bodyB.position.x - bodyA.position.x);
785
+ line.style.transform = `rotate(${angle}rad)`;
786
+
787
+ // Set opacity based on distance (closer = more opaque)
788
+ const opacity = 1 - (distance / maxDistance);
789
+ line.style.opacity = opacity * 0.5;
790
+
791
+ container.appendChild(line);
792
+ gravityLines.push(line);
793
+ }
794
+ }
795
+ }
796
+ }
797
+
798
+ // Start with a simple solar system
799
+ function initSolarSystem() {
800
+ // Add a central star
801
+ const sun = addCelestialBody('star', width / 2, height / 2);
802
+ sun.mass = 10000; // Very massive sun
803
+
804
+ // Add some planets
805
+ for (let i = 0; i < 5; i++) {
806
+ const angle = Math.random() * Math.PI * 2;
807
+ const distance = 100 + Math.random() * 200;
808
+
809
+ const planet = addCelestialBody('planet',
810
+ width / 2 + Math.cos(angle) * distance,
811
+ height / 2 + Math.sin(angle) * distance
812
+ );
813
+
814
+ // Set initial velocity for orbit
815
+ const orbitSpeed = Math.sqrt(sun.mass / distance) * 0.3;
816
+ Body.setVelocity(planet, {
817
+ x: Math.cos(angle + Math.PI/2) * orbitSpeed,
818
+ y: Math.sin(angle + Math.PI/2) * orbitSpeed
819
+ });
820
+ }
821
+
822
+ // Add some asteroids
823
+ for (let i = 0; i < 10; i++) {
824
+ const angle = Math.random() * Math.PI * 2;
825
+ const distance = 200 + Math.random() * 300;
826
+
827
+ addCelestialBody('asteroid',
828
+ width / 2 + Math.cos(angle) * distance,
829
+ height / 2 + Math.sin(angle) * distance
830
+ );
831
+ }
832
+ }
833
+
834
+ // Start the simulation
835
+ initSolarSystem();
836
+ requestAnimationFrame(run);
837
+ </script>
838
+ <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=ItsMeDevRoland/se" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
839
+ </html>