Studio Lecteur — Motion Graphics v2
Collez votre HTML animé
📄 Code HTML Ctrl+EntrĂ©e → Aperçu
đŸ–„️ Aperçu En attente
🎞️ Collez votre code HTML Ă  gauche,
puis cliquez sur ▶ Aperçu
Export en cours…
`; // ---- FIN EXEMPLE ---- codeInput.value = exemple; // ---- FONCTIONS UTILITAIRES ---- function updateRatio() { var val = ratioSelect.value; previewFrame.className = ''; if (val === 'ratio-16-9' || val === 'ratio-9-16' || val === 'ratio-auto') { previewFrame.classList.add(val); } } function getIframeDocument() { try { return previewFrame.contentDocument || previewFrame.contentWindow.document; } catch (e) { return null; } } function showProgress(label, percent) { progressOverlay.classList.add('show'); progressLabel.textContent = label; progressFill.style.width = Math.min(100, percent) + '%'; } function hideProgress() { progressOverlay.classList.remove('show'); progressFill.style.width = '0%'; } // ---- FONCTIONS D'EXPORT CRÉATIF ---- // 1. PNG : capture instantanĂ©e async function capturePNG() { var doc = getIframeDocument(); if (!doc) { alert('Affichez d\'abord l\'aperçu.'); return; } showProgress('Capture PNG…', 30); try { var canvas = await html2canvas(doc.body, { scale: 1.5, backgroundColor: null, useCORS: true, logging: false }); showProgress('GĂ©nĂ©ration…', 80); var link = document.createElement('a'); link.download = 'capture_' + Date.now() + '.png'; link.href = canvas.toDataURL('image/png'); link.click(); hideProgress(); statusBadge.textContent = '✅ PNG exportĂ©'; statusBadge.className = 'status-badge ok'; } catch (e) { hideProgress(); alert('Erreur PNG : ' + e.message); statusBadge.textContent = '⚠️ Erreur PNG'; statusBadge.className = 'status-badge error'; } } // 2. WebM : enregistrement vidĂ©o de 3s (15 fps) async function captureWebM() { var doc = getIframeDocument(); if (!doc) { alert('Affichez d\'abord l\'aperçu.'); return; } var duration = 3000; // 3 secondes var fps = 15; var totalFrames = Math.ceil((duration / 1000) * fps); // RĂ©cupĂ©rer les dimensions du contenu de l'iframe var body = doc.body; var width = body.scrollWidth || 800; var height = body.scrollHeight || 600; var canvas = document.createElement('canvas'); canvas.width = Math.min(width, 1920); canvas.height = Math.min(height, 1080); var ctx = canvas.getContext('2d'); var stream = canvas.captureStream(fps); var recorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=vp9' }); var chunks = []; recorder.ondataavailable = function(e) { if (e.data.size > 0) chunks.push(e.data); }; recorder.start(); showProgress('Enregistrement WebM (3s)…', 0); var frameCount = 0; var interval = setInterval(async function() { try { var captured = await html2canvas(body, { scale: 1, backgroundColor: null, useCORS: true, logging: false, width: width, height: height }); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(captured, 0, 0, canvas.width, canvas.height); } catch (e) { /* ignore frame errors */ } frameCount++; var progress = (frameCount / totalFrames) * 100; showProgress('Enregistrement WebM (3s)…', progress); if (frameCount >= totalFrames) { clearInterval(interval); recorder.stop(); recorder.onstop = function() { var blob = new Blob(chunks, { type: 'video/webm' }); var url = URL.createObjectURL(blob); var link = document.createElement('a'); link.download = 'animation_' + Date.now() + '.webm'; link.href = url; link.click(); setTimeout(function() { URL.revokeObjectURL(url); }, 5000); hideProgress(); statusBadge.textContent = '✅ WebM exportĂ©'; statusBadge.className = 'status-badge ok'; }; } }, 1000 / fps); } // 3. GIF animĂ© : 3 secondes Ă  10 fps (30 frames) async function captureGIF() { var doc = getIframeDocument(); if (!doc) { alert('Affichez d\'abord l\'aperçu.'); return; } if (typeof GIF === 'undefined') { alert('La bibliothĂšque GIF.js n\'est pas chargĂ©e.'); return; } var duration = 3000; var fps = 10; var totalFrames = Math.ceil((duration / 1000) * fps); var delay = Math.round(1000 / fps); var body = doc.body; var width = Math.min(body.scrollWidth || 800, 800); var height = Math.min(body.scrollHeight || 600, 600); var gif = new GIF({ workers: 2, quality: 10, width: width, height: height }); showProgress('GĂ©nĂ©ration GIF (3s)…', 0); var frameCount = 0; var interval = setInterval(async function() { try { var captured = await html2canvas(body, { scale: 1, backgroundColor: null, useCORS: true, logging: false, width: width, height: height }); // Redimensionner si nĂ©cessaire if (captured.width !== width || captured.height !== height) { var tempCanvas = document.createElement('canvas'); tempCanvas.width = width; tempCanvas.height = height; var tempCtx = tempCanvas.getContext('2d'); tempCtx.drawImage(captured, 0, 0, width, height); gif.addFrame(tempCanvas, { copy: true, delay: delay }); } else { gif.addFrame(captured, { copy: true, delay: delay }); } } catch (e) { /* ignore frame errors */ } frameCount++; var progress = (frameCount / totalFrames) * 100; showProgress('GĂ©nĂ©ration GIF (3s)…', progress); if (frameCount >= totalFrames) { clearInterval(interval); gif.on('progress', function(p) { showProgress('Encodage GIF…', 50 + p * 0.5); }); gif.on('finished', function(blob) { var url = URL.createObjectURL(blob); var link = document.createElement('a'); link.download = 'animation_' + Date.now() + '.gif'; link.href = url; link.click(); setTimeout(function() { URL.revokeObjectURL(url); }, 5000); hideProgress(); statusBadge.textContent = '✅ GIF exportĂ©'; statusBadge.className = 'status-badge ok'; }); gif.render(); } }, delay); } // ---- PRÉVISUALISATION ---- function previewCode() { var code = codeInput.value; if (!code || !code.trim()) { statusBadge.textContent = 'Erreur : code vide'; statusBadge.className = 'status-badge error'; return; } if (currentBlobUrl) { URL.revokeObjectURL(currentBlobUrl); currentBlobUrl = null; } statusBadge.textContent = 'Chargement…'; statusBadge.className = 'status-badge loading'; placeholder.style.display = 'none'; previewFrame.style.display = 'block'; try { var blob = new Blob([code], { type: 'text/html;charset=utf-8' }); var url = URL.createObjectURL(blob); currentBlobUrl = url; previewFrame.src = url; var timeout = setTimeout(function() { if (statusBadge.classList.contains('loading')) { statusBadge.textContent = '⚠️ Long chargement…'; statusBadge.className = 'status-badge'; } }, 3000); previewFrame.onload = function() { clearTimeout(timeout); statusBadge.textContent = '✅ AffichĂ©'; statusBadge.className = 'status-badge ok'; updateRatio(); }; previewFrame.onerror = function() { clearTimeout(timeout); statusBadge.textContent = '⚠️ Erreur dans le code'; statusBadge.className = 'status-badge error'; }; } catch (e) { statusBadge.textContent = 'Erreur : ' + e.message; statusBadge.className = 'status-badge error'; previewFrame.style.display = 'none'; placeholder.style.display = 'block'; } } // ---- TÉLÉCHARGER HTML ---- function downloadCode() { var code = codeInput.value; if (!code || !code.trim()) { alert('Collez d\'abord du code HTML.'); return; } var blob = new Blob([code], { type: 'text/html;charset=utf-8' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = 'motion_graphic.html'; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(function() { URL.revokeObjectURL(url); }, 5000); statusBadge.textContent = '⬇ TĂ©lĂ©chargĂ©'; statusBadge.className = 'status-badge ok'; } // ---- PLEIN ÉCRAN ---- function toggleFullscreen() { var target = previewFrame; if (!target) return; if (target.style.display === 'none') { alert('Affichez d\'abord l\'aperçu.'); return; } if (!document.fullscreenElement) { target.requestFullscreen?.() || target.webkitRequestFullscreen?.() || target.msRequestFullscreen?.(); } else { document.exitFullscreen?.() || document.webkitExitFullscreen?.() || document.msExitFullscreen?.(); } } // ---- EFFACER ---- function clearCode() { codeInput.value = ''; if (currentBlobUrl) { URL.revokeObjectURL(currentBlobUrl); currentBlobUrl = null; } previewFrame.src = ''; previewFrame.style.display = 'none'; placeholder.style.display = 'block'; statusBadge.textContent = 'EffacĂ©'; statusBadge.className = 'status-badge'; } // ---- ÉVÉNEMENTS ---- previewBtn.addEventListener('click', previewCode); downloadBtn.addEventListener('click', downloadCode); fullscreenBtn.addEventListener('click', toggleFullscreen); clearBtn.addEventListener('click', clearCode); // Nouveaux Ă©vĂ©nements pngBtn.addEventListener('click', capturePNG); webmBtn.addEventListener('click', captureWebM); gifBtn.addEventListener('click', captureGIF); ratioSelect.addEventListener('change', function() { if (previewFrame.style.display !== 'none') { updateRatio(); } }); codeInput.addEventListener('keydown', function(e) { if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); previewCode(); } }); previewFrame.addEventListener('dblclick', toggleFullscreen); // ---- LANCER L'APERÇU AUTOMATIQUEMENT ---- setTimeout(function() { previewCode(); }, 400); console.log('Studio Lecteur v2 — Exports crĂ©atifs : PNG, WebM, GIF'); })();