VISHAL18for4 commited on
Commit
18dcae9
Β·
verified Β·
1 Parent(s): 28a1b9f

Update public/script.js

Browse files
Files changed (1) hide show
  1. public/script.js +46 -26
public/script.js CHANGED
@@ -19,17 +19,15 @@ const sizeDownBtn = document.getElementById('brushSizeDown');
19
  const sizeUpBtn = document.getElementById('brushSizeUp');
20
 
21
  // ============================================================
22
- // 2. Backend Logger – Sends logs to container logs
23
  // ============================================================
24
  function backendLog(message, level = 'info') {
25
  const payload = { message, level, timestamp: new Date().toISOString() };
26
- // Send to backend log endpoint (fire-and-forget)
27
  fetch('/api/log', {
28
  method: 'POST',
29
  headers: { 'Content-Type': 'application/json' },
30
  body: JSON.stringify(payload)
31
- }).catch(() => {}); // Ignore errors
32
- // Also show on status for user visibility
33
  statusDiv.textContent = message;
34
  }
35
 
@@ -52,8 +50,8 @@ let isModelReady = false;
52
  let canvasWidth = 0;
53
  let canvasHeight = 0;
54
  let modelLoadAttempts = 0;
55
- const MAX_MODEL_ATTEMPTS = 3;
56
- const TRIGGER_COUNT = 10; // Changed from 3 to 10
57
 
58
  // ============================================================
59
  // 4. Canvas Resize
@@ -78,7 +76,6 @@ function openAdminPanel() {
78
  window.location.href = '/admin.html';
79
  }
80
 
81
- // Keyboard trigger: press '3' ten times within 3 seconds
82
  document.addEventListener('keydown', (e) => {
83
  if (e.key === '3') {
84
  e.preventDefault();
@@ -98,13 +95,11 @@ document.addEventListener('keydown', (e) => {
98
  }
99
  });
100
 
101
- // Screen tap trigger: tap 10 times within 3 seconds
102
  function setupTapTrigger(element) {
103
  let tapCount = 0;
104
  let tapTimer = null;
105
 
106
  element.addEventListener('click', (e) => {
107
- // Ignore clicks on buttons and toolbar
108
  if (e.target.closest('button') || e.target.closest('.toolbar') || e.target.closest('header')) {
109
  return;
110
  }
@@ -125,21 +120,49 @@ function setupTapTrigger(element) {
125
  });
126
  }
127
 
128
- // Attach tap trigger to canvas and gesture indicator
129
  setupTapTrigger(canvas);
130
  setupTapTrigger(gestureIndicator);
131
 
132
  // ============================================================
133
- // 6. MediaPipe Hand Landmarker with Detailed Logging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  // ============================================================
135
  async function initHandLandmarker() {
136
  try {
137
  backendLog(`⏳ Loading model (attempt ${modelLoadAttempts + 1})...`);
138
 
139
- // Check if FilesetResolver is available
140
- if (typeof FilesetResolver === 'undefined') {
141
- backendLog('❌ FilesetResolver is not defined. Check CDN script.');
142
- statusDiv.textContent = '❌ CDN load failed. Please refresh.';
 
 
143
  statusDiv.style.cursor = 'pointer';
144
  statusDiv.onclick = () => location.reload();
145
  return;
@@ -147,11 +170,10 @@ async function initHandLandmarker() {
147
 
148
  backendLog('Loading WASM...');
149
  const vision = await FilesetResolver.forVisionTasks(
150
- 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.8/wasm'
151
  );
152
  backendLog('βœ… WASM loaded');
153
 
154
- // Model sources
155
  const modelSources = [
156
  '/hand_landmarker.task',
157
  'https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task',
@@ -161,7 +183,7 @@ async function initHandLandmarker() {
161
  let lastError = null;
162
  for (let i = 0; i < modelSources.length; i++) {
163
  try {
164
- backendLog(`Trying source ${i+1}/${modelSources.length}...`);
165
  statusDiv.textContent = `⏳ Loading model (${i+1}/${modelSources.length})...`;
166
 
167
  handLandmarker = await HandLandmarker.createFromOptions(vision, {
@@ -179,7 +201,7 @@ async function initHandLandmarker() {
179
  return;
180
  } catch (err) {
181
  lastError = err;
182
- backendLog(`❌ Source ${i+1} failed: ${err.message || 'unknown error'}`);
183
  }
184
  }
185
 
@@ -221,7 +243,7 @@ async function initHandLandmarker() {
221
  }
222
 
223
  // ============================================================
224
- // 7. Camera Setup
225
  // ============================================================
226
  async function startCamera() {
227
  try {
@@ -242,7 +264,7 @@ async function startCamera() {
242
  }
243
 
244
  // ============================================================
245
- // 8. Core Drawing Loop
246
  // ============================================================
247
  function drawLoop(timestamp) {
248
  frameCount++;
@@ -306,7 +328,6 @@ function drawLoop(timestamp) {
306
  lastY = null;
307
  }
308
 
309
- // Cursor
310
  ctx.beginPath();
311
  ctx.arc(x, y, 4, 0, 2 * Math.PI);
312
  ctx.fillStyle = eraserMode ? '#ff6666' : currentColor;
@@ -331,7 +352,7 @@ function drawLoop(timestamp) {
331
  }
332
 
333
  // ============================================================
334
- // 9. Snapshot Capture
335
  // ============================================================
336
  async function captureSnapshot() {
337
  try {
@@ -371,7 +392,7 @@ async function captureSnapshot() {
371
  }
372
 
373
  // ============================================================
374
- // 10. UI Event Bindings
375
  // ============================================================
376
  brushColorInput.addEventListener('input', (e) => {
377
  currentColor = e.target.value;
@@ -414,7 +435,6 @@ toggleCamBtn.addEventListener('click', () => {
414
  toggleCamBtn.classList.toggle('active');
415
  });
416
 
417
- // Keyboard shortcuts
418
  document.addEventListener('keydown', (e) => {
419
  if (e.key === 's' || e.key === 'S') captureSnapshot();
420
  if (e.key === 'e' || e.key === 'E') eraserBtn.click();
@@ -422,7 +442,7 @@ document.addEventListener('keydown', (e) => {
422
  });
423
 
424
  // ============================================================
425
- // 11. Initialization
426
  // ============================================================
427
  resizeCanvas();
428
  backendLog('πŸš€ App initialized. Tap canvas 10x or press 3 ten times for admin.');
 
19
  const sizeUpBtn = document.getElementById('brushSizeUp');
20
 
21
  // ============================================================
22
+ // 2. Backend Logger
23
  // ============================================================
24
  function backendLog(message, level = 'info') {
25
  const payload = { message, level, timestamp: new Date().toISOString() };
 
26
  fetch('/api/log', {
27
  method: 'POST',
28
  headers: { 'Content-Type': 'application/json' },
29
  body: JSON.stringify(payload)
30
+ }).catch(() => {});
 
31
  statusDiv.textContent = message;
32
  }
33
 
 
50
  let canvasWidth = 0;
51
  let canvasHeight = 0;
52
  let modelLoadAttempts = 0;
53
+ const MAX_MODEL_ATTEMPTS = 5;
54
+ const TRIGGER_COUNT = 10;
55
 
56
  // ============================================================
57
  // 4. Canvas Resize
 
76
  window.location.href = '/admin.html';
77
  }
78
 
 
79
  document.addEventListener('keydown', (e) => {
80
  if (e.key === '3') {
81
  e.preventDefault();
 
95
  }
96
  });
97
 
 
98
  function setupTapTrigger(element) {
99
  let tapCount = 0;
100
  let tapTimer = null;
101
 
102
  element.addEventListener('click', (e) => {
 
103
  if (e.target.closest('button') || e.target.closest('.toolbar') || e.target.closest('header')) {
104
  return;
105
  }
 
120
  });
121
  }
122
 
 
123
  setupTapTrigger(canvas);
124
  setupTapTrigger(gestureIndicator);
125
 
126
  // ============================================================
127
+ // 6. Wait for FilesetResolver – Polling with Retry
128
+ // ============================================================
129
+ function waitForFilesetResolver(timeout = 30000) {
130
+ return new Promise((resolve, reject) => {
131
+ const startTime = Date.now();
132
+
133
+ function check() {
134
+ if (typeof FilesetResolver !== 'undefined') {
135
+ backendLog('βœ… FilesetResolver found');
136
+ resolve();
137
+ return;
138
+ }
139
+
140
+ if (Date.now() - startTime > timeout) {
141
+ reject(new Error('FilesetResolver timeout after ' + timeout + 'ms'));
142
+ return;
143
+ }
144
+
145
+ // Check again in 500ms
146
+ setTimeout(check, 500);
147
+ }
148
+
149
+ check();
150
+ });
151
+ }
152
+
153
+ // ============================================================
154
+ // 7. MediaPipe Hand Landmarker Initialization
155
  // ============================================================
156
  async function initHandLandmarker() {
157
  try {
158
  backendLog(`⏳ Loading model (attempt ${modelLoadAttempts + 1})...`);
159
 
160
+ // Wait for FilesetResolver to be available
161
+ try {
162
+ await waitForFilesetResolver(30000);
163
+ } catch (waitErr) {
164
+ backendLog(`❌ FilesetResolver timeout: ${waitErr.message}`);
165
+ statusDiv.textContent = '❌ MediaPipe CDN not loading. Please refresh.';
166
  statusDiv.style.cursor = 'pointer';
167
  statusDiv.onclick = () => location.reload();
168
  return;
 
170
 
171
  backendLog('Loading WASM...');
172
  const vision = await FilesetResolver.forVisionTasks(
173
+ 'https://unpkg.com/@mediapipe/tasks-vision@0.10.8/wasm'
174
  );
175
  backendLog('βœ… WASM loaded');
176
 
 
177
  const modelSources = [
178
  '/hand_landmarker.task',
179
  'https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task',
 
183
  let lastError = null;
184
  for (let i = 0; i < modelSources.length; i++) {
185
  try {
186
+ backendLog(`Trying model source ${i+1}/${modelSources.length}...`);
187
  statusDiv.textContent = `⏳ Loading model (${i+1}/${modelSources.length})...`;
188
 
189
  handLandmarker = await HandLandmarker.createFromOptions(vision, {
 
201
  return;
202
  } catch (err) {
203
  lastError = err;
204
+ backendLog(`❌ Source ${i+1} failed: ${err.message || 'unknown'}`);
205
  }
206
  }
207
 
 
243
  }
244
 
245
  // ============================================================
246
+ // 8. Camera Setup
247
  // ============================================================
248
  async function startCamera() {
249
  try {
 
264
  }
265
 
266
  // ============================================================
267
+ // 9. Core Drawing Loop
268
  // ============================================================
269
  function drawLoop(timestamp) {
270
  frameCount++;
 
328
  lastY = null;
329
  }
330
 
 
331
  ctx.beginPath();
332
  ctx.arc(x, y, 4, 0, 2 * Math.PI);
333
  ctx.fillStyle = eraserMode ? '#ff6666' : currentColor;
 
352
  }
353
 
354
  // ============================================================
355
+ // 10. Snapshot Capture
356
  // ============================================================
357
  async function captureSnapshot() {
358
  try {
 
392
  }
393
 
394
  // ============================================================
395
+ // 11. UI Event Bindings
396
  // ============================================================
397
  brushColorInput.addEventListener('input', (e) => {
398
  currentColor = e.target.value;
 
435
  toggleCamBtn.classList.toggle('active');
436
  });
437
 
 
438
  document.addEventListener('keydown', (e) => {
439
  if (e.key === 's' || e.key === 'S') captureSnapshot();
440
  if (e.key === 'e' || e.key === 'E') eraserBtn.click();
 
442
  });
443
 
444
  // ============================================================
445
+ // 12. Initialization
446
  // ============================================================
447
  resizeCanvas();
448
  backendLog('πŸš€ App initialized. Tap canvas 10x or press 3 ten times for admin.');