Download beginner.html from sam-bottes/morphoweb-3d-architect: direct link, hf CLI and curl.
- Browser
- Download file 21.5 kB
-
https://huggingface.co/spaces/sam-bottes/morphoweb-3d-architect/resolve/main/beginner.html
- Command line
-
hf download hf://spaces/sam-bottes/morphoweb-3d-architect/beginner.html
-
curl -L -o beginner.html https://huggingface.co/spaces/sam-bottes/morphoweb-3d-architect/resolve/main/beginner.html
21.5 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>MorphoWeb 3D - Architecte Visuel</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
| <style> | |
| #preview-container { | |
| background-color: #f3f4f6; | |
| border-radius: 0.5rem; | |
| height: 600px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .grid-cell { | |
| border: 1px dashed #d1d5db; | |
| position: absolute; | |
| background-color: rgba(255, 255, 255, 0.3); | |
| } | |
| .element { | |
| position: absolute; | |
| cursor: move; | |
| z-index: 10; | |
| transition: all 0.2s; | |
| } | |
| .element:hover { | |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); | |
| transform: scale(1.02); | |
| } | |
| .element-header { | |
| background: linear-gradient(135deg, #6366f1, #8b5cf6); | |
| color: white; | |
| } | |
| .element-text { | |
| background: linear-gradient(135deg, #f59e0b, #f97316); | |
| color: white; | |
| } | |
| .element-image { | |
| background: linear-gradient(135deg, #10b981, #059669); | |
| color: white; | |
| } | |
| .element-button { | |
| background: linear-gradient(135deg, #ef4444, #dc2626); | |
| color: white; | |
| } | |
| .chat-message { | |
| max-width: 80%; | |
| border-radius: 1rem; | |
| padding: 0.75rem 1rem; | |
| margin-bottom: 0.5rem; | |
| } | |
| .user-message { | |
| background-color: #6366f1; | |
| color: white; | |
| margin-left: auto; | |
| border-bottom-right-radius: 0.25rem; | |
| } | |
| .ai-message { | |
| background-color: #e5e7eb; | |
| color: #111827; | |
| margin-right: auto; | |
| border-bottom-left-radius: 0.25rem; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100"> | |
| <div class="flex h-screen"> | |
| <!-- Sidebar --> | |
| <div class="w-64 bg-white shadow-md p-4 overflow-y-auto"> | |
| <div class="flex items-center mb-6"> | |
| <i data-feather="box" class="text-purple-600 mr-2"></i> | |
| <h2 class="text-xl font-bold">Elements</h2> | |
| </div> | |
| <div class="space-y-3"> | |
| <div class="element-draggable p-3 bg-gray-50 rounded-lg border border-gray-200 cursor-pointer" draggable="true" data-type="header"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center mr-2"> | |
| <i data-feather="type" class="text-indigo-600 w-4 h-4"></i> | |
| </div> | |
| <span>Header</span> | |
| </div> | |
| </div> | |
| <div class="element-draggable p-3 bg-gray-50 rounded-lg border border-gray-200 cursor-pointer" draggable="true" data-type="text"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-amber-100 flex items-center justify-center mr-2"> | |
| <i data-feather="align-left" class="text-amber-600 w-4 h-4"></i> | |
| </div> | |
| <span>Text Block</span> | |
| </div> | |
| </div> | |
| <div class="element-draggable p-3 bg-gray-50 rounded-lg border border-gray-200 cursor-pointer" draggable="true" data-type="image"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-emerald-100 flex items-center justify-center mr-2"> | |
| <i data-feather="image" class="text-emerald-600 w-4 h-4"></i> | |
| </div> | |
| <span>Image</span> | |
| </div> | |
| </div> | |
| <div class="element-draggable p-3 bg-gray-50 rounded-lg border border-gray-200 cursor-pointer" draggable="true" data-type="button"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-red-100 flex items-center justify-center mr-2"> | |
| <i data-feather="mouse-pointer" class="text-red-600 w-4 h-4"></i> | |
| </div> | |
| <span>Button</span> | |
| </div> | |
| </div> | |
| <div class="element-draggable p-3 bg-gray-50 rounded-lg border border-gray-200 cursor-pointer" draggable="true" data-type="video"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center mr-2"> | |
| <i data-feather="video" class="text-blue-600 w-4 h-4"></i> | |
| </div> | |
| <span>Video</span> | |
| </div> | |
| </div> | |
| <div class="element-draggable p-3 bg-gray-50 rounded-lg border border-gray-200 cursor-pointer" draggable="true" data-type="form"> | |
| <div class="flex items-center"> | |
| <div class="w-8 h-8 rounded-full bg-green-100 flex items-center justify-center mr-2"> | |
| <i data-feather="edit-3" class="text-green-600 w-4 h-4"></i> | |
| </div> | |
| <span>Contact Form</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mt-8"> | |
| <h3 class="font-medium mb-2 flex items-center"> | |
| <i data-feather="help-circle" class="w-4 h-4 mr-2"></i> | |
| Quick Tips | |
| </h3> | |
| <div class="text-sm text-gray-600 space-y-2"> | |
| <p>• Drag elements to the canvas</p> | |
| <p>• Double-click to edit content</p> | |
| <p>• Resize by dragging corners</p> | |
| <p>• Ask Codex AI for help anytime</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="flex-1 flex flex-col"> | |
| <!-- Toolbar --> | |
| <div class="bg-white shadow-sm p-3 flex items-center justify-between"> | |
| <div class="flex items-center space-x-4"> | |
| <h1 class="font-bold text-lg">Architecte Visuel</h1> | |
| <div class="flex items-center text-sm bg-indigo-50 text-indigo-700 px-3 py-1 rounded-full"> | |
| <i data-feather="compass" class="w-4 h-4 mr-1"></i> | |
| <span>Construction Guidée</span> | |
| </div> | |
| </div> | |
| <div class="flex space-x-3"> | |
| <button class="flex items-center px-3 py-1 bg-gray-100 rounded-md text-sm hover:bg-gray-200"> | |
| <i data-feather="eye" class="w-4 h-4 mr-1"></i> | |
| Prévisualiser | |
| </button> | |
| <button class="flex items-center px-3 py-1 bg-indigo-600 text-white rounded-md text-sm hover:bg-indigo-700"> | |
| <i data-feather="download" class="w-4 h-4 mr-1"></i> | |
| Exporter | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Canvas Area --> | |
| <div class="flex-1 p-6 overflow-auto"> | |
| <div id="preview-container" class="w-full relative"> | |
| <!-- Grid will be generated here --> | |
| </div> | |
| </div> | |
| <!-- AI Assistant Chat --> | |
| <div class="bg-white border-t border-gray-200 h-64 flex flex-col"> | |
| <div class="p-3 border-b border-gray-200 flex items-center bg-gray-50"> | |
| <div class="w-8 h-8 rounded-full bg-purple-100 flex items-center justify-center mr-2"> | |
| <i data-feather="cpu" class="text-purple-600 w-4 h-4"></i> | |
| </div> | |
| <h3 class="font-medium">Assistant IA Codex</h3> | |
| <button class="ml-auto text-gray-500 hover:text-gray-700"> | |
| <i data-feather="minimize-2" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| <div id="chat-messages" class="flex-1 p-4 overflow-y-auto"> | |
| <div class="chat-message ai-message"> | |
| <p>Bonjour ! Je suis Codex, votre assistant IA. Je peux vous aider à construire votre site web. Essayez de glisser un élément depuis la barre latérale pour commencer !</p> | |
| </div> | |
| </div> | |
| <div class="p-3 border-t border-gray-200 flex"> | |
| <input type="text" placeholder="Demandez de l'aide à Codex..." class="flex-1 border border-gray-300 rounded-l-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-500"> | |
| <button class="bg-indigo-600 text-white px-4 py-2 rounded-r-lg hover:bg-indigo-700"> | |
| <i data-feather="send" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| feather.replace(); | |
| // Create grid for the canvas | |
| const container = document.getElementById('preview-container'); | |
| const containerWidth = container.clientWidth; | |
| const containerHeight = container.clientHeight; | |
| const gridSize = 20; // pixels | |
| // Generate grid cells | |
| for (let x = 0; x < containerWidth; x += gridSize) { | |
| for (let y = 0; y < containerHeight; y += gridSize) { | |
| const cell = document.createElement('div'); | |
| cell.className = 'grid-cell'; | |
| cell.style.width = `${gridSize}px`; | |
| cell.style.height = `${gridSize}px`; | |
| cell.style.left = `${x}px`; | |
| cell.style.top = `${y}px`; | |
| container.appendChild(cell); | |
| } | |
| } | |
| // Handle drag and drop for elements | |
| const draggables = document.querySelectorAll('.element-draggable'); | |
| draggables.forEach(draggable => { | |
| draggable.addEventListener('dragstart', (e) => { | |
| e.dataTransfer.setData('text/plain', draggable.dataset.type); | |
| e.dataTransfer.effectAllowed = 'copy'; | |
| }); | |
| }); | |
| container.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| e.dataTransfer.dropEffect = 'copy'; | |
| }); | |
| container.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| const type = e.dataTransfer.getData('text/plain'); | |
| const x = e.clientX - container.getBoundingClientRect().left; | |
| const y = e.clientY - container.getBoundingClientRect().top; | |
| // Snap to grid | |
| const snappedX = Math.floor(x / gridSize) * gridSize; | |
| const snappedY = Math.floor(y / gridSize) * gridSize; | |
| createElement(type, snappedX, snappedY); | |
| }); | |
| // Create elements on the canvas | |
| function createElement(type, x, y) { | |
| const element = document.createElement('div'); | |
| element.className = `element element-${type}`; | |
| element.dataset.type = type; | |
| // Position and size | |
| element.style.left = `${x}px`; | |
| element.style.top = `${y}px`; | |
| // Set default dimensions based on type | |
| let width, height, content; | |
| switch(type) { | |
| case 'header': | |
| width = 300; | |
| height = 80; | |
| content = '<h1>Your Header Text</h1>'; | |
| element.classList.add('element-header'); | |
| break; | |
| case 'text': | |
| width = 200; | |
| height = 120; | |
| content = '<p>Double-click to edit this text block.</p>'; | |
| element.classList.add('element-text'); | |
| break; | |
| case 'image': | |
| width = 250; | |
| height = 150; | |
| content = '<div class="flex items-center justify-center h-full"><i data-feather="image" class="w-12 h-12"></i></div>'; | |
| element.classList.add('element-image'); | |
| break; | |
| case 'button': | |
| width = 120; | |
| height = 40; | |
| content = '<button class="w-full h-full">Click Me</button>'; | |
| element.classList.add('element-button'); | |
| break; | |
| default: | |
| width = 150; | |
| height = 100; | |
| content = '<p>New Element</p>'; | |
| } | |
| element.style.width = `${width}px`; | |
| element.style.height = `${height}px`; | |
| element.innerHTML = content; | |
| // Make element draggable | |
| element.draggable = true; | |
| element.addEventListener('dragstart', (e) => { | |
| e.dataTransfer.setData('text/plain', 'move'); | |
| e.dataTransfer.setData('element-id', e.target.id || (e.target.id = 'el-' + Date.now())); | |
| e.dataTransfer.effectAllowed = 'move'; | |
| }); | |
| // Handle double-click to edit | |
| element.addEventListener('dblclick', () => { | |
| if (type === 'text') { | |
| const currentText = element.querySelector('p').textContent; | |
| const newText = prompt('Edit text:', currentText); | |
| if (newText !== null) { | |
| element.querySelector('p').textContent = newText; | |
| } | |
| } else if (type === 'header') { | |
| const currentText = element.querySelector('h1').textContent; | |
| const newText = prompt('Edit header:', currentText); | |
| if (newText !== null) { | |
| element.querySelector('h1').textContent = newText; | |
| } | |
| } else if (type === 'button') { | |
| const currentText = element.querySelector('button').textContent; | |
| const newText = prompt('Edit button text:', currentText); | |
| if (newText !== null) { | |
| element.querySelector('button').textContent = newText; | |
| } | |
| } | |
| }); | |
| // Add resize handles | |
| if (type !== 'button') { | |
| const resizeHandle = document.createElement('div'); | |
| resizeHandle.className = 'absolute bottom-0 right-0 w-3 h-3 bg-white border border-gray-400 cursor-nwse-resize'; | |
| resizeHandle.style.transform = 'translate(50%, 50%)'; | |
| resizeHandle.addEventListener('mousedown', initResize); | |
| element.appendChild(resizeHandle); | |
| } | |
| container.appendChild(element); | |
| feather.replace(); | |
| // Notify AI | |
| addAIMessage(`I've added a ${type} element to your page. You can move it by dragging.`); | |
| } | |
| // Handle moving elements | |
| container.addEventListener('dragover', (e) => { | |
| e.preventDefault(); | |
| e.dataTransfer.dropEffect = 'move'; | |
| }); | |
| container.addEventListener('drop', (e) => { | |
| e.preventDefault(); | |
| if (e.dataTransfer.getData('text/plain') === 'move') { | |
| const id = e.dataTransfer.getData('element-id'); | |
| const element = document.getElementById(id); | |
| if (element) { | |
| const x = e.clientX - container.getBoundingClientRect().left - parseInt(element.style.width) / 2; | |
| const y = e.clientY - container.getBoundingClientRect().top - parseInt(element.style.height) / 2; | |
| // Snap to grid | |
| const snappedX = Math.floor(x / gridSize) * gridSize; | |
| const snappedY = Math.floor(y / gridSize) * gridSize; | |
| element.style.left = `${snappedX}px`; | |
| element.style.top = `${snappedY}px`; | |
| } | |
| } | |
| }); | |
| // Resize functionality | |
| function initResize(e) { | |
| e.stopPropagation(); | |
| const element = e.target.parentElement; | |
| const startX = e.clientX; | |
| const startY = e.clientY; | |
| const startWidth = parseInt(element.style.width); | |
| const startHeight = parseInt(element.style.height); | |
| function doResize(e) { | |
| const newWidth = startWidth + (e.clientX - startX); | |
| const newHeight = startHeight + (e.clientY - startY); | |
| // Snap to grid | |
| const snappedWidth = Math.max(40, Math.floor(newWidth / gridSize) * gridSize); | |
| const snappedHeight = Math.max(40, Math.floor(newHeight / gridSize) * gridSize); | |
| element.style.width = `${snappedWidth}px`; | |
| element.style.height = `${snappedHeight}px`; | |
| } | |
| function stopResize() { | |
| window.removeEventListener('mousemove', doResize); | |
| window.removeEventListener('mouseup', stopResize); | |
| } | |
| window.addEventListener('mousemove', doResize); | |
| window.addEventListener('mouseup', stopResize); | |
| } | |
| // Chat functionality | |
| function addAIMessage(text) { | |
| const chat = document.getElementById('chat-messages'); | |
| const message = document.createElement('div'); | |
| message.className = 'chat-message ai-message'; | |
| message.innerHTML = `<p>${text}</p>`; | |
| chat.appendChild(message); | |
| chat.scrollTop = chat.scrollHeight; | |
| } | |
| // Handle chat input | |
| const chatInput = document.querySelector('#chat-messages + div input'); | |
| const chatButton = document.querySelector('#chat-messages + div button'); | |
| chatButton.addEventListener('click', () => { | |
| const message = chatInput.value.trim(); | |
| if (message) { | |
| // Add user message | |
| const chat = document.getElementById('chat-messages'); | |
| const userMessage = document.createElement('div'); | |
| userMessage.className = 'chat-message user-message'; | |
| userMessage.innerHTML = `<p>${message}</p>`; | |
| chat.appendChild(userMessage); | |
| // Clear input | |
| chatInput.value = ''; | |
| // Simulate AI response (in a real app, this would call an API) | |
| setTimeout(() => { | |
| const responses = [ | |
| "Je peux vous aider avec ça ! Que souhaitez-vous savoir précisément ?", | |
| "Excellente question ! Pour cet élément, essayez de double-cliquer pour modifier son contenu.", | |
| "Vous pouvez redimensionner les éléments en tirant la poignée dans le coin inférieur droit.", | |
| "Essayez de glisser un autre élément depuis la barre latérale pour ajouter du contenu.", | |
| "Voulez-vous que je génère du contenu exemple pour vous ?" | |
| ]; | |
| addAIMessage(responses[Math.floor(Math.random() * responses.length)]); | |
| }, 1000); | |
| } | |
| }); | |
| // Allow pressing Enter to send message | |
| chatInput.addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| chatButton.click(); | |
| } | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |