MNE-Zone commited on
Commit
f7d9ab3
·
verified ·
1 Parent(s): d397f0b

Failed to generate 3D model

Browse files
Files changed (3) hide show
  1. index.html +2 -2
  2. script.js +110 -38
  3. style.css +13 -3
index.html CHANGED
@@ -7,8 +7,7 @@
7
  <link rel="icon" type="image/x-icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🎨</text></svg>">
8
  <link rel="stylesheet" href="style.css">
9
  <script src="https://cdn.tailwindcss.com"></script>
10
- <script src="https://cdn.tailwindcss.com"></script>
11
- <script>
12
  tailwind.config = {
13
  theme: {
14
  extend: {
@@ -48,6 +47,7 @@
48
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js"></script>
49
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
50
  <script src="https://sdk.amazonaws.com/js/aws-sdk-2.1000.0.min.js"></script>
 
51
  </head>
52
  <body class="bg-gradient-to-br from-primary-500 via-secondary-500 to-primary-600 min-h-screen">
53
  <custom-header></custom-header>
 
7
  <link rel="icon" type="image/x-icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🎨</text></svg>">
8
  <link rel="stylesheet" href="style.css">
9
  <script src="https://cdn.tailwindcss.com"></script>
10
+ <script>
 
11
  tailwind.config = {
12
  theme: {
13
  extend: {
 
47
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js"></script>
48
  <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
49
  <script src="https://sdk.amazonaws.com/js/aws-sdk-2.1000.0.min.js"></script>
50
+ <script src="https://sdk.amazonaws.com/js/aws-sdk-2.1000.0.min.js"></script>
51
  </head>
52
  <body class="bg-gradient-to-br from-primary-500 via-secondary-500 to-primary-600 min-h-screen">
53
  <custom-header></custom-header>
script.js CHANGED
@@ -23,6 +23,22 @@ let scene, camera, renderer, controls, currentModel;
23
  let currentTaskId = null;
24
  let statusCheckInterval = null;
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  // Initialize AWS S3
27
  AWS.config.update({
28
  accessKeyId: API_CONFIG.S3_ACCESS,
@@ -162,53 +178,64 @@ const progressBar = document.getElementById('progressBar');
162
  const progressFill = document.getElementById('progressFill');
163
 
164
  fileInput.addEventListener('change', handleFileSelect);
165
- generateBtn.addEventListener('generateBtn', generate3DModel);
166
-
167
  function handleFileSelect(event) {
168
  const file = event.target.files[0];
169
  if (file && file.type.startsWith('image/')) {
170
  const reader = new FileReader();
171
  reader.onload = function(e) {
172
- previewImg.src = e.target.result;
173
- imagePreview.classList.remove('hidden');
174
- imagePreview.classList.add('animate-float');
 
 
 
 
175
  };
176
  reader.readAsDataURL(file);
177
  }
178
  }
179
-
180
  // Drag and drop
181
- const uploadArea = document.querySelector('label[for="fileInput"] > div');
182
-
183
- uploadArea.addEventListener('dragover', (e) => {
184
- e.preventDefault();
185
- uploadArea.classList.add('drag-active');
186
- });
 
 
187
 
188
- uploadArea.addEventListener('dragleave', () => {
189
- uploadArea.classList.remove('drag-active');
190
- });
191
 
192
- uploadArea.addEventListener('drop', (e) => {
193
- e.preventDefault();
194
- uploadArea.classList.remove('drag-active');
195
-
196
- const files = e.dataTransfer.files;
197
- if (files.length > 0 && files[0].type.startsWith('image/')) {
198
- fileInput.files = files;
199
- handleFileSelect({ target: { files } });
 
 
 
 
200
  }
201
  });
202
-
203
  // 3D Model Generation
204
  async function generate3DModel() {
 
 
 
 
 
205
  const file = fileInput.files[0];
206
  if (!file) {
207
  showStatus('error', 'Please select an image first', 'alert-circle');
208
  return;
209
  }
210
-
211
- showStatus('processing', 'Uploading image...', 'upload-cloud');
212
  progressBar.classList.remove('hidden');
213
  updateProgress(20);
214
 
@@ -234,8 +261,13 @@ async function generate3DModel() {
234
  progressBar.classList.add('hidden');
235
  }
236
  }
237
-
238
  async function uploadToS3(file) {
 
 
 
 
 
 
239
  const fileName = `uploads/${Date.now()}_${file.name}`;
240
  const params = {
241
  Bucket: API_CONFIG.BUCKET_NAME,
@@ -314,7 +346,9 @@ function pollTaskStatus(taskId) {
314
  showStatus('success', '3D model generated successfully!', 'check-circle');
315
 
316
  // Create a demo 3D model
317
- createDemoModel();
 
 
318
 
319
  // Display mock model info
320
  displayModelInfo({
@@ -332,8 +366,7 @@ function pollTaskStatus(taskId) {
332
 
333
  return;
334
  }
335
-
336
- // Real API polling (uncomment when you have real API)
337
  /*
338
  statusCheckInterval = setInterval(async () => {
339
  try {
@@ -410,6 +443,19 @@ function load3DModel(modelUrl) {
410
 
411
  // Create a demo 3D model for demonstration purposes
412
  function createDemoModel() {
 
 
 
 
 
 
 
 
 
 
 
 
 
413
  // Remove existing model
414
  if (currentModel) {
415
  scene.remove(currentModel);
@@ -453,6 +499,11 @@ function displayModelInfo(data) {
453
  const modelInfo = document.getElementById('modelInfo');
454
  const modelDetails = document.getElementById('modelDetails');
455
 
 
 
 
 
 
456
  modelDetails.innerHTML = `
457
  <p><strong>Format:</strong> ${data.format || 'GLTF'}</p>
458
  <p><strong>Quality:</strong> ${data.quality || 'High'}</p>
@@ -463,9 +514,13 @@ function displayModelInfo(data) {
463
 
464
  modelInfo.classList.remove('hidden');
465
  }
466
-
467
  function addToRecentGallery(modelUrl) {
468
  const recentModels = document.getElementById('recentModels');
 
 
 
 
 
469
  const card = document.createElement('div');
470
  card.className = 'aspect-square bg-gray-100 rounded-lg overflow-hidden model-card hover-lift';
471
  card.innerHTML = `
@@ -480,8 +535,12 @@ function addToRecentGallery(modelUrl) {
480
  recentModels.removeChild(recentModels.lastChild);
481
  }
482
  }
483
-
484
  function showStatus(type, message, icon) {
 
 
 
 
 
485
  statusContainer.classList.remove('hidden');
486
  statusBox.className = `rounded-xl p-4 transition-all duration-300 status-${type}`;
487
 
@@ -492,19 +551,32 @@ function showStatus(type, message, icon) {
492
  statusIcon.innerHTML = iconHtml;
493
  statusText.textContent = message;
494
 
495
- feather.replace();
 
 
496
  }
497
-
498
  function updateProgress(percent) {
499
- progressFill.style.width = `${percent}%`;
 
 
500
  }
501
-
502
  // Initialize viewer on load
503
  window.addEventListener('load', () => {
 
 
 
 
 
 
504
  setTimeout(() => {
505
  initViewer();
506
  }, 100);
507
  });
508
 
509
- // Generate button click handler
510
- document.getElementById('generateBtn').addEventListener('click', generate3DModel);
 
 
 
 
 
 
23
  let currentTaskId = null;
24
  let statusCheckInterval = null;
25
 
26
+ // DOM element references
27
+ let fileInput, imagePreview, previewImg, generateBtn, statusContainer, statusBox, statusIcon, statusText, progressBar, progressFill;
28
+
29
+ // Initialize DOM elements
30
+ function initDOMElements() {
31
+ fileInput = document.getElementById('fileInput');
32
+ imagePreview = document.getElementById('imagePreview');
33
+ previewImg = document.getElementById('previewImg');
34
+ generateBtn = document.getElementById('generateBtn');
35
+ statusContainer = document.getElementById('statusContainer');
36
+ statusBox = document.getElementById('statusBox');
37
+ statusIcon = document.getElementById('statusIcon');
38
+ statusText = document.getElementById('statusText');
39
+ progressBar = document.getElementById('progressBar');
40
+ progressFill = document.getElementById('progressFill');
41
+ }
42
  // Initialize AWS S3
43
  AWS.config.update({
44
  accessKeyId: API_CONFIG.S3_ACCESS,
 
178
  const progressFill = document.getElementById('progressFill');
179
 
180
  fileInput.addEventListener('change', handleFileSelect);
181
+ generateBtn.addEventListener('click', generate3DModel);
 
182
  function handleFileSelect(event) {
183
  const file = event.target.files[0];
184
  if (file && file.type.startsWith('image/')) {
185
  const reader = new FileReader();
186
  reader.onload = function(e) {
187
+ if (previewImg) {
188
+ previewImg.src = e.target.result;
189
+ }
190
+ if (imagePreview) {
191
+ imagePreview.classList.remove('hidden');
192
+ imagePreview.classList.add('animate-float');
193
+ }
194
  };
195
  reader.readAsDataURL(file);
196
  }
197
  }
 
198
  // Drag and drop
199
+ document.addEventListener('DOMContentLoaded', () => {
200
+ const uploadArea = document.querySelector('label[for="fileInput"] > div');
201
+
202
+ if (uploadArea) {
203
+ uploadArea.addEventListener('dragover', (e) => {
204
+ e.preventDefault();
205
+ uploadArea.classList.add('drag-active');
206
+ });
207
 
208
+ uploadArea.addEventListener('dragleave', () => {
209
+ uploadArea.classList.remove('drag-active');
210
+ });
211
 
212
+ uploadArea.addEventListener('drop', (e) => {
213
+ e.preventDefault();
214
+ uploadArea.classList.remove('drag-active');
215
+
216
+ const files = e.dataTransfer.files;
217
+ if (files.length > 0 && files[0].type.startsWith('image/')) {
218
+ if (fileInput) {
219
+ fileInput.files = files;
220
+ handleFileSelect({ target: { files } });
221
+ }
222
+ }
223
+ });
224
  }
225
  });
 
226
  // 3D Model Generation
227
  async function generate3DModel() {
228
+ if (!fileInput) {
229
+ console.error('File input not found');
230
+ return;
231
+ }
232
+
233
  const file = fileInput.files[0];
234
  if (!file) {
235
  showStatus('error', 'Please select an image first', 'alert-circle');
236
  return;
237
  }
238
+ showStatus('processing', 'Uploading image...', 'upload-cloud');
 
239
  progressBar.classList.remove('hidden');
240
  updateProgress(20);
241
 
 
261
  progressBar.classList.add('hidden');
262
  }
263
  }
 
264
  async function uploadToS3(file) {
265
+ // Demo mode - simulate upload
266
+ if (API_CONFIG.DEMO_MODE) {
267
+ await new Promise(resolve => setTimeout(resolve, 1000));
268
+ return `https://demo-server.com/uploads/${Date.now()}_${file.name}`;
269
+ }
270
+
271
  const fileName = `uploads/${Date.now()}_${file.name}`;
272
  const params = {
273
  Bucket: API_CONFIG.BUCKET_NAME,
 
346
  showStatus('success', '3D model generated successfully!', 'check-circle');
347
 
348
  // Create a demo 3D model
349
+ setTimeout(() => {
350
+ createDemoModel();
351
+ }, 100);
352
 
353
  // Display mock model info
354
  displayModelInfo({
 
366
 
367
  return;
368
  }
369
+ // Real API polling (uncomment when you have real API)
 
370
  /*
371
  statusCheckInterval = setInterval(async () => {
372
  try {
 
443
 
444
  // Create a demo 3D model for demonstration purposes
445
  function createDemoModel() {
446
+ // Check if Three.js is available
447
+ if (typeof THREE === 'undefined') {
448
+ console.error('Three.js not loaded');
449
+ showStatus('error', '3D engine not available', 'x-circle');
450
+ return;
451
+ }
452
+
453
+ if (!scene) {
454
+ console.error('Scene not initialized');
455
+ showStatus('error', '3D viewer not ready', 'x-circle');
456
+ return;
457
+ }
458
+
459
  // Remove existing model
460
  if (currentModel) {
461
  scene.remove(currentModel);
 
499
  const modelInfo = document.getElementById('modelInfo');
500
  const modelDetails = document.getElementById('modelDetails');
501
 
502
+ if (!modelInfo || !modelDetails) {
503
+ console.error('Model info elements not found');
504
+ return;
505
+ }
506
+
507
  modelDetails.innerHTML = `
508
  <p><strong>Format:</strong> ${data.format || 'GLTF'}</p>
509
  <p><strong>Quality:</strong> ${data.quality || 'High'}</p>
 
514
 
515
  modelInfo.classList.remove('hidden');
516
  }
 
517
  function addToRecentGallery(modelUrl) {
518
  const recentModels = document.getElementById('recentModels');
519
+ if (!recentModels) {
520
+ console.error('Recent models container not found');
521
+ return;
522
+ }
523
+
524
  const card = document.createElement('div');
525
  card.className = 'aspect-square bg-gray-100 rounded-lg overflow-hidden model-card hover-lift';
526
  card.innerHTML = `
 
535
  recentModels.removeChild(recentModels.lastChild);
536
  }
537
  }
 
538
  function showStatus(type, message, icon) {
539
+ if (!statusContainer || !statusBox || !statusIcon || !statusText) {
540
+ console.error('Status elements not found');
541
+ return;
542
+ }
543
+
544
  statusContainer.classList.remove('hidden');
545
  statusBox.className = `rounded-xl p-4 transition-all duration-300 status-${type}`;
546
 
 
551
  statusIcon.innerHTML = iconHtml;
552
  statusText.textContent = message;
553
 
554
+ if (typeof feather !== 'undefined') {
555
+ feather.replace();
556
+ }
557
  }
 
558
  function updateProgress(percent) {
559
+ if (progressFill) {
560
+ progressFill.style.width = `${percent}%`;
561
+ }
562
  }
 
563
  // Initialize viewer on load
564
  window.addEventListener('load', () => {
565
+ // Initialize Feather icons first
566
+ if (typeof feather !== 'undefined') {
567
+ feather.replace();
568
+ }
569
+
570
+ // Initialize viewer after DOM is ready
571
  setTimeout(() => {
572
  initViewer();
573
  }, 100);
574
  });
575
 
576
+ // Generate button click handler - wrap in DOMContentLoaded to ensure elements exist
577
+ document.addEventListener('DOMContentLoaded', () => {
578
+ const generateBtnElement = document.getElementById('generateBtn');
579
+ if (generateBtnElement) {
580
+ generateBtnElement.addEventListener('click', generate3DModel);
581
+ }
582
+ });
style.css CHANGED
@@ -47,14 +47,13 @@
47
  ::-webkit-scrollbar-thumb:hover {
48
  background: linear-gradient(135deg, #5a67d8 0%, #d946ef 100%);
49
  }
50
-
51
  /* Loading states */
52
  .loading-spinner {
53
  border: 3px solid #f3f3f3;
54
  border-top: 3px solid #667eea;
55
  border-radius: 50%;
56
- width: 40px;
57
- height: 40px;
58
  animation: spin 1s linear infinite;
59
  }
60
 
@@ -63,6 +62,17 @@
63
  100% { transform: rotate(360deg); }
64
  }
65
 
 
 
 
 
 
 
 
 
 
 
 
66
  /* Glassmorphism effect */
67
  .glass {
68
  background: rgba(255, 255, 255, 0.1);
 
47
  ::-webkit-scrollbar-thumb:hover {
48
  background: linear-gradient(135deg, #5a67d8 0%, #d946ef 100%);
49
  }
 
50
  /* Loading states */
51
  .loading-spinner {
52
  border: 3px solid #f3f3f3;
53
  border-top: 3px solid #667eea;
54
  border-radius: 50%;
55
+ width: 20px;
56
+ height: 20px;
57
  animation: spin 1s linear infinite;
58
  }
59
 
 
62
  100% { transform: rotate(360deg); }
63
  }
64
 
65
+ /* Status container fixes */
66
+ #statusContainer {
67
+ transition: all 0.3s ease;
68
+ }
69
+
70
+ #statusIcon {
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ min-width: 24px;
75
+ }
76
  /* Glassmorphism effect */
77
  .glass {
78
  background: rgba(255, 255, 255, 0.1);