[[INSTRUCTION: ]] # Roof Visualizer Shieldline Visualizer Professional AI Design Studio 1 Material Metal Shingle Tile 2 Color 3 Photo 📸 Click to upload home GENERATE DESIGN 🏠 Upload a photo of your home to see the transformation. Original Design AI is rendering... DOWNLOAD DESIGN :root { --sl-primary: #d32f2f; --sl-dark: #1a1a1b; --sl-border: #e2e8f0; } .sl-container { max-width: 1200px; margin: 20px auto; background: #fff; border-radius: 16px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.1); font-family: sans-serif; } .sl-header { background: #fff; padding: 20px 30px; border-bottom: 1px solid var(--sl-border); } .sl-title { font-size: 22px; font-weight: 800; margin: 0; } .sl-title span { color: var(--sl-primary); } .sl-subtitle { font-size: 13px; color: #64748b; margin: 2px 0 0; } .sl-main-grid { display: grid; grid-template-columns: 320px 1fr; min-height: 550px; } .sl-sidebar { padding: 25px; border-right: 1px solid var(--sl-border); background: #fcfcfd; } .sl-step-wrapper { margin-bottom: 25px; } .sl-step-head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; } .step-num { background: var(--sl-dark); color: #fff; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; } .sl-step-head label { font-weight: 700; font-size: 12px; text-transform: uppercase; color: #444; } .sl-btn-group { display: flex; gap: 5px; } .mat-btn { flex: 1; padding: 10px; border: 1px solid var(--sl-border); border-radius: 6px; cursor: pointer; background: #fff; font-weight: 600; font-size: 12px; } .mat-btn.active { background: var(--sl-primary); color: #fff; border-color: var(--sl-primary); } .sl-swatch-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; } .swatch { width: 100%; aspect-ratio: 1; border-radius: 6px; border: 2px solid #fff; box-shadow: 0 2px 4px rgba(0,0,0,0.1); cursor: pointer; transition: 0.2s; } .swatch.active { transform: scale(1.1); box-shadow: 0 0 0 2px var(--sl-primary); } .sl-selected-name { text-align: center; font-size: 11px; color: #64748b; margin-top: 5px; } .sl-upload-card { border: 2px dashed var(--sl-border); padding: 15px; text-align: center; border-radius: 10px; cursor: pointer; } .sl-generate-btn { width: 100%; padding: 15px; background: var(--sl-dark); color: #fff; border: none; border-radius: 8px; font-weight: 700; cursor: pointer; transition: 0.2s; } .sl-generate-btn:hover { background: var(--sl-primary); } .sl-preview { padding: 30px; background: #f1f5f9; } .sl-canvas-box { width: 100%; aspect-ratio: 16/9; background: #fff; border-radius: 12px; overflow: hidden; display: flex; align-items: center; justify-content: center; position: relative; } #sl-empty-state { text-align: center; color: #94a3b8; } /* Slider UI */ .sl-slider-input { position: absolute; -webkit-appearance: none; width: 100%; height: 100%; background: transparent; top: 0; left: 0; cursor: ew-resize; z-index: 10; margin: 0; } .sl-slider-input::-webkit-slider-thumb { -webkit-appearance: none; width: 40px; height: 40px; background: var(--sl-primary); border: 4px solid #fff; border-radius: 50%; } .sl-slider-label { position: absolute; bottom: 15px; background: rgba(0,0,0,0.7); color: #fff; padding: 4px 10px; border-radius: 4px; font-size: 10px; font-weight: 700; pointer-events: none; } .sl-slider-label.before { left: 15px; } .sl-slider-label.after { right: 15px; } .dna-spinner { border: 4px solid #f3f3f3; border-top: 4px solid var(--sl-primary); border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 10px; } @keyframes spin { 100% { transform: rotate(360deg); } } .sl-dl-btn { background: var(--sl-dark); color: #fff; padding: 12px 30px; text-decoration: none; border-radius: 6px; font-weight: 700; } .sl-error-box { padding: 20px; color: var(--sl-primary); background: #fff5f5; border: 1px solid var(--sl-primary); border-radius: 8px; text-align: center; } @media (max-width: 800px) { .sl-main-grid { grid-template-columns: 1fr; } .sl-sidebar { border-right: none; border-bottom: 1px solid var(--sl-border); } } const slCat = {"Metal":{"colors":{"Charcoal Gray":"#4B4C4E","Slate Gray":"#606366","Terra Cotta":"#B55A44","Colonial Red":"#8E3E34","Aged Copper":"#7E5E4E","Evergreen":"#2D3B2D","Bayside Black":"#1A1A1A","Matte Black":"#2B2B2B","Galvalume":"#A6A9AA"}},"Shingle":{"colors":{"Pewter Gray":"#707372","Barkwood":"#5E4B3C","Birchwood":"#D2D2D2","Charcoal":"#363738","Chestnut Valley":"#5D4037","Midnight Mesa":"#212121","Weathered Wood":"#8B8272","Hickory":"#4E3B2B"}},"Tile":{"colors":{"Sanibel Terra Cotta":"#B55A44","Windsor Slate":"#454545","Tuscany Walnut":"#5C4033","Sierra Madre":"#2D2D2D","Indian Red":"#A52A2A"}}}; let selMat = '', selCol = '', upImg = '', upMime = '', originalFull = ''; function slSwitch(m) { selMat = m; document.querySelectorAll('.mat-btn').forEach(b => b.classList.toggle('active', b.innerText === m)); const grid = document.getElementById('sl-swatches'); document.getElementById('sl-palette-box').style.display = 'block'; grid.innerHTML = ''; for (const [name, hex] of Object.entries(slCat[m].colors)) { const s = document.createElement('div'); s.className = 'swatch'; s.style.background = hex; s.title = name; s.onclick = () => { selCol = name; document.querySelectorAll('.swatch').forEach(i => i.classList.remove('active')); s.classList.add('active'); document.getElementById('sl-color-name').innerText = name; }; grid.appendChild(s); } } function slUpload(i) { const f = i.files[0]; if(!f) return; upMime = f.type; document.getElementById('sl-status-text').innerText = f.name; const r = new FileReader(); r.onload = () => { upImg = r.result.split(',')[1]; originalFull = r.result; // Pre-load the "Before" image so it's ready for the slider document.getElementById('sl-img-before').src = r.result; }; r.readAsDataURL(f); } document.getElementById('sl-run').onclick = async () => { if(!upImg || !selCol) return alert("Please select a color and upload your photo first."); const loader = document.getElementById('sl-loading'); const container = document.getElementById('sl-slider-container'); const empty = document.getElementById('sl-empty-state'); const slider = document.getElementById('sl-comparison-slider'); const beforeWrapper = document.getElementById('sl-before-wrapper'); const beforeImg = document.getElementById('sl-img-before'); const canvas = document.getElementById('sl-canvas'); // 1. RESET UI FOR NEW GENERATION loader.style.display = 'block'; empty.style.display = 'none'; container.style.opacity = '0.3'; // Dim the old design while loading document.getElementById('sl-actions').style.display = 'none'; try { const res = await fetch('/wp-json/shieldline/v7/process', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ image: upImg, color: selCol, material: selMat, mime: upMime }) }); const data = await res.json(); if(res.ok && data.image) { // 2. UPDATE IMAGES document.getElementById('sl-img-after').src = data.image; // Ensure "Before" image is still the original upload beforeImg.src = originalFull; // 3. SHOW SLIDER & RESET POSITION container.style.display = 'block'; container.style.opacity = '1'; slider.value = 50; beforeWrapper.style.width = "50%"; // 4. FIX SCALING (Important for repeat renders) const updateSliderSize = () => { beforeImg.style.width = canvas.offsetWidth + "px"; beforeImg.style.height = canvas.offsetHeight + "px"; }; updateSliderSize(); slider.oninput = (e) => { beforeWrapper.style.width = e.target.value + "%"; updateSliderSize(); }; document.getElementById('sl-actions').style.display = 'block'; document.getElementById('sl-dl').href = data.image; } else { alert("AI Error: " + (data.message || "The safety filter blocked this design. Try a clearer photo.")); container.style.opacity = '1'; } } catch(e) { alert("Network Error: Please check your connection."); } finally { loader.style.display = 'none'; } };