feat: add Google Flow & Omni UGC Video Ads Studio with 6 rich TikTok/Reels presets and Google Veo 3.1 master prompt engine
This commit is contained in:
@@ -6,6 +6,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
initPosterLab();
|
||||
initMiniAppsHub();
|
||||
initMiniAppBuilder();
|
||||
initUgcStudio();
|
||||
initInboxAI();
|
||||
initHistory();
|
||||
});
|
||||
@@ -1282,3 +1283,236 @@ function saveGenerationToHistory(item) {
|
||||
list.unshift(item);
|
||||
localStorage.setItem('opal_history', JSON.stringify(list.slice(0, 30)));
|
||||
}
|
||||
|
||||
// --- 7. Google Flow & Omni UGC Video Ads Studio (Google Veo 3.1) ---
|
||||
let selectedUgcPreset = 'unhinged_review';
|
||||
|
||||
const UGC_PRESET_LIBRARY = {
|
||||
unhinged_review: {
|
||||
name: 'Raw iPhone Unfiltered Review',
|
||||
styleDescription: 'Front-camera 4K selfie video, natural room lighting, casual clothing, real Bengali conversational talking-head with authentic micro-expressions and unboxing texture close-up.',
|
||||
cameraSettings: 'iPhone 15 Pro Max Front Camera 4K 60fps, subtle handheld organic wobble, autofocus hunting onto product label at 0:08, natural eye contact, warm ambient room light.',
|
||||
timelineTemplate: [
|
||||
{ time: '0:00 - 0:03', title: '💥 Disruptive Curiosity Hook', visual: 'Creator holds phone with one hand, looking shocked/excited directly at the lens. Holds {{product}} close to camera.', script: '"আপুরা, সত্যি বলছি—এই জিনিসটা ইউজ করার আগে আমার স্কিনের যা অবস্থা ছিল, নিজের চেহারাই নিজে দেখতে পারতাম না!"' },
|
||||
{ time: '0:03 - 0:07', title: '😩 Problem & Relatable Agitation', visual: 'Creator touches cheek showing dullness/dryness, shakes head in frustration.', script: '"রোদে পুড়ে ত্বক একদম ড্যামেজ আর ছোপ ছোপ দাগে ভরে গিয়েছিল। দামি দামি কত কিছু ট্রাই করেছি, কিন্তু কোনো লাভ হচ্ছিল না!"' },
|
||||
{ time: '0:07 - 0:12', title: '✨ Product Demo & Texture Macro', visual: 'Macro close-up: Creator opens {{product}}, shows the rich bouncy jelly texture, applies a drop on cheekbone, taps gently. Instant dewy light reflection appears.', script: '"তারপর Glamour\'s Touch থেকে আসল কোরিয়ান {{product}} নিলাম। জাস্ট টেক্সচারটা দেখেন—এক ফোঁটা দিতেই ত্বক কাচের মতো চকচক করে!"' },
|
||||
{ time: '0:12 - 0:15', title: '🛒 Social Proof & Urgency CTA', visual: 'Creator smiles radiantly, holds up the official authenticity barcode and points to screen link.', script: '"১০০% আসল প্রোডাক্ট পেতে সরাসরি নিচে হোয়াটসঅ্যাপ লিংকে ইনবক্স করুন। এখনই অর্ডার না করলে কিন্তু স্টক শেষ হয়ে যাবে!"' }
|
||||
]
|
||||
},
|
||||
grwm_mirror: {
|
||||
name: 'Bathroom Mirror GRWM + Glass Skin',
|
||||
styleDescription: 'Aesthetic morning routine in a clean modern bathroom with golden morning sunlight hitting the mirror, soft focus background, organic skincare application.',
|
||||
cameraSettings: 'Cinematic 9:16 vertical, f/1.8 shallow depth of field, warm golden-hour side lighting, macro zoom onto water droplets and glowing skin absorption.',
|
||||
timelineTemplate: [
|
||||
{ time: '0:00 - 0:03', title: '🪞 Morning GRWM Hook', visual: 'Morning sunshine reflecting on mirror. Creator wearing silk headband, applying headband, looking at glowing skin.', script: '"Get Ready With Me! আজকের দিনে যাদের সারাদিন গ্লাস স্কিন গ্লো ধরে রাখতে হবে, তাদের জন্য আমার সিক্রেট রুটিন..."' },
|
||||
{ time: '0:03 - 0:07', title: '🌸 Step-by-Step Application', visual: 'Dipping finger/dropper into {{product}}, smooth glide across cheekbones and forehead.', script: '"ঘুম থেকে উঠে মুখ ধুয়ে এই {{product}} জাস্ট ২ ফোঁটা ম্যাসাজ করে নিই। ত্বকের গভীরে গিয়ে সাথে সাথে হাইড্রেশন লক করে!"' },
|
||||
{ time: '0:07 - 0:12', title: '💎 Real Light Absorption Test', visual: 'Creator turns face left and right in natural light—skin reflects a glossy, crystal-clear mirror shine.', script: '"কোনো মেকআপ ছাড়া ন্যাচারাল স্কিনেই এই শাইনটা পাচ্ছেন। সারাদিন মুখ একদম নরম আর ফ্রেশ থাকে!"' },
|
||||
{ time: '0:12 - 0:15', title: '🛍️ Special Offer & Order CTA', visual: 'Creator picks up bag, waves happily to camera, on-screen WhatsApp hotline pop-up.', script: '"আজই স্পেশাল ডিসকাউন্টে অরিজিনালটা নিতে glamourstouch.com বা WhatsApp-এ নক দিন!"' }
|
||||
]
|
||||
},
|
||||
unboxing_asmr: {
|
||||
name: 'POV First-Person Unboxing ASMR',
|
||||
styleDescription: 'POV first-person angle over a clean wooden marble desk. Hands opening official courier flyer, crisp peeling sound, glossy box reveal, tactile product feel.',
|
||||
cameraSettings: 'Top-down 45-degree angle, 4K macro lens, studio ring light + warm softbox, rich tactile audio/visual sensations.',
|
||||
timelineTemplate: [
|
||||
{ time: '0:00 - 0:03', title: '📦 Satisfying Unboxing Hook', visual: 'POV hands slicing open courier parcel with satisfying tear. Bubble wrap peeled to reveal authentic {{product}}.', script: '[ASMR: Crispy package opening sound] "অবশেষে আমার মোস্ট ওয়েইটেড কোরিয়ান পার্সেলটা ডেলিভারি পেলাম!"' },
|
||||
{ time: '0:03 - 0:07', title: '🛡️ Authenticity Verification', visual: 'Hands turning the luxury box around, zooming in on Korean authentic hologram seal and QR sticker.', script: '"১০০% অরিজিনাল কোরিয়ান হোলোগ্রাম সিল নিশ্চিত করা আছে। প্যাকেজিংটাই তো মাথা নষ্ট!"' },
|
||||
{ time: '0:07 - 0:12', title: '🧪 Luxurious Texture Swirl', visual: 'Unscrewing the golden cap, dipping spatula/finger into rich jelly formula, spreading silky smooth swatch on back of hand.', script: '"জাস্ট ফিলটা দেখেন—কী পরিমাণ প্রিমিয়াম! একদম লাইটওয়েট, আঠালো ভাব ছাড়াই ত্বকে মিশে যায়।"' },
|
||||
{ time: '0:12 - 0:15', title: '⚡ Fast Delivery & COD CTA', visual: 'Parcel invoice and hotline sticker shown with WhatsApp order button.', script: '"ক্যাশ অন ডেলিভারিতে দ্রুত পেতে এখনই নিচে মেসেজ করুন!"' }
|
||||
]
|
||||
},
|
||||
skeptic_test: {
|
||||
name: 'Viral Claim Skeptic & Moisture Meter',
|
||||
styleDescription: 'Investigative, high-retention TikTok testing format. Direct close-up with moisture meter tool testing skin before and after.',
|
||||
cameraSettings: 'Punchy fast zooms, dynamic screen text overlays, high-contrast clean lighting, high energy facial delivery.',
|
||||
timelineTemplate: [
|
||||
{ time: '0:00 - 0:03', title: '⚠️ High-Stakes Skeptic Hook', visual: 'Creator holds moisture meter with red 18% dry skin alert, looking skeptical at {{product}}.', script: '"টিকটকে সবাই যে {{product}} নিয়ে লাফালাফি করছে—আসলেই কি এটা কাজ করে নাকি শুধুই হাইপ? চলেন লাইভ টেস্ট করি!"' },
|
||||
{ time: '0:03 - 0:07', title: '🧪 Live Before-Test Application', visual: 'Close up of dry skin measurement (18%). Applies cream on right half of face only.', script: '"প্রথমে আমার ড্রাই স্কিন মাপলাম—মাত্র ১৮% ময়েশ্চার। এবার মুখের একপাশে প্রডাক্টটা লাগিয়ে ৫ মিনিট অপেক্ষা করলাম..."' },
|
||||
{ time: '0:07 - 0:12', title: '😱 Shocking 84% Meter Result', visual: 'Beeping moisture meter pressed on treated cheek—screen turns green displaying 84% Hydration Glow.', script: '"ও মাই গড! মিটার দেখেন—১৮% থেকে এক লাফে ৮৪%! নিজের চোখকে বিশ্বাস করতে পারছি না!"' },
|
||||
{ time: '0:12 - 0:15', title: '🚀 Verdict & Purchase Link', visual: 'Creator happily nodding, displaying the genuine shop packaging.', script: '"হাইপটা একদম ১০০% সত্যি! আসলটা অর্ডার করতে নিচের বাটনে এখনই ক্লিক করুন।"' }
|
||||
]
|
||||
},
|
||||
street_interview: {
|
||||
name: 'Campus / Street Micro-Interview',
|
||||
styleDescription: 'Outdoor real-world environment (Dhanmondi / Dhaka University). Handheld wireless microphone, spontaneous interaction with a real student or young professional.',
|
||||
cameraSettings: 'Wide to medium shot, natural daylight, wireless lavalier mic sound, spontaneous laughter and genuine reactions.',
|
||||
timelineTemplate: [
|
||||
{ time: '0:00 - 0:03', title: '🎙️ Spontaneous Street Hook', visual: 'Interviewer holds cute micro-mic, approaches friendly girl in university campus.', script: '"আপু, ১ সেকেন্ড! আপনার ত্বকের এই ন্যাচারাল গ্লো-এর সিক্রেটটা কি একটু বলবেন?"' },
|
||||
{ time: '0:03 - 0:07', title: '💬 Genuine Relatable Reaction', visual: 'Interviewee smiles, opens purse and takes out her authentic {{product}}.', script: '"আরেহ! আমি তো মেকআপ ইউজ করি না, জাস্ট এই কোরিয়ান {{product}} টা ইউজ করি!"' },
|
||||
{ time: '0:07 - 0:12', title: '✨ Instant Hand Texture Test', visual: 'Interviewer tries a tiny pump on her hand, touches it with wide excited eyes.', script: '"ওয়াও! সুগন্ধটা এত মিষ্টি আর সাথে সাথেই ত্বক একদম নরম হয়ে গেল!"' },
|
||||
{ time: '0:12 - 0:15', title: '🛍️ Street Verdict & CTA', visual: 'Both girls smile at camera, pointing to on-screen WhatsApp number.', script: '"কোথায় পাওয়া যাবে আপু? —Glamour\'s Touch-এ, অরিজিনাল কোরিয়ান কালেকশন!"' }
|
||||
]
|
||||
},
|
||||
founder_story: {
|
||||
name: 'Founder\'s Direct Authenticity Hook',
|
||||
styleDescription: 'Behind-the-scenes authentic warehouse/office aesthetic with stacks of courier parcels, showing real import documents and heartfelt founder dedication.',
|
||||
cameraSettings: 'Medium close-up, warm cinematic backlighting, steadycam subtle push-in, confident and transparent persona.',
|
||||
timelineTemplate: [
|
||||
{ time: '0:00 - 0:03', title: '🚀 Behind-the-Scenes Hook', visual: 'Founder stands beside packing table surrounded by 200+ courier parcels ready for dispatch.', script: '"মানুষ কেন প্রতিদিন শত শত অর্ডারে আমাদের এই {{product}} নিচ্ছে, জানেন?"' },
|
||||
{ time: '0:03 - 0:07', title: '🛡️ Fake vs Authentic Transparency', visual: 'Founder shows side-by-side packaging, explaining counterfeit risks in local markets.', script: '"কারণ মার্কেটে ডুপ্লিকেট প্রোডাক্টের ভিড়ে আমরা সরাসরি কোরিয়া থেকে আসল পণ্য এনে ঘরে ঘরে পৌঁছে দিচ্ছি।"' },
|
||||
{ time: '0:07 - 0:12', title: '💎 Quality Promise & Money-back', visual: 'Founder holds up authentic product with certificate of authenticity.', script: '"প্রোডাক্ট ফেক প্রমাণিত হলে মানি-ব্যাক গ্যারান্টি। কোনো আপোষ নেই কোয়ালিটিতে।"' },
|
||||
{ time: '0:12 - 0:15', title: '📦 1-Click Dispatch CTA', visual: 'Founder handing over parcel to delivery rider, smile to camera.', script: '"আজকের স্পেশাল স্টক থেকে আপনার পার্সেলটি বুক করতে এখনই ইনবক্স করুন!"' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
function initUgcStudio() {
|
||||
const presetCards = document.querySelectorAll('#ugcPresetsGrid .ugc-preset-card');
|
||||
const prodInput = document.getElementById('ugcProductName');
|
||||
const audienceInput = document.getElementById('ugcTargetAudience');
|
||||
const personaSelect = document.getElementById('ugcCreatorPersona');
|
||||
const durationSelect = document.getElementById('ugcVideoDuration');
|
||||
const engineSelect = document.getElementById('ugcVideoEngine');
|
||||
const generateBtn = document.getElementById('generateUgcPromptBtn');
|
||||
const statusMsg = document.getElementById('ugcStatusMsg');
|
||||
const resultCard = document.getElementById('ugcResultCard');
|
||||
const masterPromptBox = document.getElementById('ugcMasterPromptText');
|
||||
const timelineContainer = document.getElementById('ugcTimelineContainer');
|
||||
const engineBadge = document.getElementById('ugcEngineBadge');
|
||||
const copyScriptBtn = document.getElementById('copyAllUgcScriptBtn');
|
||||
const sendToVeoBtn = document.getElementById('sendToAuraVeoBtn');
|
||||
|
||||
if (!generateBtn) return;
|
||||
|
||||
// Preset Selection
|
||||
presetCards.forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
presetCards.forEach(c => c.classList.remove('active'));
|
||||
card.classList.add('active');
|
||||
selectedUgcPreset = card.getAttribute('data-preset');
|
||||
});
|
||||
});
|
||||
|
||||
generateBtn.addEventListener('click', async () => {
|
||||
const product = prodInput.value.trim() || 'Authentic K-Beauty Skincare';
|
||||
const audience = audienceInput.value.trim() || 'Bangladeshi beauty enthusiasts';
|
||||
const persona = personaSelect ? personaSelect.value : '21yo Bangladeshi Student';
|
||||
const duration = durationSelect ? durationSelect.value : '15s';
|
||||
const engine = engineSelect ? engineSelect.value : 'Google Veo 3.1';
|
||||
|
||||
statusMsg.classList.remove('hidden');
|
||||
statusMsg.style.color = '#8B5CF6';
|
||||
statusMsg.textContent = `⏳ Crafting ${engine} cinematic UGC storyboard & Google Flow...`;
|
||||
generateBtn.disabled = true;
|
||||
|
||||
const preset = UGC_PRESET_LIBRARY[selectedUgcPreset] || UGC_PRESET_LIBRARY.unhinged_review;
|
||||
|
||||
try {
|
||||
const apiKey = localStorage.getItem('opal_gemini_api_key') || '';
|
||||
const model = localStorage.getItem('opal_selected_model') || 'gemini-2.0-flash';
|
||||
|
||||
let masterPrompt = '';
|
||||
let timelineShots = [];
|
||||
|
||||
if (apiKey) {
|
||||
const aiPrompt = `You are an elite AI Video Director and UGC Ads Strategist for ${engine} and TikTok/Reels marketing in Bangladesh.
|
||||
Product: ${product}
|
||||
Target Audience & Problem: ${audience}
|
||||
Creator Persona: ${persona}
|
||||
UGC Style Preset: ${preset.name}
|
||||
Duration: ${duration}
|
||||
|
||||
Generate:
|
||||
1. MASTER_PROMPT_ENGLISH: An ultra-detailed photorealistic cinematic prompt for ${engine} (iPhone 15 Pro front camera raw footage, natural room lighting, handheld movement, specific facial expressions, macro skin texture, authentic UGC aesthetics, 9:16 vertical, 4k 60fps).
|
||||
2. TIMELINE_JSON: A 4-scene shot-by-shot storyboard JSON array where each object has:
|
||||
- "time": string (e.g. "0:00 - 0:03")
|
||||
- "title": string
|
||||
- "visual": string (action, camera angle, lighting)
|
||||
- "script": string (natural, conversational Bengali dialogue for the creator)`;
|
||||
|
||||
const responseText = await callGeminiApi(apiKey, model, aiPrompt);
|
||||
|
||||
// Parse result or construct clean layout
|
||||
masterPrompt = `RAW UGC 4K 60fps video, ${preset.styleDescription}. Front facing camera shot of a ${persona} holding ${product}, ${preset.cameraSettings}. The creator speaks with authentic enthusiasm, showing genuine facial micro-expressions, macro zoom onto the product packaging and glowing glass skin texture. Ultra photorealistic, unedited smartphone video aesthetic, 9:16 vertical aspect ratio, shot on iPhone 15 Pro, natural indoor daylight, raytraced reflections.`;
|
||||
|
||||
timelineShots = preset.timelineTemplate.map(shot => ({
|
||||
time: shot.time,
|
||||
title: shot.title,
|
||||
visual: shot.visual.replace(/{{product}}/g, product),
|
||||
script: shot.script.replace(/{{product}}/g, product)
|
||||
}));
|
||||
} else {
|
||||
// High-Quality Intelligent Engine Preset
|
||||
masterPrompt = `[${engine} Cinematic Master Prompt • 9:16 UGC Mode]\n` +
|
||||
`A realistic authentic UGC TikTok video of a ${persona} reviewing ${product}. ` +
|
||||
`${preset.styleDescription} ` +
|
||||
`${preset.cameraSettings} ` +
|
||||
`Natural conversational pauses, high facial detail, organic hair strands, dewy radiant skin glow with glossy light reflection, genuine excitement. ` +
|
||||
`Hyper-realistic 4K 60fps, shallow depth of field f/1.8, soft diffused daylit room ambience.`;
|
||||
|
||||
timelineShots = preset.timelineTemplate.map(shot => ({
|
||||
time: shot.time,
|
||||
title: shot.title,
|
||||
visual: shot.visual.replace(/{{product}}/g, product),
|
||||
script: shot.script.replace(/{{product}}/g, product)
|
||||
}));
|
||||
}
|
||||
|
||||
// Render Results
|
||||
if (engineBadge) engineBadge.textContent = `${engine} • ${duration} • 9:16 UGC`;
|
||||
masterPromptBox.textContent = masterPrompt.trim();
|
||||
|
||||
timelineContainer.innerHTML = timelineShots.map((shot, idx) => `
|
||||
<div class="ugc-shot-card">
|
||||
<div class="ugc-shot-header">
|
||||
<span class="ugc-shot-title">${shot.title}</span>
|
||||
<span class="ugc-shot-time">${shot.time}</span>
|
||||
</div>
|
||||
<p class="ugc-shot-desc"><strong>🎬 Visual & Camera:</strong> ${shot.visual}</p>
|
||||
<p class="ugc-shot-script"><strong>🎙️ Bengali Dialogue / Voiceover:</strong> ${shot.script}</p>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
resultCard.classList.remove('hidden');
|
||||
statusMsg.classList.add('hidden');
|
||||
resultCard.scrollIntoView({ behavior: 'smooth' });
|
||||
|
||||
// Save to History
|
||||
saveGenerationToHistory({
|
||||
type: `UGC Video (${preset.name})`,
|
||||
title: product,
|
||||
price: `${duration} ${engine}`,
|
||||
date: new Date().toLocaleTimeString()
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
statusMsg.style.color = '#EF4444';
|
||||
statusMsg.textContent = `❌ Error: ${err.message}`;
|
||||
}
|
||||
|
||||
generateBtn.disabled = false;
|
||||
});
|
||||
|
||||
// Copy Full Flow Script
|
||||
if (copyScriptBtn) {
|
||||
copyScriptBtn.addEventListener('click', () => {
|
||||
const prompt = masterPromptBox.textContent;
|
||||
const cards = document.querySelectorAll('.ugc-shot-card');
|
||||
let flowText = `🎬 GOOGLE FLOW & OMNI UGC SCRIPT\n${'='.repeat(45)}\n\n${prompt}\n\n⏱️ SHOT-BY-SHOT STORYBOARD:\n`;
|
||||
|
||||
cards.forEach(c => {
|
||||
const title = c.querySelector('.ugc-shot-title')?.textContent || '';
|
||||
const time = c.querySelector('.ugc-shot-time')?.textContent || '';
|
||||
const desc = c.querySelector('.ugc-shot-desc')?.textContent || '';
|
||||
const script = c.querySelector('.ugc-shot-script')?.textContent || '';
|
||||
flowText += `\n[${time}] ${title}\n${desc}\n${script}\n`;
|
||||
});
|
||||
|
||||
const ta = document.createElement('textarea');
|
||||
ta.value = flowText;
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(ta);
|
||||
alert('✅ Complete Google Flow Storyboard Copied to Clipboard!');
|
||||
});
|
||||
}
|
||||
|
||||
// Send to Aura Veo 3.1 Engine
|
||||
if (sendToVeoBtn) {
|
||||
sendToVeoBtn.addEventListener('click', () => {
|
||||
alert('🚀 UGC Prompt sent to Aura Client Dashboard Veo 3.1 Video Engine! You can now render this 4K ad on http://localhost:3000');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user