:root{--ind:#1E3A5F;--ind-light:#2a5280;--ind-gradient:linear-gradient(135deg,#1E3A5F 0%,#2a5280 50%,#1a4a7a 100%);--orange:#F15A24;--orange-gradient:linear-gradient(135deg,#F15A24 0%,#ff7a44 100%);--gray-50:#f9fafb;--gray-100:#f3f4f6;--gray-200:#e5e7eb;--gray-500:#6b7280;--gray-700:#374151;--gray-900:#111827;--radius:14px;--shadow:0 1px 3px rgba(0,0,0,.08);--shadow-hover:0 12px 40px rgba(0,0,0,.12);--max-w:720px} *{box-sizing:border-box;margin:0;padding:0} body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,sans-serif;background:var(--gray-50);color:var(--gray-900)} .voice-hero{background:var(--ind-gradient);padding:clamp(48px,6vw,80px) 24px 48px;text-align:center;color:#fff} .voice-hero h1{font-size:clamp(28px,4vw,42px);font-weight:800;line-height:1.15;margin-bottom:14px;letter-spacing:-.02em} .voice-hero p{font-size:clamp(15px,1.8vw,19px);opacity:.88;max-width:560px;margin:0 auto;line-height:1.55} .voice-container{max-width:var(--max-w);margin:-32px auto 60px;padding:0 20px;position:relative;z-index:2} .voice-card{background:#fff;border-radius:var(--radius);box-shadow:var(--shadow-hover);padding:clamp(28px,4vw,44px);margin-bottom:24px} .voice-card h2{font-size:20px;font-weight:700;color:var(--gray-900);margin-bottom:8px} .voice-card p.desc{font-size:15px;color:var(--gray-500);line-height:1.6;margin-bottom:24px} .script-box{background:var(--gray-50);border:1px solid var(--gray-200);border-radius:12px;padding:24px;margin-bottom:28px;position:relative} .script-label{font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--orange);font-weight:700;margin-bottom:10px;display:block} .script-text{font-size:16px;line-height:1.7;color:var(--gray-700);font-style:italic} .waveform-wrap{height:80px;background:#0f1419;border-radius:10px;margin-bottom:20px;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative} .waveform-wrap canvas{width:100%;height:100%} .waveform-placeholder{color:rgba(255,255,255,.35);font-size:14px;position:absolute} .timer-row{display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:24px} .timer{font-size:clamp(32px,5vw,48px);font-weight:800;color:var(--ind);font-variant-numeric:tabular-nums;letter-spacing:.04em} .timer-limit{font-size:16px;color:var(--gray-500);font-weight:500} .record-btn{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;padding:16px;border:none;border-radius:50px;font-size:17px;font-weight:700;cursor:pointer;transition:all .25s} .record-btn.idle{background:var(--orange-gradient);color:#fff;box-shadow:0 4px 20px rgba(241,90,36,.35)} .record-btn.idle:hover{transform:translateY(-2px);box-shadow:0 8px 30px rgba(241,90,36,.45)} .record-btn.recording{background:#DC2626;color:#fff;animation:pulse-red 1.5s infinite} .record-btn.done{background:var(--ind);color:#fff} @keyframes pulse-red{0%,100%{box-shadow:0 0 0 0 rgba(220,38,38,.4)}50%{box-shadow:0 0 0 12px rgba(220,38,38,0)}} .rec-dot{width:12px;height:12px;border-radius:50%;background:#fff;flex-shrink:0} .recording .rec-dot{animation:blink 1s infinite} @keyframes blink{0%,100%{opacity:1}50%{opacity:.3}} .playback-section{display:none;margin-top:24px;padding-top:24px;border-top:1px solid var(--gray-200)} .playback-section.show{display:block} .playback-row{display:flex;align-items:center;gap:12px;margin-bottom:20px} .play-btn{width:44px;height:44px;border-radius:50%;background:var(--ind);color:#fff;border:none;cursor:pointer;font-size:18px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:transform .2s} .play-btn:hover{transform:scale(1.08)} .audio-bar{flex:1;height:6px;background:var(--gray-200);border-radius:3px;position:relative;cursor:pointer} .audio-bar-fill{height:100%;background:var(--ind);border-radius:3px;width:0%;transition:width .1s linear} .audio-time{font-size:13px;color:var(--gray-500);font-variant-numeric:tabular-nums;min-width:40px;text-align:right} .action-row{display:flex;gap:12px;margin-top:20px;flex-wrap:wrap} .action-row .btn{flex:1;min-width:200px;padding:15px 24px;border-radius:50px;font-size:16px;font-weight:700;cursor:pointer;text-align:center;transition:all .25s;border:none;text-decoration:none;display:inline-flex;align-items:center;justify-content:center;gap:8px} .btn-primary{background:var(--orange-gradient);color:#fff;box-shadow:0 4px 20px rgba(241,90,36,.3)} .btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 30px rgba(241,90,36,.4)} .btn-secondary{background:#fff;color:var(--gray-700);border:2px solid var(--gray-200) !important} .btn-secondary:hover{border-color:var(--gray-500) !important;color:var(--gray-900)} .btn-rerecord{background:transparent;color:var(--gray-500);border:1px solid var(--gray-200) !important;font-size:14px;padding:10px 20px;min-width:auto;flex:0} .btn-rerecord:hover{color:var(--gray-700);border-color:var(--gray-500) !important} .loading-overlay{display:none;position:fixed;inset:0;background:rgba(15,20,25,.85);z-index:9999;align-items:center;justify-content:center;flex-direction:column;gap:20px} .loading-overlay.show{display:flex} .loading-spinner{width:56px;height:56px;border:4px solid rgba(255,255,255,.15);border-top-color:var(--orange);border-radius:50%;animation:spin .8s linear infinite} @keyframes spin{to{transform:rotate(360deg)}} .loading-text{color:#fff;font-size:18px;font-weight:600;text-align:center;max-width:320px;line-height:1.5} .loading-sub{color:rgba(255,255,255,.6);font-size:14px;text-align:center} .error-msg{background:#FEF2F2;border:1px solid #FECACA;border-radius:10px;padding:14px 18px;color:#DC2626;font-size:14px;margin-top:16px;display:none} .error-msg.show{display:block} .skip-section{text-align:center;margin-top:8px} .skip-link{display:inline-flex;align-items:center;gap:6px;color:var(--gray-500);font-size:15px;text-decoration:none;padding:12px 24px;border-radius:50px;transition:all .2s} .skip-link:hover{color:var(--gray-700);background:var(--gray-100)} .permission-denied{display:none;text-align:center;padding:40px 20px} .permission-denied.show{display:block} .permission-denied h3{font-size:20px;color:var(--gray-900);margin-bottom:12px} .permission-denied p{color:var(--gray-500);font-size:15px;line-height:1.6;margin-bottom:24px}

Personalize Your Property Video

Record 30 seconds of your voice and we'll use it for your property video tour — your clients hear you, not a generic AI narrator.

Read the Script Below

Click record and read the following script naturally. This gives us enough of your voice to generate the full narration.

Your Script
Welcome to this beautiful property. Featuring elegant living spaces, modern amenities, and stunning views, this home offers the perfect blend of luxury and comfort. Located in one of the most desirable neighborhoods, with top-rated schools and vibrant local dining. Schedule your private showing today.
Waveform will appear here
0:00 / 0:30
0:00

Microphone Access Required

Please allow microphone access in your browser to record your voice. Click the lock icon in your address bar and enable the microphone.

Continue with Default Voice
Cloning your voice...
This takes about 30 seconds. Please don't close this page.
(function(){ var mediaRecorder = null; var audioChunks = []; var audioBlob = null; var audioUrl = null; var audioElement = null; var stream = null; var analyser = null; var animFrameId = null; var timerInterval = null; var seconds = 0; var isRecording = false; var isPlaying = false; var canvas = document.getElementById("waveformCanvas"); var ctx = canvas.getContext("2d"); var recordBtn = document.getElementById("recordBtn"); var recordLabel = document.getElementById("recordLabel"); var timerEl = document.getElementById("timer"); var playbackSection = document.getElementById("playbackSection"); var playBtn = document.getElementById("playBtn"); var audioBarFill = document.getElementById("audioBarFill"); var audioTimeEl = document.getElementById("audioTime"); var loadingOverlay = document.getElementById("loadingOverlay"); var errorMsg = document.getElementById("errorMsg"); var waveformPlaceholder = document.getElementById("waveformPlaceholder"); var urlParams = new URLSearchParams(window.location.search); var propertyId = urlParams.get("property_id") || ""; if (propertyId) { var links = document.querySelectorAll('a[href*="/broker-building/"]'); for (var i = 0; i < links.length; i++) { links[i].href = "/broker-building/?property_id=" + propertyId; } } function resizeCanvas() { var wrap = document.getElementById("waveformWrap"); var dpr = window.devicePixelRatio || 1; canvas.width = wrap.clientWidth * dpr; canvas.height = wrap.clientHeight * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); } resizeCanvas(); window.addEventListener("resize", resizeCanvas); function fmt(s) { return Math.floor(s / 60) + ":" + String(Math.floor(s % 60)).padStart(2, "0"); } function drawWaveform(dataArray, bufferLength) { var dpr = window.devicePixelRatio || 1; var w = canvas.width / dpr; var h = canvas.height / dpr; ctx.clearRect(0, 0, w, h); ctx.fillStyle = "#0f1419"; ctx.fillRect(0, 0, w, h); var barW = 3; var gap = 2; var bars = Math.floor(w / (barW + gap)); var step = Math.floor(bufferLength / bars); for (var i = 0; i < bars; i++) { var sum = 0; for (var j = 0; j < step; j++) { sum += dataArray[i * step + j]; } var avg = sum / step; var barH = Math.max(2, (avg / 255) * h * 0.85); var x = i * (barW + gap); var y = (h - barH) / 2; var gradient = ctx.createLinearGradient(x, y, x, y + barH); gradient.addColorStop(0, "#F15A24"); gradient.addColorStop(1, "#ff7a44"); ctx.fillStyle = gradient; ctx.fillRect(x, y, barW, barH); } if (isRecording) { animFrameId = requestAnimationFrame(function() { analyser.getByteFrequencyData(dataArray); drawWaveform(dataArray, bufferLength); }); } } function drawIdleWaveform() { var dpr = window.devicePixelRatio || 1; var w = canvas.width / dpr; var h = canvas.height / dpr; ctx.clearRect(0, 0, w, h); ctx.fillStyle = "#0f1419"; ctx.fillRect(0, 0, w, h); var barW = 3, gap = 2; var bars = Math.floor(w / (barW + gap)); for (var i = 0; i 0) audioChunks.push(e.data); }; mediaRecorder.onstop = function() { audioBlob = new Blob(audioChunks, { type: mediaRecorder.mimeType || "audio/webm" }); audioUrl = URL.createObjectURL(audioBlob); audioElement = new Audio(audioUrl); showPlayback(); }; mediaRecorder.start(250); isRecording = true; recordBtn.className = "record-btn recording"; recordLabel.textContent = "Stop Recording"; timerInterval = setInterval(function() { seconds++; timerEl.textContent = fmt(seconds); if (seconds >= 30) { stopRecording(); } }, 1000); analyser.getByteFrequencyData(dataArray); drawWaveform(dataArray, bufferLength); } function stopRecording() { isRecording = false; if (timerInterval) { clearInterval(timerInterval); timerInterval = null; } if (animFrameId) { cancelAnimationFrame(animFrameId); animFrameId = null; } if (mediaRecorder && mediaRecorder.state !== "inactive") { mediaRecorder.stop(); } if (stream) { stream.getTracks().forEach(function(t) { t.stop(); }); stream = null; } recordBtn.className = "record-btn done"; recordLabel.textContent = "Recording Complete"; recordBtn.disabled = true; } function showPlayback() { playbackSection.classList.add("show"); audioElement.addEventListener("timeupdate", function() { if (audioElement.duration) { var pct = (audioElement.currentTime / audioElement.duration) * 100; audioBarFill.style.width = pct + "%"; audioTimeEl.textContent = fmt(audioElement.currentTime); } }); audioElement.addEventListener("ended", function() { isPlaying = false; playBtn.innerHTML = "▶"; audioBarFill.style.width = "0%"; audioTimeEl.textContent = "0:00"; }); } window.togglePlayback = function() { if (!audioElement) return; if (isPlaying) { audioElement.pause(); isPlaying = false; playBtn.innerHTML = "▶"; } else { audioElement.play(); isPlaying = true; playBtn.innerHTML = "❚❚"; } }; window.seekAudio = function(e) { if (!audioElement || !audioElement.duration) return; var bar = document.getElementById("audioBar"); var rect = bar.getBoundingClientRect(); var pct = (e.clientX - rect.left) / rect.width; audioElement.currentTime = pct * audioElement.duration; }; window.resetRecording = function() { if (audioElement) { audioElement.pause(); audioElement = null; } if (audioUrl) { URL.revokeObjectURL(audioUrl); audioUrl = null; } audioBlob = null; audioChunks = []; isPlaying = false; seconds = 0; timerEl.textContent = "0:00"; playbackSection.classList.remove("show"); recordBtn.disabled = false; recordBtn.className = "record-btn idle"; recordLabel.textContent = "Start Recording"; errorMsg.classList.remove("show"); drawIdleWaveform(); waveformPlaceholder.style.display = ""; }; window.submitVoice = async function() { if (!audioBlob) return; if (!propertyId) { showError("Missing property ID. Please return to checkout."); return; } loadingOverlay.classList.add("show"); try { var formData = new FormData(); var ext = (audioBlob.type.indexOf("webm") > -1) ? "webm" : (audioBlob.type.indexOf("mp4") > -1 ? "m4a" : "wav"); formData.append("audio", audioBlob, "voice-recording." + ext); formData.append("property_id", propertyId); var resp = await fetch("/api/broker-voice-clone.php", { method: "POST", body: formData }); var data = await resp.json(); if (data.success) { window.location.href = "/broker-building/?property_id=" + propertyId + "&voice=cloned"; } else { loadingOverlay.classList.remove("show"); showError(data.error || "Voice cloning failed. Please try again or skip."); } } catch (e) { loadingOverlay.classList.remove("show"); showError("Network error. Please check your connection and try again."); } }; function showError(msg) { errorMsg.textContent = msg; errorMsg.classList.add("show"); } drawIdleWaveform(); })();
LinkedIn Instagram TikTok Facebook Pinterest
E

Chat with East13

Typically replies instantly