arirajuns commited on
Commit
76bfa1a
·
verified ·
1 Parent(s): cb97404

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +373 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Space3
3
- emoji: 🦀
4
- colorFrom: yellow
5
- colorTo: purple
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: space3
3
+ emoji: 🐳
4
+ colorFrom: pink
5
+ colorTo: blue
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,373 @@
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, maximum-scale=1.0, user-scalable=no">
6
+ <title>Pendulum Challenge</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
+ .pendulum-arm {
12
+ transform-origin: top center;
13
+ touch-action: none;
14
+ }
15
+ .target {
16
+ transition: all 0.3s ease;
17
+ touch-action: none;
18
+ }
19
+ .target-hit {
20
+ transform: scale(1.2);
21
+ opacity: 0;
22
+ }
23
+ #game-container {
24
+ background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
25
+ touch-action: none;
26
+ }
27
+ .amplitude-indicator {
28
+ background: linear-gradient(to right, #4facfe 0%, #00f2fe 100%);
29
+ }
30
+ .frequency-indicator {
31
+ background: linear-gradient(to right, #a1c4fd 0%, #c2e9fb 100%);
32
+ }
33
+ .pendulum-bob {
34
+ box-shadow: 0 0 20px rgba(255,215,0,0.7);
35
+ }
36
+ body {
37
+ -webkit-tap-highlight-color: transparent;
38
+ -webkit-touch-callout: none;
39
+ -webkit-user-select: none;
40
+ user-select: none;
41
+ }
42
+ .physics-card {
43
+ max-height: 0;
44
+ overflow: hidden;
45
+ transition: max-height 0.3s ease;
46
+ }
47
+ .physics-card.open {
48
+ max-height: 500px;
49
+ }
50
+ </style>
51
+ </head>
52
+ <body class="bg-gray-900 text-white min-h-screen flex flex-col items-center justify-start p-2">
53
+ <div class="w-full max-w-md">
54
+ <header class="text-center mb-4 sticky top-0 bg-gray-900 z-10 pt-2 pb-2">
55
+ <h1 class="text-2xl font-bold mb-1 text-yellow-300">Pendulum Challenge</h1>
56
+ <p class="text-sm text-gray-300">Swing to hit targets!</p>
57
+ </header>
58
+
59
+ <!-- Mobile Controls Info -->
60
+ <div class="bg-blue-900 bg-opacity-50 rounded-lg p-2 mb-3 text-sm flex items-center">
61
+ <i class="fas fa-info-circle mr-2 text-blue-300"></i>
62
+ <span>Drag the gold ball to swing. Hit targets when amplitude matches.</span>
63
+ </div>
64
+
65
+ <div class="relative w-full aspect-[3/4] rounded-xl overflow-hidden shadow-2xl mb-3" id="game-container">
66
+ <div id="pendulum" class="absolute top-0 left-1/2 transform -translate-x-1/2">
67
+ <div class="pendulum-arm w-1 h-48 md:h-64 bg-gray-300 mx-auto relative">
68
+ <div class="pendulum-bob absolute bottom-0 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-10 h-10 md:w-12 md:h-12 rounded-full bg-yellow-500 border-4 border-yellow-600"></div>
69
+ </div>
70
+ </div>
71
+ <div id="targets" class="absolute inset-0"></div>
72
+ <div class="absolute bottom-2 left-2 bg-black bg-opacity-50 p-1 rounded">
73
+ <div class="flex items-center gap-1 text-sm">
74
+ <span class="text-yellow-400"><i class="fas fa-bullseye"></i></span>
75
+ <span id="score">0</span>
76
+ </div>
77
+ </div>
78
+ </div>
79
+
80
+ <div class="grid grid-cols-2 gap-2 mb-3">
81
+ <div class="bg-gray-800 p-2 rounded-lg">
82
+ <h3 class="text-sm font-semibold mb-1 text-center">Amplitude</h3>
83
+ <div class="amplitude-indicator h-3 rounded-full overflow-hidden">
84
+ <div id="amplitude-bar" class="h-full bg-blue-500 w-0"></div>
85
+ </div>
86
+ <div class="text-center mt-1 text-xs">
87
+ <span id="amplitude-value">0°</span>
88
+ </div>
89
+ </div>
90
+ <div class="bg-gray-800 p-2 rounded-lg">
91
+ <h3 class="text-sm font-semibold mb-1 text-center">Frequency</h3>
92
+ <div class="frequency-indicator h-3 rounded-full overflow-hidden">
93
+ <div id="frequency-bar" class="h-full bg-blue-400 w-0"></div>
94
+ </div>
95
+ <div class="text-center mt-1 text-xs">
96
+ <span id="frequency-value">0 Hz</span>
97
+ </div>
98
+ </div>
99
+ </div>
100
+
101
+ <!-- Collapsible Physics Info -->
102
+ <div class="bg-gray-800 rounded-lg mb-3 overflow-hidden">
103
+ <div class="flex justify-between items-center p-2 cursor-pointer" id="physics-toggle">
104
+ <h2 class="text-lg font-bold text-yellow-300">Physics Info</h2>
105
+ <i class="fas fa-chevron-down transition-transform duration-300" id="physics-chevron"></i>
106
+ </div>
107
+ <div class="physics-card" id="physics-content">
108
+ <div class="p-3 pt-0 space-y-3">
109
+ <div>
110
+ <h3 class="font-semibold">Pendulum Motion</h3>
111
+ <p class="text-xs text-gray-300">Swinging under gravity's influence, demonstrating harmonic motion.</p>
112
+ </div>
113
+ <div>
114
+ <h3 class="font-semibold">Period (T)</h3>
115
+ <p class="text-xs text-gray-300">T = 2π√(L/g)<br>L = length, g = gravity (9.8 m/s²)</p>
116
+ </div>
117
+ <div>
118
+ <h3 class="font-semibold">Amplitude</h3>
119
+ <p class="text-xs text-gray-300">Maximum angle from rest position.</p>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ <button id="restart-btn" class="w-full bg-yellow-600 hover:bg-yellow-700 text-white font-bold py-3 px-4 rounded transition duration-300 mb-2">
126
+ <i class="fas fa-redo mr-2"></i> Restart Game
127
+ </button>
128
+ </div>
129
+
130
+ <script>
131
+ // Game variables
132
+ let score = 0;
133
+ let amplitude = 0;
134
+ let frequency = 0;
135
+ let pendulumAngle = 0;
136
+ let angularVelocity = 0;
137
+ let isDragging = false;
138
+ let lastTime = 0;
139
+ let pendulumLength = 192; // pixels (shorter for mobile)
140
+ let gravity = 0.4; // pixels per frame squared (slower for mobile)
141
+ let damping = 0.99; // damping factor
142
+ let targets = [];
143
+ let animationId;
144
+ let gameStarted = false;
145
+ let touchStartAngle = 0;
146
+
147
+ // DOM elements
148
+ const pendulum = document.getElementById('pendulum');
149
+ const pendulumArm = document.querySelector('.pendulum-arm');
150
+ const pendulumBob = document.querySelector('.pendulum-bob');
151
+ const targetsContainer = document.getElementById('targets');
152
+ const scoreDisplay = document.getElementById('score');
153
+ const amplitudeValue = document.getElementById('amplitude-value');
154
+ const amplitudeBar = document.getElementById('amplitude-bar');
155
+ const frequencyValue = document.getElementById('frequency-value');
156
+ const frequencyBar = document.getElementById('frequency-bar');
157
+ const restartBtn = document.getElementById('restart-btn');
158
+ const gameContainer = document.getElementById('game-container');
159
+ const physicsToggle = document.getElementById('physics-toggle');
160
+ const physicsContent = document.getElementById('physics-content');
161
+ const physicsChevron = document.getElementById('physics-chevron');
162
+
163
+ // Initialize game
164
+ function initGame() {
165
+ score = 0;
166
+ scoreDisplay.textContent = score;
167
+ targetsContainer.innerHTML = '';
168
+ targets = [];
169
+
170
+ // Create initial targets (fewer and larger for mobile)
171
+ createTarget(30, 30, 100);
172
+ createTarget(45, window.innerWidth * 0.7, 150);
173
+ createTarget(60, window.innerWidth * 0.3, 200);
174
+
175
+ // Reset pendulum
176
+ pendulumAngle = 0;
177
+ angularVelocity = 0;
178
+ updatePendulumPosition();
179
+ updatePhysicsDisplays();
180
+
181
+ if (!gameStarted) {
182
+ setupEventListeners();
183
+ gameStarted = true;
184
+ }
185
+
186
+ startAnimation();
187
+ }
188
+
189
+ // Create a target at a specific angle and position
190
+ function createTarget(requiredAmplitude, x, y) {
191
+ const target = document.createElement('div');
192
+ target.className = 'target absolute w-12 h-12 md:w-16 md:h-16 rounded-full bg-red-500 border-4 border-red-700 flex items-center justify-center text-white font-bold cursor-pointer transform -translate-x-1/2 -translate-y-1/2';
193
+ target.style.left = `${x}px`;
194
+ target.style.top = `${y}px`;
195
+ target.textContent = `${requiredAmplitude}°`;
196
+ target.dataset.amplitude = requiredAmplitude;
197
+
198
+ // Make targets easier to hit on mobile
199
+ target.addEventListener('click', () => {
200
+ if (Math.abs(amplitude) >= requiredAmplitude * 0.8) {
201
+ hitTarget(target);
202
+ }
203
+ });
204
+
205
+ targetsContainer.appendChild(target);
206
+ targets.push({
207
+ element: target,
208
+ x: x,
209
+ y: y,
210
+ requiredAmplitude: requiredAmplitude,
211
+ hit: false
212
+ });
213
+
214
+ return target;
215
+ }
216
+
217
+ // Handle target hit
218
+ function hitTarget(targetElement) {
219
+ const target = targets.find(t => t.element === targetElement);
220
+ if (target && !target.hit) {
221
+ target.hit = true;
222
+ targetElement.classList.add('target-hit');
223
+ score += Math.floor(target.requiredAmplitude * 1.5);
224
+ scoreDisplay.textContent = score;
225
+
226
+ setTimeout(() => {
227
+ targetElement.remove();
228
+ // Create a new target at random position
229
+ const newX = 50 + Math.random() * (gameContainer.offsetWidth - 100);
230
+ const newY = 50 + Math.random() * (gameContainer.offsetHeight - 100);
231
+ const newAmplitude = 20 + Math.floor(Math.random() * 50);
232
+ createTarget(newAmplitude, newX, newY);
233
+ }, 300);
234
+ }
235
+ }
236
+
237
+ // Update pendulum position based on angle
238
+ function updatePendulumPosition() {
239
+ pendulumArm.style.transform = `rotate(${pendulumAngle}deg)`;
240
+ }
241
+
242
+ // Update physics displays
243
+ function updatePhysicsDisplays() {
244
+ amplitude = Math.abs(pendulumAngle);
245
+ amplitudeValue.textContent = `${amplitude.toFixed(1)}°`;
246
+ amplitudeBar.style.width = `${Math.min(100, amplitude)}%`;
247
+
248
+ // Calculate frequency (approximate)
249
+ if (amplitude > 5) {
250
+ const period = 2 * Math.PI * Math.sqrt(pendulumLength / (gravity * 100));
251
+ frequency = 1 / period;
252
+ frequencyValue.textContent = `${frequency.toFixed(3)} Hz`;
253
+ frequencyBar.style.width = `${Math.min(100, frequency * 150)}%`;
254
+ } else {
255
+ frequency = 0;
256
+ frequencyValue.textContent = "0 Hz";
257
+ frequencyBar.style.width = "0%";
258
+ }
259
+ }
260
+
261
+ // Physics update
262
+ function updatePhysics(timestamp) {
263
+ if (!lastTime) lastTime = timestamp;
264
+ const deltaTime = (timestamp - lastTime) / 16; // Normalize to ~60fps
265
+ lastTime = timestamp;
266
+
267
+ if (!isDragging) {
268
+ // Apply gravity
269
+ const angularAcceleration = (-gravity / pendulumLength) * Math.sin(pendulumAngle * Math.PI / 180);
270
+ angularVelocity += angularAcceleration * deltaTime;
271
+ angularVelocity *= damping;
272
+ pendulumAngle += angularVelocity * deltaTime;
273
+
274
+ updatePendulumPosition();
275
+ updatePhysicsDisplays();
276
+ }
277
+
278
+ animationId = requestAnimationFrame(updatePhysics);
279
+ }
280
+
281
+ // Start animation loop
282
+ function startAnimation() {
283
+ lastTime = 0;
284
+ cancelAnimationFrame(animationId);
285
+ animationId = requestAnimationFrame(updatePhysics);
286
+ }
287
+
288
+ // Calculate angle from touch position
289
+ function getAngleFromTouch(touchX, touchY) {
290
+ const rect = gameContainer.getBoundingClientRect();
291
+ const centerX = rect.left + rect.width / 2;
292
+ const centerY = rect.top + 10; // Pivot point
293
+
294
+ const deltaX = touchX - centerX;
295
+ const deltaY = touchY - centerY;
296
+
297
+ return Math.atan2(deltaX, deltaY) * (180 / Math.PI) - 90;
298
+ }
299
+
300
+ // Event listeners setup
301
+ function setupEventListeners() {
302
+ // Touch controls for pendulum
303
+ pendulumBob.addEventListener('touchstart', (e) => {
304
+ e.preventDefault();
305
+ isDragging = true;
306
+ const touch = e.touches[0];
307
+ touchStartAngle = getAngleFromTouch(touch.clientX, touch.clientY) - pendulumAngle;
308
+
309
+ // Visual feedback
310
+ pendulumBob.classList.add('scale-110');
311
+ });
312
+
313
+ document.addEventListener('touchmove', (e) => {
314
+ if (!isDragging) return;
315
+ e.preventDefault();
316
+ const touch = e.touches[0];
317
+ pendulumAngle = getAngleFromTouch(touch.clientX, touch.clientY) - touchStartAngle;
318
+ angularVelocity = 0;
319
+
320
+ updatePendulumPosition();
321
+ updatePhysicsDisplays();
322
+ });
323
+
324
+ document.addEventListener('touchend', () => {
325
+ if (isDragging) {
326
+ isDragging = false;
327
+ pendulumBob.classList.remove('scale-110');
328
+ // Give the pendulum a small initial velocity based on release angle
329
+ angularVelocity = -pendulumAngle * 0.015; // Slower for mobile
330
+ }
331
+ });
332
+
333
+ // Click targets (also works for touch)
334
+ targetsContainer.addEventListener('click', (e) => {
335
+ if (e.target.classList.contains('target')) {
336
+ const requiredAmplitude = parseFloat(e.target.dataset.amplitude);
337
+ if (Math.abs(amplitude) >= requiredAmplitude * 0.8) {
338
+ hitTarget(e.target);
339
+ }
340
+ }
341
+ });
342
+
343
+ // Restart button
344
+ restartBtn.addEventListener('click', initGame);
345
+
346
+ // Physics info toggle
347
+ physicsToggle.addEventListener('click', () => {
348
+ physicsContent.classList.toggle('open');
349
+ physicsChevron.classList.toggle('rotate-180');
350
+ });
351
+
352
+ // Prevent scrolling when touching the game
353
+ document.addEventListener('touchmove', (e) => {
354
+ if (isDragging) {
355
+ e.preventDefault();
356
+ }
357
+ }, { passive: false });
358
+ }
359
+
360
+ // Start the game
361
+ initGame();
362
+
363
+ // Handle window resize
364
+ window.addEventListener('resize', () => {
365
+ // Reposition targets on resize
366
+ targets.forEach(target => {
367
+ target.element.style.left = `${target.x}px`;
368
+ target.element.style.top = `${target.y}px`;
369
+ });
370
+ });
371
+ </script>
372
+ <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=arirajuns/space3" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
373
+ </html>