128 BPM
Escenas:
⚡ Batch + IA
🎬 Escenas
🧊 3D
⚡ FX
🎵 Audio
📝 Texto
🎥 Video
🎬 Referencia YouTube
🎨 Estilo
🌍 Escenario
👤 Personaje
📸 Foto de referencia (opcional)Para mantener el mismo personaje
● FlinFlow
Sin escenas — genera imágenes →
flash + zoom
Director IA — FlinFlow Pídeme que genere escenas, proponga movimientos de cámara o dirija el video
Editor
F:0/240 · 0:00
// ══════════════════════════════════════════════════════ // IMAGE ENGINE — Pollinations with robust retry // No fal.ai (key 401), no parallel requests // ══════════════════════════════════════════════════════ function setCardStatus(cardId, msg, isErr=false){ const c=document.getElementById(cardId);if(!c)return; let el=c.querySelector('.cs'); if(!el){el=document.createElement('div');el.className='cs';el.style.cssText='position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,.8);color:#fff;font-size:10px;padding:4px 7px;text-align:center;line-height:1.5;z-index:5;border-radius:0 0 var(--r) var(--r)';c.appendChild(el);} el.style.color=isErr?'#ff6584':'#cfc'; el.textContent=msg; } async function fetchImgBlob(url, ms=90000){ const ctrl=new AbortController(); const tid=setTimeout(()=>ctrl.abort(),ms); try{ const r=await fetch(url,{signal:ctrl.signal}); clearTimeout(tid); if(r.status===429){const ra=parseInt(r.headers.get('Retry-After')||'20');throw Object.assign(new Error('429'),{status:429,wait:ra});} if(!r.ok) throw Object.assign(new Error('HTTP '+r.status),{status:r.status}); const b=await r.blob(); if(!b.type.startsWith('image/')) throw new Error('No es imagen'); return URL.createObjectURL(b); }catch(e){ clearTimeout(tid); if(e.name==='AbortError') throw Object.assign(new Error('Timeout'),{status:0}); throw e; } } // Pollinations with retry — handles 429 and 500 async function genFlux(prompt, variation, cardId=''){ const sizes={tiktok:{w:768,h:1024},youtube:{w:1024,h:576},instagram:{w:1024,h:1024},original:{w:768,h:1024}}; const{w,h}=sizes[S_exportFormat]||sizes.tiktok; const lbls=['Principal','Alternativa','Variación A','Variación B','Extra A','Extra B']; const lbl=lbls[variation]||'V'+(variation+1); const seed=(Date.now()%99999)+variation*1337; const p=encodeURIComponent((prompt+', cinematic, dramatic lighting').substring(0,400)); const url=`https://image.pollinations.ai/prompt/${p}?width=${w}&height=${h}&seed=${seed}&model=flux`; for(let attempt=0;attempt<4;attempt++){ try{ if(cardId) setCardStatus(cardId, attempt===0?'📷 Generando…':`🔄 Reintento ${attempt}/3…`); const blobUrl=await fetchImgBlob(url,90000); if(cardId) setCardStatus(cardId,'✓ Lista'); return{url:blobUrl,lbl}; }catch(e){ const wait=e.status===429?(e.wait||20):e.status===500||e.status===0?10*(attempt+1):0; if(wait===0) break; // non-retryable if(cardId) setCardStatus(cardId,`⏳ ${e.status===429?'Rate limit':'Servidor'} — ${wait}s…`); setStatus(`⏳ Pollinations: esperando ${wait}s…`); await new Promise(r=>setTimeout(r,wait*1000)); } } // Last resort: try a different seed/variant try{ if(cardId) setCardStatus(cardId,'🔄 Último intento…'); const altSeed=Math.floor(Math.random()*99999); const altUrl=`https://image.pollinations.ai/prompt/${p}?width=${w}&height=${h}&seed=${altSeed}&model=flux`; const blobUrl=await fetchImgBlob(altUrl,120000); if(cardId) setCardStatus(cardId,'✓ Lista'); return{url:blobUrl,lbl}; }catch(e){ if(cardId) setCardStatus(cardId,'❌ Sin imagen',true); throw new Error('Pollinations no responde. Intenta en unos minutos.'); } }