ParulPandey commited on
Commit
e77ab3b
·
verified ·
1 Parent(s): e701f60

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +275 -18
index.html CHANGED
@@ -1,19 +1,276 @@
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>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>MediaPipe Wrecking Ball & Block Stacker</title>
6
+ <style>
7
+ body {
8
+ margin: 0;
9
+ overflow: hidden;
10
+ background-color: #222;
11
+ display: flex;
12
+ justify-content: center;
13
+ align-items: center;
14
+ height: 100vh;
15
+ }
16
+ #canvasContainer {
17
+ position: relative;
18
+ width: 800px;
19
+ height: 600px;
20
+ box-shadow: 0 0 15px rgba(0,0,0,0.6);
21
+ overflow: hidden;
22
+ background-color: #333;
23
+ }
24
+ #videoInput {
25
+ position: absolute;
26
+ top: 0;
27
+ left: 0;
28
+ width: 100%;
29
+ height: 100%;
30
+ object-fit: cover;
31
+ z-index: 0;
32
+ transform: scaleX(-1);
33
+ }
34
+ #handGestureOverlay {
35
+ position: absolute;
36
+ top: 0;
37
+ left: 0;
38
+ width: 100%;
39
+ height: 100%;
40
+ pointer-events: none;
41
+ z-index: 2;
42
+ }
43
+ </style>
44
+ </head>
45
+ <body>
46
+ <div id="canvasContainer">
47
+ <video id="videoInput" autoplay playsinline></video>
48
+ <canvas id="handGestureOverlay"></canvas>
49
+ </div>
50
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js"></script>
51
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"></script>
52
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
53
+ <script>
54
+ const videoElement = document.getElementById('videoInput');
55
+ const canvasContainer = document.getElementById('canvasContainer');
56
+ const handGestureOverlayCanvas = document.getElementById('handGestureOverlay');
57
+ const handGestureOverlayCtx = handGestureOverlayCanvas.getContext('2d');
58
+
59
+ const RENDER_WIDTH = 800;
60
+ const RENDER_HEIGHT = 600;
61
+ handGestureOverlayCanvas.width = RENDER_WIDTH;
62
+ handGestureOverlayCanvas.height = RENDER_HEIGHT;
63
+
64
+ const MIRROR_COORDS_FOR_DISPLAY_AND_PHYSICS = true;
65
+ let handWorldX = 0, handWorldY = 0;
66
+ let isPinching = false;
67
+ let grabbedBody = null;
68
+ let grabConstraint = null;
69
+ let blockGrabOffset = {x: 0, y: 0};
70
+
71
+ const PINCH_THRESHOLD_PX = 45;
72
+ const GRAB_RADIUS_BALL_PX = 70;
73
+ const GRAB_RADIUS_BLOCK_PX = 45;
74
+ const GRAB_STIFFNESS = 0.4;
75
+ const LANDMARK_RADIUS = 12;
76
+ const LANDMARK_COLOR = '#00BCD4';
77
+
78
+ const hands = new Hands({locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`});
79
+ hands.setOptions({
80
+ maxNumHands: 1,
81
+ modelComplexity: 1,
82
+ minDetectionConfidence: 0.65,
83
+ minTrackingConfidence: 0.65
84
+ });
85
+
86
+ const { Engine, Render, Runner, Composites, Composite, Constraint, Bodies, Body, Events, Vector, Bounds } = Matter;
87
+
88
+ var Example = Example || {};
89
+ Example.wreckingBallAndBlocks = function() {
90
+ var engine = Engine.create(), world = engine.world;
91
+ var render = Render.create({
92
+ element: canvasContainer,
93
+ engine: engine,
94
+ options: {
95
+ width: RENDER_WIDTH,
96
+ height: RENDER_HEIGHT,
97
+ wireframes: false,
98
+ background: 'transparent',
99
+ showAngleIndicator: false
100
+ }
101
+ });
102
+ if (render.canvas) {
103
+ render.canvas.style.position = 'absolute';
104
+ render.canvas.style.top = '0';
105
+ render.canvas.style.left = '0';
106
+ render.canvas.style.zIndex = '1';
107
+ }
108
+ Render.run(render);
109
+ var runner = Runner.create();
110
+ Runner.run(runner, engine);
111
+
112
+ var rows = 12; // Taller tower
113
+ var blockHeight = 45;
114
+ var blockWidth = 45;
115
+ var stackStartX = RENDER_WIDTH * 0.65;
116
+ var yy = RENDER_HEIGHT - 15 - blockHeight * rows;
117
+
118
+ var stack = Composites.stack(stackStartX, yy, 5, rows, 0, 0, function(x, y) {
119
+ return Bodies.rectangle(x, y, blockWidth, blockHeight, {
120
+ render: {
121
+ fillStyle: '#27ae60',
122
+ strokeStyle: '#fff', // White boundary
123
+ lineWidth: 2 // Make boundary visible
124
+ },
125
+ friction: 0.7,
126
+ restitution: 0.05
127
+ });
128
+ });
129
+
130
+ var ball = Bodies.circle(RENDER_WIDTH * 0.25, RENDER_HEIGHT * 0.65, 40, {
131
+ density: 0.04,
132
+ frictionAir: 0.005,
133
+ render: { fillStyle: '#c0392b' }
134
+ });
135
+
136
+ Composite.add(world, [
137
+ stack,
138
+ ball,
139
+ Constraint.create({
140
+ pointA: { x: RENDER_WIDTH * 0.35, y: RENDER_HEIGHT * 0.1 },
141
+ bodyB: ball,
142
+ stiffness: 0.04,
143
+ damping: 0.05,
144
+ length: RENDER_HEIGHT * 0.55,
145
+ render: { strokeStyle: '#7f8c8d', lineWidth: 2 }
146
+ }),
147
+ Bodies.rectangle(RENDER_WIDTH/2, -25, RENDER_WIDTH, 50, { isStatic: true, render: { fillStyle: '#333'} }),
148
+ Bodies.rectangle(RENDER_WIDTH/2, RENDER_HEIGHT + 25, RENDER_WIDTH, 50, { isStatic: true, render: { fillStyle: '#333'} }),
149
+ Bodies.rectangle(RENDER_WIDTH + 25, RENDER_HEIGHT/2, 50, RENDER_HEIGHT, { isStatic: true, render: { fillStyle: '#333'} }),
150
+ Bodies.rectangle(-25, RENDER_HEIGHT/2, 50, RENDER_HEIGHT, { isStatic: true, render: { fillStyle: '#333'} })
151
+ ]);
152
+
153
+ Events.on(engine, 'beforeUpdate', function(event) {
154
+ if (!ball || !stack || !stack.bodies) return;
155
+
156
+ if (isPinching) {
157
+ if (!grabbedBody) {
158
+ const distToBall = Vector.magnitude(Vector.sub(ball.position, {x: handWorldX, y: handWorldY}));
159
+ if (distToBall < ball.circleRadius + GRAB_RADIUS_BALL_PX / 2) {
160
+ grabbedBody = ball;
161
+ blockGrabOffset = {x:0, y:0};
162
+ } else {
163
+ for (let i = stack.bodies.length - 1; i >= 0; i--) {
164
+ const body = stack.bodies[i];
165
+ if (Bounds.contains(body.bounds, {x: handWorldX, y: handWorldY})) {
166
+ const bodyCurrentWidth = body.bounds.max.x - body.bounds.min.x;
167
+ const bodyCurrentHeight = body.bounds.max.y - body.bounds.min.y;
168
+ if (Vector.magnitude(Vector.sub(body.position, {x: handWorldX, y: handWorldY})) < Math.max(bodyCurrentWidth, bodyCurrentHeight) / 1.5 + GRAB_RADIUS_BLOCK_PX) {
169
+ grabbedBody = body;
170
+ blockGrabOffset = Vector.sub({x: handWorldX, y: handWorldY}, body.position);
171
+ Body.setAngularVelocity(grabbedBody, 0);
172
+ Body.setVelocity(grabbedBody, {x:0, y:0});
173
+ break;
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ if (grabbedBody) {
180
+ grabConstraint = Constraint.create({
181
+ pointA: { x: handWorldX, y: handWorldY },
182
+ bodyB: grabbedBody,
183
+ pointB: grabbedBody === ball ? {x:0, y:0} : blockGrabOffset,
184
+ length: grabbedBody === ball ? 0 : Vector.magnitude(blockGrabOffset) * 0.1,
185
+ stiffness: GRAB_STIFFNESS,
186
+ damping: 0.15,
187
+ render: { visible: false }
188
+ });
189
+ Composite.add(world, grabConstraint);
190
+ }
191
+ } else {
192
+ if (grabConstraint) {
193
+ grabConstraint.pointA.x = handWorldX;
194
+ grabConstraint.pointA.y = handWorldY;
195
+ }
196
+ }
197
+ } else {
198
+ if (grabbedBody && grabConstraint) {
199
+ Composite.remove(world, grabConstraint);
200
+ grabConstraint = null;
201
+ grabbedBody = null;
202
+ }
203
+ }
204
+ });
205
+
206
+ Render.lookAt(render, { min: { x: 0, y: 0 }, max: { x: RENDER_WIDTH, y: RENDER_HEIGHT }});
207
+ return { engine, runner, render, canvas: render.canvas, stop: () => { Render.stop(render); Runner.stop(runner); camera.stop(); } };
208
+ };
209
+
210
+ function onHandResults(results) {
211
+ handGestureOverlayCtx.clearRect(0, 0, RENDER_WIDTH, RENDER_HEIGHT);
212
+ if (results.multiHandLandmarks && results.multiHandLandmarks.length > 0) {
213
+ const landmarks = results.multiHandLandmarks[0];
214
+ const thumbTipLandmark = landmarks[4];
215
+ const indexTipLandmark = landmarks[8];
216
+
217
+ if (thumbTipLandmark && indexTipLandmark) {
218
+ let thumbDrawX = thumbTipLandmark.x * RENDER_WIDTH;
219
+ let indexDrawX = indexTipLandmark.x * RENDER_WIDTH;
220
+ let thumbPhysX = thumbTipLandmark.x * RENDER_WIDTH;
221
+ let indexPhysX = indexTipLandmark.x * RENDER_WIDTH;
222
+
223
+ if (MIRROR_COORDS_FOR_DISPLAY_AND_PHYSICS) {
224
+ thumbDrawX = (1 - thumbTipLandmark.x) * RENDER_WIDTH;
225
+ indexDrawX = (1 - indexTipLandmark.x) * RENDER_WIDTH;
226
+ thumbPhysX = (1 - thumbTipLandmark.x) * RENDER_WIDTH;
227
+ indexPhysX = (1 - indexTipLandmark.x) * RENDER_WIDTH;
228
+ }
229
+ const thumbDrawY = thumbTipLandmark.y * RENDER_HEIGHT;
230
+ const indexDrawY = indexTipLandmark.y * RENDER_HEIGHT;
231
+ const thumbPhysY = thumbTipLandmark.y * RENDER_HEIGHT;
232
+ const indexPhysY = indexTipLandmark.y * RENDER_HEIGHT;
233
+
234
+ [ {x: thumbDrawX, y: thumbDrawY}, {x: indexDrawX, y: indexDrawY} ].forEach(p => {
235
+ handGestureOverlayCtx.beginPath();
236
+ handGestureOverlayCtx.arc(p.x, p.y, LANDMARK_RADIUS, 0, 2 * Math.PI);
237
+ handGestureOverlayCtx.fillStyle = LANDMARK_COLOR;
238
+ handGestureOverlayCtx.fill();
239
+ handGestureOverlayCtx.strokeStyle = 'rgba(255,255,255,0.3)';
240
+ handGestureOverlayCtx.lineWidth = 1.5;
241
+ handGestureOverlayCtx.stroke();
242
+ });
243
+
244
+ const distance = Math.hypot(thumbPhysX - indexPhysX, thumbPhysY - indexPhysY);
245
+ handWorldX = (thumbPhysX + indexPhysX) / 2;
246
+ handWorldY = (thumbPhysY + indexPhysY) / 2;
247
+ isPinching = (distance < PINCH_THRESHOLD_PX);
248
+ } else {
249
+ isPinching = false;
250
+ }
251
+ } else {
252
+ isPinching = false;
253
+ }
254
+ }
255
+ hands.onResults(onHandResults);
256
+
257
+ const camera = new Camera(videoElement, {
258
+ onFrame: async () => {
259
+ if (videoElement.readyState >= HTMLMediaElement.HAVE_ENOUGH_DATA && videoElement.videoWidth > 0) {
260
+ await hands.send({image: videoElement});
261
+ }
262
+ },
263
+ width: 640,
264
+ height: 480
265
+ });
266
+ camera.start();
267
+
268
+ Example.wreckingBallAndBlocks.title = 'MediaPipe Wrecking Ball & Blocks (Adjusted)';
269
+ const gameInstance = Example.wreckingBallAndBlocks();
270
+
271
+ window.addEventListener('beforeunload', () => {
272
+ if (gameInstance && gameInstance.stop) gameInstance.stop();
273
+ });
274
+ </script>
275
+ </body>
276
+ </html>