💬 Lip Sync Tool

Bring Photos to
Life with Voice

Upload a portrait and audio clip — we animate the mouth in sync with the audio, overlay a waveform, and add cinematic effects. Download as video. 100% in your browser.

Real-time lip sync animation
3 mouth styles
8 visual effects
Download as WebM video
📸 Portrait Photo
🖼️
Drop or click to upload
JPG, PNG, WebP — portrait works best
🎙️ Audio Clip
🎵
Drop or click to upload
MP3, WAV, OGG — up to 60s recommended
😮
Realistic
Natural open/close
😛
Cartoon
Exaggerated style
😑
Minimal
Subtle movement
🎞️
None
🔲
Vignette
🎬
Film Grain
🌅
Warm
❄️
Cool

B&W
💜
Neon Glow
📺
Vintage
'); } function downloadResult(){ if(!recordedBlob)return; var a=document.createElement('a');a.href=URL.createObjectURL(recordedBlob);a.download='talking-photo-'+Date.now()+'.webm';a.click(); } function snapshotFrame(){ var a=document.createElement('a');a.href=document.getElementById('mainCanvas').toDataURL('image/jpeg',.92);a.download='talking-photo-frame-'+Date.now()+'.jpg';a.click(); }function setProgress(pct){document.getElementById('progressCircle').style.strokeDashoffset=157-(157*pct/100);} function showStatus(msg){var el=document.getElementById('statusBox');el.textContent=msg;el.style.display='block';} function showErr(m){var e=document.getElementById('errorMsg');e.textContent='⚠ '+m;e.style.display='block';} function hideErr(){document.getElementById('errorMsg').style.display='none';} function resetAll(){ photoImg=null;audioFile=null;audioBuffer=null;recordedBlob=null; if(animReq)cancelAnimationFrame(animReq); if(sourceNode)try{sourceNode.stop();}catch(e){} ['photoPrompt','audioPrompt'].forEach(function(id){document.getElementById(id).style.display='block';}); ['photoLoaded','audioLoaded'].forEach(function(id){document.getElementById(id).style.display='none';}); ['photoZone','audioZone'].forEach(function(id){document.getElementById(id).classList.remove('loaded');}); document.getElementById('photoInput').value='';document.getElementById('audioInput').value=''; document.getElementById('createBtn').disabled=true;document.getElementById('downloadBtn').disabled=true; document.getElementById('playBtn').disabled=true;document.getElementById('resultWrap').style.display='none'; document.getElementById('statusBox').style.display='none';hideErr(); }