3dgen / index.html
blacksiders's picture
cool it's working but we need to generate model with https://huggingface.co/spaces/ilcve21/Sparc3D. model - Initial Deployment
d76ea03 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Model Generator with Sparc3D</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.model-container {
width: 100%;
height: 400px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
}
.model-placeholder {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { opacity: 0.5; }
50% { opacity: 0.8; }
100% { opacity: 0.5; }
}
.loading-spinner {
width: 50px;
height: 50px;
border: 5px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: #4f46e5;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.model-view {
width: 100%;
height: 100%;
object-fit: contain;
}
.history-item {
transition: all 0.3s ease;
}
.history-item:hover {
transform: scale(1.02);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="mb-10 text-center">
<h1 class="text-4xl md:text-5xl font-bold text-indigo-800 mb-3">3D Model Generator</h1>
<p class="text-lg text-gray-600 max-w-2xl mx-auto">
Create stunning 3D models from text prompts using the power of Sparc3D's AI technology
</p>
</header>
<!-- Main Content -->
<div class="flex flex-col lg:flex-row gap-8">
<!-- Generation Panel -->
<div class="lg:w-2/3">
<div class="bg-white rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Generate New Model</h2>
<!-- Prompt Input -->
<div class="mb-6">
<label for="prompt" class="block text-sm font-medium text-gray-700 mb-2">Describe your 3D model</label>
<div class="flex gap-2">
<input
type="text"
id="prompt"
placeholder="e.g. A futuristic spaceship with glowing engines"
class="flex-1 px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
>
<button id="generate-btn" class="px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition flex items-center gap-2">
<i class="fas fa-magic"></i> Generate
</button>
</div>
</div>
<!-- Advanced Options (Collapsible) -->
<div class="mb-6">
<button id="advanced-toggle" class="flex items-center text-indigo-600 hover:text-indigo-800 transition mb-3">
<i class="fas fa-cog mr-2"></i>
Advanced Options
<i class="fas fa-chevron-down ml-2 text-sm transition-transform" id="advanced-arrow"></i>
</button>
<div id="advanced-options" class="hidden bg-gray-50 p-4 rounded-lg space-y-4">
<div>
<label for="style" class="block text-sm font-medium text-gray-700 mb-1">Style</label>
<select id="style" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<option value="realistic">Realistic</option>
<option value="cartoon">Cartoon</option>
<option value="low-poly">Low Poly</option>
<option value="scifi">Sci-Fi</option>
</select>
</div>
<div>
<label for="quality" class="block text-sm font-medium text-gray-700 mb-1">Quality</label>
<select id="quality" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<option value="low">Low (Faster)</option>
<option value="medium" selected>Medium</option>
<option value="high">High (Slower)</option>
</select>
</div>
<div>
<label for="color" class="block text-sm font-medium text-gray-700 mb-1">Primary Color</label>
<input type="color" id="color" value="#4f46e5" class="h-10 w-10 cursor-pointer">
</div>
</div>
</div>
<!-- Model Display -->
<div class="model-container mb-6">
<div id="model-placeholder" class="model-placeholder text-center p-6">
<i class="fas fa-cube text-6xl text-gray-400 mb-4"></i>
<p class="text-gray-500">Enter a prompt and click Generate to create your 3D model</p>
</div>
<div id="loading-indicator" class="hidden absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
<div class="loading-spinner"></div>
<p class="ml-3 text-white font-medium">Generating your 3D model...</p>
</div>
<iframe id="model-view" class="model-view hidden" frameborder="0"></iframe>
<iframe id="sparc3d-iframe" src="https://ilcve21-sparc3d.hf.space" class="hidden w-full h-full"></iframe>
</div>
<!-- Action Buttons -->
<div class="flex flex-wrap gap-3">
<button id="download-btn" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition flex items-center gap-2 disabled:opacity-50" disabled>
<i class="fas fa-download"></i> Download
</button>
<button id="share-btn" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition flex items-center gap-2 disabled:opacity-50" disabled>
<i class="fas fa-share-alt"></i> Share
</button>
<button id="regenerate-btn" class="px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition flex items-center gap-2">
<i class="fas fa-sync-alt"></i> Regenerate
</button>
</div>
</div>
</div>
<!-- History Panel -->
<div class="lg:w-1/3">
<div class="bg-white rounded-xl shadow-lg p-6 h-full">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-semibold text-gray-800">Your History</h2>
<button id="clear-history" class="text-sm text-red-500 hover:text-red-700 flex items-center gap-1">
<i class="fas fa-trash"></i> Clear
</button>
</div>
<div id="history-list" class="space-y-3 max-h-[600px] overflow-y-auto pr-2">
<!-- History items will be added here -->
<div class="text-center py-10 text-gray-400" id="empty-history-message">
<i class="fas fa-history text-4xl mb-3"></i>
<p>Your generated models will appear here</p>
</div>
</div>
</div>
</div>
</div>
<!-- Info Section -->
<div class="mt-12 bg-indigo-50 rounded-xl p-6">
<h3 class="text-xl font-semibold text-indigo-800 mb-3">About Sparc3D</h3>
<p class="text-gray-700 mb-4">
This app uses <a href="https://lizhihao6.github.io/Sparc3D/" target="_blank" class="text-indigo-600 hover:underline">Sparc3D</a>, a free AI-powered 3D model generator that creates high-quality 3D assets from text descriptions.
</p>
<div class="grid md:grid-cols-3 gap-4">
<div class="bg-white p-4 rounded-lg shadow">
<i class="fas fa-bolt text-indigo-500 text-2xl mb-2"></i>
<h4 class="font-medium text-gray-800">Fast Generation</h4>
<p class="text-sm text-gray-600">Create 3D models in minutes instead of hours</p>
</div>
<div class="bg-white p-4 rounded-lg shadow">
<i class="fas fa-paint-brush text-indigo-500 text-2xl mb-2"></i>
<h4 class="font-medium text-gray-800">Customizable</h4>
<p class="text-sm text-gray-600">Control style, quality and colors of your models</p>
</div>
<div class="bg-white p-4 rounded-lg shadow">
<i class="fas fa-download text-indigo-500 text-2xl mb-2"></i>
<h4 class="font-medium text-gray-800">Free to Use</h4>
<p class="text-sm text-gray-600">Download your creations without any cost</p>
</div>
</div>
</div>
</div>
<script>
// Listen for messages from the Sparc3D iframe
window.addEventListener('message', (event) => {
if (event.origin !== 'https://ilcve21-sparc3d.hf.space') return;
if (event.data.type === 'model-ready') {
const modelUrl = event.data.url;
document.getElementById('model-view').src = modelUrl;
document.getElementById('sparc3d-iframe').classList.add('hidden');
document.getElementById('model-view').classList.remove('hidden');
}
if (event.data.type === 'generation-error') {
console.error('Generation error:', event.data.error);
// Show error message to user
}
});
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const promptInput = document.getElementById('prompt');
const generateBtn = document.getElementById('generate-btn');
const regenerateBtn = document.getElementById('regenerate-btn');
const downloadBtn = document.getElementById('download-btn');
const shareBtn = document.getElementById('share-btn');
const advancedToggle = document.getElementById('advanced-toggle');
const advancedOptions = document.getElementById('advanced-options');
const advancedArrow = document.getElementById('advanced-arrow');
const modelPlaceholder = document.getElementById('model-placeholder');
const loadingIndicator = document.getElementById('loading-indicator');
const modelView = document.getElementById('model-view');
const historyList = document.getElementById('history-list');
const emptyHistoryMessage = document.getElementById('empty-history-message');
const clearHistoryBtn = document.getElementById('clear-history');
// Toggle advanced options
advancedToggle.addEventListener('click', function() {
advancedOptions.classList.toggle('hidden');
advancedArrow.classList.toggle('rotate-180');
});
// Generate model function using Sparc3D Hugging Face Space
async function generateModel(prompt, style = 'realistic', quality = 'medium', color = '#4f46e5') {
if (!prompt.trim()) {
alert('Please enter a description for your 3D model');
return;
}
// Show loading state
modelPlaceholder.classList.add('hidden');
loadingIndicator.classList.remove('hidden');
modelView.classList.add('hidden');
try {
// Show the Sparc3D iframe
const sparc3dIframe = document.getElementById('sparc3d-iframe');
sparc3dIframe.classList.remove('hidden');
// Wait for iframe to load
await new Promise(resolve => {
sparc3dIframe.onload = resolve;
});
// Send message to iframe with prompt
sparc3dIframe.contentWindow.postMessage({
type: 'generate',
prompt: prompt,
style: style,
quality: quality,
color: color
}, 'https://ilcve21-sparc3d.hf.space');
// Hide loading indicator
loadingIndicator.classList.add('hidden');
// Enable download and share buttons
downloadBtn.disabled = false;
shareBtn.disabled = false;
// Add to history
addToHistory(prompt, 'https://ilcve21-sparc3d.hf.space');
} catch (error) {
console.error('Error generating model:', error);
loadingIndicator.classList.add('hidden');
modelPlaceholder.classList.remove('hidden');
// Create and show error message
const errorElement = document.createElement('div');
errorElement.className = 'bg-red-50 border-l-4 border-red-500 p-4 mb-4';
errorElement.innerHTML = `
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-exclamation-circle text-red-500"></i>
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
Failed to generate model. Please try again later.
</p>
</div>
</div>
`;
// Insert error message above the model container
modelContainer.insertAdjacentElement('beforebegin', errorElement);
// Remove error after 5 seconds
setTimeout(() => {
errorElement.remove();
}, 5000);
}
}
// Add generated model to history
function addToHistory(prompt, modelUrl) {
// Remove empty message if it's the first item
if (emptyHistoryMessage) {
emptyHistoryMessage.remove();
}
const historyItem = document.createElement('div');
historyItem.className = 'history-item bg-gray-50 rounded-lg p-4 cursor-pointer hover:bg-indigo-50 border border-gray-200';
historyItem.innerHTML = `
<div class="flex items-start gap-3">
<div class="bg-indigo-100 p-2 rounded-lg">
<i class="fas fa-cube text-indigo-600"></i>
</div>
<div class="flex-1">
<h4 class="font-medium text-gray-800 line-clamp-1">${prompt}</h4>
<p class="text-xs text-gray-500 mb-2">Just now</p>
<div class="flex gap-2">
<button class="view-btn text-xs px-3 py-1 bg-indigo-100 text-indigo-700 rounded hover:bg-indigo-200 transition">
<i class="fas fa-eye mr-1"></i> View
</button>
<button class="download-btn text-xs px-3 py-1 bg-green-100 text-green-700 rounded hover:bg-green-200 transition">
<i class="fas fa-download mr-1"></i> Download
</button>
</div>
</div>
</div>
`;
// Add click handlers
const viewBtn = historyItem.querySelector('.view-btn');
const downloadBtn = historyItem.querySelector('.download-btn');
viewBtn.addEventListener('click', (e) => {
e.stopPropagation();
modelPlaceholder.classList.add('hidden');
modelView.classList.remove('hidden');
modelView.src = modelUrl;
});
downloadBtn.addEventListener('click', (e) => {
e.stopPropagation();
downloadModel(modelUrl, prompt);
});
historyItem.addEventListener('click', () => {
modelPlaceholder.classList.add('hidden');
modelView.classList.remove('hidden');
modelView.src = modelUrl;
});
// Add to top of history
historyList.insertBefore(historyItem, historyList.firstChild);
}
// Download model function
async function downloadModel(url, prompt) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Failed to download model');
}
const blob = await response.blob();
const downloadUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = `3d-model-${prompt.substring(0, 20).toLowerCase().replace(/\s+/g, '-')}.glb`;
document.body.appendChild(link);
link.click();
// Clean up
setTimeout(() => {
document.body.removeChild(link);
window.URL.revokeObjectURL(downloadUrl);
}, 100);
} catch (error) {
console.error('Error downloading model:', error);
alert('Failed to download model. Please try again.');
}
}
// Share model function
function shareModel() {
if (navigator.share) {
navigator.share({
title: 'Check out this 3D model I created',
text: `I created a 3D model of "${promptInput.value}" using Sparc3D`,
url: window.location.href,
})
.catch(err => {
console.error('Error sharing:', err);
});
} else {
// Fallback for browsers that don't support Web Share API
alert('Web Share API not supported in your browser. Copy this link to share: ' + window.location.href);
}
}
// Get model container element
const modelContainer = document.querySelector('.model-container');
// Event listeners
generateBtn.addEventListener('click', function() {
// Clear any previous errors
const existingError = document.querySelector('.bg-red-50');
if (existingError) {
existingError.remove();
}
const prompt = promptInput.value;
const style = document.getElementById('style').value;
const quality = document.getElementById('quality').value;
const color = document.getElementById('color').value;
generateModel(prompt, style, quality, color);
});
regenerateBtn.addEventListener('click', function() {
if (!promptInput.value.trim()) {
alert('Please enter a description first');
return;
}
const prompt = promptInput.value;
const style = document.getElementById('style').value;
const quality = document.getElementById('quality').value;
const color = document.getElementById('color').value;
generateModel(prompt, style, quality, color);
});
downloadBtn.addEventListener('click', function() {
if (modelView.src) {
const prompt = promptInput.value || 'my-3d-model';
downloadModel(modelView.src, prompt);
}
});
shareBtn.addEventListener('click', shareModel);
clearHistoryBtn.addEventListener('click', function() {
if (confirm('Are you sure you want to clear your generation history?')) {
historyList.innerHTML = `
<div class="text-center py-10 text-gray-400" id="empty-history-message">
<i class="fas fa-history text-4xl mb-3"></i>
<p>Your generated models will appear here</p>
</div>
`;
}
});
// Load any saved history from localStorage
function loadHistory() {
// In a real app, you would load from localStorage or a backend
// This is just a placeholder
}
loadHistory();
// Allow pressing Enter in the prompt input to generate
promptInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
generateBtn.click();
}
});
});
</script>
<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=blacksiders/3dgen" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>