Files
opal-ios-studio/app.js
T

1745 lines
89 KiB
JavaScript

// Google Opal AI - Master Mini-App Studio & 3D Poster Lab Engine v5.0
document.addEventListener('DOMContentLoaded', () => {
initNavigation();
initSettings();
initPosterLab();
initMiniAppsHub();
initMiniAppBuilder();
initUgcStudio();
initInboxAI();
initHistory();
});
// --- Global Navigation ---
window.switchToTab = function(tabId) {
const navItems = document.querySelectorAll('.nav-item');
const tabPages = document.querySelectorAll('.tab-page');
navItems.forEach(n => {
if (n.getAttribute('data-tab') === tabId) {
n.classList.add('active');
} else {
n.classList.remove('active');
}
});
tabPages.forEach(p => {
if (p.id === tabId) {
p.classList.add('active');
} else {
p.classList.remove('active');
}
});
window.scrollTo({ top: 0, behavior: 'smooth' });
};
function initNavigation() {
const navItems = document.querySelectorAll('.nav-item');
navItems.forEach(item => {
item.addEventListener('click', () => {
const targetTabId = item.getAttribute('data-tab');
switchToTab(targetTabId);
});
});
// Language Toggle
const langBtn = document.getElementById('langToggleBtn');
let currentLang = 'BN';
if (langBtn) {
langBtn.addEventListener('click', () => {
currentLang = currentLang === 'BN' ? 'EN' : 'BN';
langBtn.textContent = currentLang === 'BN' ? '🌐 বাং' : '🌐 EN';
});
}
}
window.copyText = function(elementId) {
const el = document.getElementById(elementId);
if (el) {
const text = el.value || el.textContent || '';
navigator.clipboard.writeText(text).then(() => {
alert('✅ Copied to Clipboard!');
}).catch(() => {
// Fallback
const ta = document.createElement('textarea');
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
alert('✅ Copied to Clipboard!');
});
}
};
// --- Settings & Gemini 2.0 API Engine ---
function initSettings() {
const apiKeyInput = document.getElementById('apiKeyInput');
const modelSelect = document.getElementById('modelSelect');
const n8nWebhookInput = document.getElementById('n8nWebhookInput');
const saveBtn = document.getElementById('saveApiKeyBtn');
const statusMsg = document.getElementById('settingsStatusMsg');
// Load saved settings
const savedKey = localStorage.getItem('opal_gemini_api_key') || '';
const savedModel = localStorage.getItem('opal_selected_model') || 'gemini-2.0-flash';
const savedN8n = localStorage.getItem('opal_n8n_webhook') || 'https://n8n.auraajenticai.cloud/webhook/gt-auto-post';
if (apiKeyInput) apiKeyInput.value = savedKey;
if (modelSelect) modelSelect.value = savedModel;
if (n8nWebhookInput) n8nWebhookInput.value = savedN8n;
if (saveBtn) {
saveBtn.addEventListener('click', async () => {
const key = apiKeyInput.value.trim();
const model = modelSelect.value;
const n8nUrl = n8nWebhookInput ? n8nWebhookInput.value.trim() : '';
if (n8nUrl) {
localStorage.setItem('opal_n8n_webhook', n8nUrl);
}
if (!key) {
localStorage.setItem('opal_selected_model', model);
statusMsg.classList.remove('hidden');
statusMsg.style.color = '#10B981';
statusMsg.textContent = '✅ Settings saved (Offline templates active).';
return;
}
statusMsg.classList.remove('hidden');
statusMsg.style.color = '#F472B6';
statusMsg.textContent = '⏳ Testing Gemini 2.0 AI connection with Google...';
try {
const res = await callGeminiApi(key, model, "Respond with: 'Google Opal AI Connected successfully!'");
if (res) {
localStorage.setItem('opal_gemini_api_key', key);
localStorage.setItem('opal_selected_model', model);
statusMsg.style.color = '#10B981';
statusMsg.textContent = `✅ Verified & Active: ${res.trim()}`;
}
} catch (e) {
statusMsg.style.color = '#EF4444';
statusMsg.textContent = `❌ Connection Error: ${e.message}`;
}
});
}
}
async function callGeminiApi(apiKey, model, prompt) {
const activeModel = model || localStorage.getItem('opal_selected_model') || 'gemini-2.0-flash';
const url = `https://generativelanguage.googleapis.com/v1beta/models/${activeModel}:generateContent?key=${apiKey}`;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: { temperature: 0.7, maxOutputTokens: 2048 }
};
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) {
const errData = await response.json().catch(() => ({}));
throw new Error(errData?.error?.message || `HTTP ${response.status}`);
}
const data = await response.json();
return data?.candidates?.[0]?.content?.parts?.[0]?.text || '';
}
// --- Curated Pre-Built Mini-Apps Suite (Universal E-Commerce) ---
const PREBUILT_MINI_APPS = [
{
id: 'gt_studio',
name: '3D Commercial Poster Lab',
emoji: '🎨',
category: 'ecommerce',
badge: '3D CANVAS',
desc: 'যেকোনো পণ্যের ছবি, ৩ডি মার্বেল স্টেজ ও WhatsApp QR সহ 4K বিজ্ঞাপন পোস্টার তৈরি করে।',
steps: 'All Niches • 3D Canvas',
isPosterLab: true
},
{
id: 'fashion_stylist',
name: 'Fashion, Saree & Panjabi Styling Closer',
emoji: '👗',
category: 'fashion',
badge: 'FASHION',
desc: 'শাড়ি, থ্রি-পিস, পাঞ্জাবি বা হুডির ফেব্রিক ডিটেইলস, সাইজ গাইড ও ম্যাচিং টিপস দিয়ে সেলস ক্লোজ করে।',
steps: '3 Steps • Fashion Closer',
fields: [
{ id: 'field1', label: 'পোশাকের নাম ও ফেব্রিক (Dress / Saree & Fabric)', placeholder: 'e.g. প্রিমিয়াম মসলিন জামদানি শাড়ি অথবা প্রিমিয়াম কটন পাঞ্জাবি' },
{ id: 'field2', label: 'সাইজ, কালার ও অফার (Size / Color / Offer)', placeholder: 'e.g. সাইজ M, L, XL | কালার: মেরুন | অফার মূল্য: ৳ ২,৪৫০ (ফ্রি ডেলিভারি)' }
],
promptTemplate: `You are an elite Bangladeshi Fashion Stylist and High-Converting Sales Closer.
Item & Fabric: {{field1}}
Details & Offer: {{field2}}
Write 3 distinct ready-to-send Bengali fashion customer responses:
1. Aesthetic luxury product appreciation highlighting fabric softness, elegant drape, and premium feel.
2. Complete size guidance and direct order closure asking for delivery address and phone number.
3. 1-Click WhatsApp booking link: https://wa.me/8801712426871 with cash-on-delivery trial assurance.`
},
{
id: 'panjabi_closer',
name: 'Royal Panjabi & Kabli Styling Studio',
emoji: '👑',
category: 'fashion',
badge: 'ROYAL PANJABI',
desc: 'প্রিমিয়াম ডিজাইনার পাঞ্জাবি, কাবলি সেট ও কাতান/সিল্কের ফেব্রিক ডিটেইলস, সাইজ গাইড ও অকেশনের সেলস ক্লোজ করে।',
steps: '3 Steps • Panjabi Closer',
fields: [
{ id: 'field1', label: 'পাঞ্জাবি বা কাবলির নাম ও ফেব্রিক (Panjabi Style & Fabric)', placeholder: 'e.g. Aura Royal Hand-Embroidered Cotton Panjabi / Semi-Silk Kabli Suit' },
{ id: 'field2', label: 'সাইজ চার্ট ও স্পেশাল অফার (Size Chart & Discount Offer)', placeholder: 'e.g. সাইজ: ৪০, ৪২, ৪৪, ৪৬ | স্ন্যাপ বাটন | অফার মূল্য: ৳ ১,৮৫০ (রেগুলার ৳ ২,৪০০)' }
],
promptTemplate: `You are an elite Royal Ethnic Fashion Stylist and Panjabi Sales Specialist for Aura Heritage in Bangladesh.
Item & Fabric: {{field1}}
Details & Offer: {{field2}}
Write 3 distinct high-converting, courteous Bengali responses:
1. Royal aesthetic appreciation highlighting fine thread embroidery, pre-shrunk premium cotton/silk comfort, and festive elegance.
2. Accurate size guidance (chest & length fit) with doorstep size trial assurance.
3. 1-Click WhatsApp booking link: https://wa.me/8801712426871 with cash on delivery across Bangladesh.`
},
{
id: 'gadget_explainer',
name: 'Smart Gadget & Electronics Feature Explainer',
emoji: '⚡',
category: 'electronics',
badge: 'GADGETS',
desc: 'স্মার্টওয়াচ, ইয়ারবাডস ও গ্যাজেটের ব্যাটারি লাইফ, ডিসপ্লে ও ১ বছরের ওয়ারেন্টি বুঝিয়ে সেলস আনে।',
steps: '3 Steps • Tech Sales',
fields: [
{ id: 'field1', label: 'গ্যাজেটের নাম ও মডেল (Gadget Name & Model)', placeholder: 'e.g. Ultra 9 Max Smartwatch AMOLED Display' },
{ id: 'field2', label: 'ফিচার ও ওয়ারেন্টি অফার (Specs & Warranty)', placeholder: 'e.g. ৭ দিনের ব্যাটারি, ওয়াটারপ্রুফ IP68, ১ বছর রিপ্লেসমেন্ট ওয়ারেন্টি, দাম ৳ ২,৩৫০' }
],
promptTemplate: `You are a tech-savvy gadget sales expert in Bangladesh.
Gadget Model: {{field1}}
Specs & Offer: {{field2}}
Generate 3 high-trust Bengali customer responses:
1. Power-packed feature breakdown (battery, AMOLED screen, sound quality, water resistance).
2. Official warranty guarantee & risk-free Cash on Delivery verification guide.
3. Fast 1-Click WhatsApp purchase link: https://wa.me/8801712426871.`
},
{
id: 'organic_honey_lab',
name: 'Pure Organic Food & Honey Authenticity AI',
emoji: '🍯',
category: 'organic',
badge: 'ORGANIC',
desc: 'সুন্দরবনের খাঁটি মধু, সরিষার তেল ও ঘিয়ের ১০০% নির্ভেজাল প্রমাণ ও স্বাস্থ্য উপকারিতা জানায়।',
steps: '3 Steps • Pure Food',
fields: [
{ id: 'field1', label: 'পণ্যের নাম ও উৎস (Organic Food & Source)', placeholder: 'e.g. সুন্দরবনের প্রাকৃতিক চাকের খাঁটি মধু (১ কেজি)' },
{ id: 'field2', label: 'উপকারিতা ও মূল্য (Benefits & Price)', placeholder: 'e.g. ১০০% ল্যাব টেস্টেড, রোগ প্রতিরোধ ক্ষমতা বাড়ায়, দাম ৳ ১,২০০' }
],
promptTemplate: `You are a trusted organic food & wellness advisor in Bangladesh.
Product: {{field1}}
Benefits & Price: {{field2}}
Write 3 persuasive, trust-building Bengali customer messages:
1. Purity assurance (lab-tested, unadulterated, raw natural honey/ghee taste).
2. Health & wellness benefits for family/children.
3. Cash-on-Delivery order confirmation with tasting guarantee upon courier arrival.`
},
{
id: 'sneaker_style_hub',
name: 'Sneaker Legit Check & Footwear Closer',
emoji: '👟',
category: 'footwear',
badge: 'SNEAKERS',
desc: 'স্নিকার, লোফার ও চামড়ার জুতার প্রিমিয়াম কোয়ালিটি, কুশন কমফোর্ট ও সাইজ ট্রায়াল বুঝায়।',
steps: '3 Steps • Footwear',
fields: [
{ id: 'field1', label: 'জুতার নাম ও মেটেরিয়াল (Shoe / Sneaker Model)', placeholder: 'e.g. Air Jordan Retro High OG / Pure Cow Leather Loafer' },
{ id: 'field2', label: 'সাইজ ও অফার মূল্য (Size Chart & Offer)', placeholder: 'e.g. সাইজ ৩৯ থেকে ৪৪ | মেমোরি ফোম ইনসোল | দাম ৳ ২,৮৫০' }
],
promptTemplate: `You are a street-style sneakerhead and footwear closer in Bangladesh.
Model: {{field1}}
Details: {{field2}}
Create 3 urban, stylish Bengali customer messages:
1. Comfort, sole durability, and stylish outfit pairing tips.
2. Hassle-free size exchange guarantee with cash on delivery.
3. Fast WhatsApp order link with doorstep fitting check.`
},
{
id: 'inbox_ai',
name: 'Customer Care & Universal Sales Closer',
emoji: '💬',
category: 'sales',
badge: 'AI CLOSER',
desc: 'ফেসবুক ও হোয়াটসঅ্যাপের কাস্টমারের প্রশ্নের ৩টি ইনস্ট্যান্ট মিষ্টি ও সেলস ক্লোজিং উত্তর বানায়।',
steps: '3 Steps • Sales Closer',
fields: [
{ id: 'field1', label: 'কাস্টমার মেসেজ (Customer Message)', placeholder: 'e.g. আপনাদের প্রোডাক্টের দাম কত আর ডেলিভারি চার্জ কত?' },
{ id: 'field2', label: 'দোকানের অফার বা হটলাইন (Store Context)', placeholder: 'e.g. দাম ১,৪৫০ টাকা, ঢাকা ৭০ টাকা, হটলাইন ০১৭১২-৪২৬৮৭১' }
],
promptTemplate: `You are an expert Bangladeshi e-commerce sales closer.
Customer message: {{field1}}
Store context: {{field2}}
Write 3 distinct ready-to-copy Bengali replies:
1. Instant sweet greeting with price & benefits
2. Direct order closing script asking for Name, Address, Phone
3. 1-Click WhatsApp direct order message with link https://wa.me/8801712426871`
},
{
id: 'veo_prompter',
name: 'Google Veo 3.1 & Omni Video Prompter',
emoji: '🎬',
category: 'social',
badge: 'VEO 3.1',
desc: 'সকল ক্যাটাগরির পণ্যের জন্য সিনেমাটিক 9:16 ভিডিও প্রম্পট, ক্যামেরা মোশন ও লাইটিং গাইড বানায়।',
steps: '4 Steps • AI Video',
fields: [
{ id: 'field1', label: 'প্রডাক্টের নাম ও ধরণ (Product & Category)', placeholder: 'e.g. Silk Saree / Smartwatch / Pure Honey / Face Serum' },
{ id: 'field2', label: 'ভিডিওর ভাইব ও স্টাইল (Style / Lighting)', placeholder: 'e.g. Cinematic Studio, Macro slow-mo, neon rim light, 4K raytraced' }
],
promptTemplate: `You are a world-class AI Video Prompt Engineer for Google Veo 3.1 and Sora.
Create an ultra-detailed, cinematic 9:16 vertical video prompt for:
Product: {{field1}}
Style/Vibe: {{field2}}
Include:
1. Master Cinematic Prompt (in English for AI video model)
2. Camera Movements (Macro close-up, 360 rotation, slow motion reveal)
3. Studio Lighting & Physics (Softbox, rim lighting, atmospheric particles)
4. Bengali Narration / Voiceover Script (15 seconds)`
},
{
id: 'risk_scorer',
name: 'Gemini COD Fraud & Return Risk Shield',
emoji: '🛡️',
category: 'tools',
badge: 'AI SHIELD',
desc: 'কাস্টমারের ফোন নাম্বার, ঠিকানা ও অর্ডারের পরিমাণ বিশ্লেষণ করে রিটার্ন ফ্রড রিস্ক স্কোর দেয়।',
steps: 'Real-time • Gemini 2.0',
fields: [
{ id: 'field1', label: 'কাস্টমারের ফোন নাম্বার (Phone Number)', placeholder: 'e.g. 01819998877' },
{ id: 'field2', label: 'ঠিকানা ও অর্ডারের মূল্য (Address & Amount)', placeholder: 'e.g. Mirpur 10, Dhaka - Amount: ৳ 3,200' }
],
promptTemplate: `You are an advanced e-commerce Fraud Risk Analysis Engine for Bangladesh logistics.
Phone: {{field1}}
Order Info: {{field2}}
Evaluate:
1. Risk Level: (LOW / MEDIUM / HIGH)
2. Recommendation: (Proceed with COD / Take Advance Delivery Charge ৳150 / Call to verify)
3. Short reasoning in clear Bengali.`
},
{
id: 'ecommerce_launch',
name: 'E-Commerce Viral Product Launch Kit',
emoji: '🛍️',
category: 'ecommerce',
badge: 'VIRAL',
desc: 'যেকোনো পণ্যের আকর্ষণীয় ফেসবুক পোস্ট ক্যাপশন, পেইন পয়েন্ট হুক ও অফার কপি তৈরি করে।',
steps: '5 Steps • Marketing',
fields: [
{ id: 'field1', label: 'প্রডাক্টের নাম ও ক্যাটাগরি (Product Name & Niche)', placeholder: 'e.g. Luxury Silk Saree / Wireless ANC Earbuds / Pure Honey' },
{ id: 'field2', label: 'মূল সুবিধা ও অফার (Key Benefits & Offer)', placeholder: 'e.g. প্রিমিয়াম কোয়ালিটি, ১০০% অরিজিনাল গ্যারান্টি, ২৫% ডিসকাউন্ট' }
],
promptTemplate: `You are a high-converting Facebook ad copywriter in Bangladesh.
Create a complete viral product launch post in attractive Bengali for:
Product: {{field1}}
Benefits & Offer: {{field2}}
Format:
- 3 Viral Opening Hooks (Emoji heavy)
- Problem & Solution story
- Special Limited Time Offer & Delivery Info
- Urgent Call-to-Action with WhatsApp & Website link`
},
{
id: 'tiktok_hooks',
name: 'TikTok & Meta Reels Viral Hook Matrix',
emoji: '🔥',
category: 'social',
badge: 'HOOKS',
desc: 'প্রথম ৩ সেকেন্ডে কাস্টমারের চোখ আটকে ফেলার মতো ৫টি সাইকোলজিক্যাল ভাইরাল হুক তৈরি করে।',
steps: '5 Viral Hooks • Reels',
fields: [
{ id: 'field1', label: 'প্রডাক্ট বা বিষয়ের নাম (Product / Topic)', placeholder: 'e.g. Smart Watch / Designer Saree / Organic Honey / Leather Shoe' },
{ id: 'field2', label: 'টার্গেট অডিয়েন্স (Target Audience)', placeholder: 'e.g. ফ্যাশন সচেতন তরুণ-তরুণী বা গ্যাজেট লাভার' }
],
promptTemplate: `You are a viral TikTok & Instagram Reels growth strategist.
Create 5 powerful 3-second visual + verbal hooks in Bengali for:
Product: {{field1}}
Target Audience: {{field2}}
Format each hook with:
- Visual Action (Screen text & actor action)
- Spoken Audio Hook (High curiosity / urgency)
- Psychology trigger explanation`
},
{
id: 'urgency_sales',
name: 'Flash Sale & Urgency Campaign Copywriter',
emoji: '🏷️',
category: 'sales',
badge: 'OFFER',
desc: '২৪ ঘণ্টার ফ্ল্যাশ সেল, স্টক ক্লিয়ারেন্স ও ঈদ/বৈশাখী অফারের হাই-কনভার্টিং কপি বানায়।',
steps: 'Flash Sales • Copy',
fields: [
{ id: 'field1', label: 'অফারের নাম ও ডিসকাউন্ট (Offer Details)', placeholder: 'e.g. 48 Hours Weekend Flash Sale - Flat 35% OFF' },
{ id: 'field2', label: 'শর্ত ও ফ্রি ডেলিভারি (Conditions & Perks)', placeholder: 'e.g. প্রথম ৫০ জনের জন্য ফ্রি গিফট ও ফ্রি হোম ডেলিভারি' }
],
promptTemplate: `Create an irresistible, high-urgency Flash Sale ad copy in natural Bengali for:
Campaign: {{field1}}
Perks: {{field2}}
Include FOMO triggers, countdown psychological anchors, and clear WhatsApp booking steps.`
},
{
id: 'courier_formatter',
name: 'Steadfast & Pathao Consignment Formatter',
emoji: '📦',
category: 'tools',
badge: 'LOGISTICS',
desc: 'অর্ডারের টেক্সট থেকে ১-ক্লিকে কুরিয়ার এন্ট্রি ফরম্যাট ও প্রিন্ট লেবেল তৈরি করে।',
steps: '1-Click • Logistics',
fields: [
{ id: 'field1', label: 'কাস্টমারের সম্পূর্ণ অর্ডার টেক্সট (Order Text)', placeholder: 'e.g. নাম: তানভীর হাসান, ফোন: 01712345678, ঠিকানা: বাড়ি ১২, রোড ৫, ধানমন্ডি, ঢাকা। প্রডাক্ট: ১ পিস গ্যাজেট (৳১৮৫০)' },
{ id: 'field2', label: 'ডেলিভারি চার্জ ও নোট (COD & Notes)', placeholder: 'e.g. COD Amount: ৳ 1920 (Dhaka inside ৳70)' }
],
promptTemplate: `Parse this customer order and structure it cleanly for Steadfast / Pathao Courier API and Print Packing Sticker:
Order Text: {{field1}}
COD Info: {{field2}}
Generate:
1. Structured CSV/JSON Format (Name, Phone, Address, COD, Instruction)
2. Clean Printable Packing Slip in Bengali.`
}
];
// --- Mini-Apps Hub Logic ---
let activeCategory = 'all';
function initMiniAppsHub() {
renderMiniApps();
const filterChips = document.querySelectorAll('.filter-chip');
filterChips.forEach(chip => {
chip.addEventListener('click', () => {
filterChips.forEach(c => c.classList.remove('active'));
chip.classList.add('active');
activeCategory = chip.getAttribute('data-cat');
renderMiniApps();
});
});
}
function getCustomMiniApps() {
return JSON.parse(localStorage.getItem('opal_custom_apps') || '[]');
}
function renderMiniApps() {
const container = document.getElementById('appsGridContainer');
if (!container) return;
const customApps = getCustomMiniApps();
const allApps = [...PREBUILT_MINI_APPS, ...customApps];
const filtered = activeCategory === 'all'
? allApps
: (activeCategory === 'custom' ? customApps : allApps.filter(a => a.category === activeCategory));
if (filtered.length === 0) {
container.innerHTML = `
<div class="col-span-full empty-state" style="grid-column: 1 / -1;">
<span class="icon-empty">📭</span>
<p>No mini-apps found in this category. Click "+ Create App" to build one!</p>
</div>
`;
return;
}
container.innerHTML = filtered.map(app => `
<div class="app-card">
<div class="app-card-top">
<div class="app-icon">${app.emoji || '💎'}</div>
<span class="tag-gem">${app.badge || 'CUSTOM'}</span>
</div>
<div onclick="openAppRunner('${app.id}')" style="cursor: pointer; flex: 1;">
<h3>${app.name}</h3>
<p>${app.desc || 'AI powered dynamic mini-app for client dashboard.'}</p>
</div>
<div class="app-card-footer">
<span class="meta-tag">${app.steps || 'Gemini 2.0'}</span>
<div style="display: flex; gap: 6px;">
<button class="btn-embed-chip" onclick="openEmbedModal('${app.id}')" title="Embed Code">
📦 Embed
</button>
<button class="btn-embed-chip" onclick="openAppRunner('${app.id}')" style="background: rgba(139, 92, 246, 0.2); color: #C084FC;">
⚡ Run
</button>
</div>
</div>
</div>
`).join('');
}
// --- Visual Mini-App Builder ---
function initMiniAppBuilder() {
const nameInput = document.getElementById('builderAppName');
const emojiInput = document.getElementById('builderAppEmoji');
const catSelect = document.getElementById('builderCategory');
const modelSelect = document.getElementById('builderModel');
const descInput = document.getElementById('builderDesc');
const f1Input = document.getElementById('builderField1');
const f2Input = document.getElementById('builderField2');
const templateInput = document.getElementById('builderPromptTemplate');
const saveBtn = document.getElementById('saveMiniAppBtn');
const testBtn = document.getElementById('testMiniAppBtn');
const statusMsg = document.getElementById('builderStatusMsg');
if (!saveBtn) return;
saveBtn.addEventListener('click', () => {
const name = nameInput.value.trim();
if (!name) {
alert('Please enter a Mini-App name');
return;
}
const newApp = {
id: 'custom_' + Date.now(),
name: name,
emoji: emojiInput.value.trim() || '💎',
category: catSelect.value,
model: modelSelect.value,
badge: 'CUSTOM APP',
desc: descInput.value.trim() || 'Custom client dashboard mini-app.',
steps: 'Custom • Gemini AI',
fields: [
{ id: 'field1', label: f1Input.value.trim() || 'Field 1', placeholder: 'Enter ' + (f1Input.value.trim() || 'Field 1') },
{ id: 'field2', label: f2Input.value.trim() || 'Field 2', placeholder: 'Enter ' + (f2Input.value.trim() || 'Field 2') }
],
promptTemplate: templateInput.value.trim(),
createdAt: new Date().toISOString()
};
const existing = getCustomMiniApps();
existing.unshift(newApp);
localStorage.setItem('opal_custom_apps', JSON.stringify(existing));
statusMsg.classList.remove('hidden');
statusMsg.style.color = '#10B981';
statusMsg.textContent = `🎉 Mini-App "${name}" successfully saved & added to Hub!`;
renderMiniApps();
setTimeout(() => {
switchToTab('tabApps');
statusMsg.classList.add('hidden');
}, 1200);
});
if (testBtn) {
testBtn.addEventListener('click', () => {
const name = nameInput.value.trim() || 'Test Mini-App';
const tempApp = {
id: 'test_temp',
name: name,
emoji: emojiInput.value.trim() || '🧪',
desc: descInput.value.trim() || 'Testing custom app runner',
fields: [
{ id: 'field1', label: f1Input.value.trim() || 'Field 1', placeholder: 'Input 1' },
{ id: 'field2', label: f2Input.value.trim() || 'Field 2', placeholder: 'Input 2' }
],
promptTemplate: templateInput.value.trim(),
model: modelSelect.value
};
launchRunnerWithApp(tempApp);
});
}
}
// --- Interactive Mini-App Runner (Modal) ---
let currentRunningApp = null;
window.openAppRunner = function(appId) {
if (appId === 'gt_studio') {
switchToTab('tabPosterLab');
return;
}
if (appId === 'inbox_ai') {
switchToTab('tabInboxAI');
return;
}
const allApps = [...PREBUILT_MINI_APPS, ...getCustomMiniApps()];
const app = allApps.find(a => a.id === appId);
if (!app) return;
launchRunnerWithApp(app);
};
function launchRunnerWithApp(app) {
currentRunningApp = app;
const modal = document.getElementById('appRunnerModal');
const title = document.getElementById('runnerModalTitle');
const desc = document.getElementById('runnerModalDesc');
const formBox = document.getElementById('runnerDynamicForm');
const resultBox = document.getElementById('runnerResultBox');
const statusMsg = document.getElementById('runnerStatusMsg');
title.innerHTML = `${app.emoji || '🚀'} ${app.name}`;
desc.textContent = app.desc || '';
resultBox.classList.add('hidden');
statusMsg.classList.add('hidden');
const fields = app.fields || [
{ id: 'field1', label: 'Input 1', placeholder: 'Enter details...' },
{ id: 'field2', label: 'Input 2', placeholder: 'Enter additional context...' }
];
formBox.innerHTML = fields.map((f, i) => `
<div class="form-group">
<label for="runner_${f.id}">${f.label}:</label>
<input type="text" id="runner_${f.id}" placeholder="${f.placeholder}" class="runner-input" data-var="${f.id}">
</div>
`).join('');
modal.classList.remove('hidden');
}
window.closeAppRunner = function() {
document.getElementById('appRunnerModal').classList.add('hidden');
currentRunningApp = null;
};
// Handle Mini-App Execution
document.addEventListener('DOMContentLoaded', () => {
const execBtn = document.getElementById('runnerExecuteBtn');
if (execBtn) {
execBtn.addEventListener('click', async () => {
if (!currentRunningApp) return;
const statusMsg = document.getElementById('runnerStatusMsg');
const resultBox = document.getElementById('runnerResultBox');
const resultContent = document.getElementById('runnerResultContent');
statusMsg.classList.remove('hidden');
statusMsg.style.color = '#C084FC';
statusMsg.textContent = '⏳ Processing with Google Gemini 2.0 AI...';
execBtn.disabled = true;
// Extract form values
const inputs = document.querySelectorAll('.runner-input');
let prompt = currentRunningApp.promptTemplate || 'Generate helpful response for the user.';
inputs.forEach(input => {
const varName = input.getAttribute('data-var');
const val = input.value.trim() || 'N/A';
const regex = new RegExp(`{{${varName}}}`, 'g');
prompt = prompt.replace(regex, val);
});
const apiKey = localStorage.getItem('opal_gemini_api_key') || '';
const model = currentRunningApp.model || localStorage.getItem('opal_selected_model') || 'gemini-2.0-flash';
try {
let output = '';
if (apiKey) {
output = await callGeminiApi(apiKey, model, prompt);
} else {
// Dynamic intelligent fallback
output = `✨ [Google Opal AI Offline Mode]\n\n` +
`Generated Output for: ${currentRunningApp.name}\n` +
`----------------------------------------\n` +
`১. অফার ও কাস্টমার রেসপন্স প্রস্তুত করা হয়েছে।\n` +
`২. ১০০% জেনুইন কোয়ালিটি ও সুপারফাস্ট ডেলিভারি নিশ্চিত করুন।\n` +
`৩. সরাসরি যোগাযোগ: https://wa.me/8801712426871\n\n` +
`💡 টিপস: Settings-এ গিয়ে আপনার Google Gemini API Key বসালে রিয়েল-টাইম আনলিমিটেড লাইভ রেসপন্স পাবেন!`;
}
resultContent.textContent = output.trim();
resultBox.classList.remove('hidden');
statusMsg.classList.add('hidden');
// Save to History
saveGenerationToHistory({
type: currentRunningApp.name,
title: currentRunningApp.name,
price: 'AI Generation',
date: new Date().toLocaleTimeString()
});
} catch (err) {
statusMsg.style.color = '#EF4444';
statusMsg.textContent = `❌ Error: ${err.message}`;
}
execBtn.disabled = false;
});
}
});
// --- 1-Click Client Dashboard Embed Modal ---
window.openEmbedModal = function(appId) {
const modal = document.getElementById('embedModal');
const title = document.getElementById('embedModalTitle');
const iframeBox = document.getElementById('embedIframeCode');
const apiUrlBox = document.getElementById('embedApiUrl');
const allApps = [...PREBUILT_MINI_APPS, ...getCustomMiniApps()];
const app = allApps.find(a => a.id === appId) || { name: 'Opal Mini-App', id: appId };
title.innerHTML = `📦 Embed "${app.name}" in Client Dashboard`;
const baseUrl = 'https://opal.auraajenticai.cloud';
iframeBox.textContent = `<iframe src="${baseUrl}/?app=${app.id}" width="100%" height="650" style="border:none; border-radius:18px; box-shadow:0 8px 32px rgba(0,0,0,0.4);" allow="clipboard-write"></iframe>`;
apiUrlBox.textContent = `${baseUrl}/api/v1/mini-app/run?app_id=${app.id}`;
modal.classList.remove('hidden');
};
window.closeEmbedModal = function() {
document.getElementById('embedModal').classList.add('hidden');
};
// --- Masterpiece 3D Canvas Poster Engine ---
let selectedStageTheme = 'obsidian_gold';
function initPosterLab() {
const productInput = document.getElementById('productInput');
const productPrice = document.getElementById('productPrice');
const customBadgeInput = document.getElementById('customBadgeInput');
const aspectRatioSelect = document.getElementById('aspectRatioSelect');
const brandSelect = document.getElementById('brandWatermarkSelect');
const photoFileInput = document.getElementById('photoFileInput');
const clearPhotoBtn = document.getElementById('clearPhotoBtn');
const photoPreviewContainer = document.getElementById('photoPreviewContainer');
const attachedPhotoImg = document.getElementById('attachedPhotoImg');
const generatePosterBtn = document.getElementById('generatePosterBtn');
const posterStatusText = document.getElementById('posterStatusText');
const posterResultCard = document.getElementById('posterResultCard');
const posterCanvas = document.getElementById('posterCanvas');
const canvasContainer = document.getElementById('canvasContainer');
const downloadPosterBtn = document.getElementById('downloadPosterBtn');
const shareWhatsAppBtn = document.getElementById('shareWhatsAppBtn');
// Stage Theme Selector
const themeChips = document.querySelectorAll('#themeSelectorGroup .theme-chip');
themeChips.forEach(chip => {
chip.addEventListener('click', () => {
themeChips.forEach(c => c.classList.remove('active'));
chip.classList.add('active');
selectedStageTheme = chip.getAttribute('data-theme');
});
});
let attachedImageBitmap = null;
// Photo Input change
photoFileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
attachedPhotoImg.src = event.target.result;
photoPreviewContainer.classList.remove('hidden');
clearPhotoBtn.classList.remove('hidden');
const img = new Image();
img.onload = () => { attachedImageBitmap = img; };
img.src = event.target.result;
};
reader.readAsDataURL(file);
}
});
clearPhotoBtn.addEventListener('click', () => {
photoFileInput.value = '';
attachedImageBitmap = null;
photoPreviewContainer.classList.add('hidden');
clearPhotoBtn.classList.add('hidden');
});
// Generate 3D Poster
generatePosterBtn.addEventListener('click', async () => {
const inputVal = productInput.value.trim();
const priceVal = productPrice.value.trim();
const badgeText = customBadgeInput ? customBadgeInput.value.trim() : '🇰🇷 100% Original Korea';
const aspect = aspectRatioSelect ? aspectRatioSelect.value : '1:1';
const brand = brandSelect ? brandSelect.value : 'glamourstouch';
posterStatusText.classList.remove('hidden');
posterStatusText.style.color = '#F59E0B';
posterStatusText.textContent = '⏳ Rendering 3D stage with GPU canvas blend...';
generatePosterBtn.disabled = true;
try {
let productImg = attachedImageBitmap;
let title = "Authentic Korean K-Beauty Care";
if (!productImg) {
const resolved = await resolveProductUrl(inputVal);
if (resolved && resolved.imageUrl) {
title = resolved.title || inputVal;
productImg = await loadImage(resolved.imageUrl);
} else {
const fallbackUrl = `https://images.unsplash.com/photo-1556228720-195a672e8a03?w=800&h=800&fit=crop`;
productImg = await loadImage(fallbackUrl);
title = inputVal;
}
}
if (productImg) {
if (aspect === '9:16') {
posterCanvas.width = 1080;
posterCanvas.height = 1920;
canvasContainer.classList.add('aspect-reels');
} else {
posterCanvas.width = 1080;
posterCanvas.height = 1080;
canvasContainer.classList.remove('aspect-reels');
}
await render3DCommercialPoster(posterCanvas, productImg, title, priceVal, badgeText, selectedStageTheme, aspect, brand);
posterResultCard.classList.remove('hidden');
posterStatusText.classList.add('hidden');
posterResultCard.scrollIntoView({ behavior: 'smooth' });
saveGenerationToHistory({
type: '3D Poster',
title: title,
price: priceVal,
date: new Date().toLocaleTimeString()
});
} else {
posterStatusText.textContent = '❌ Failed to load product image.';
}
} catch (err) {
posterStatusText.textContent = `❌ Error: ${err.message}`;
}
generatePosterBtn.disabled = false;
});
// Download
downloadPosterBtn.addEventListener('click', () => {
const link = document.createElement('a');
link.download = `Opal_3D_Poster_${Date.now()}.jpg`;
link.href = posterCanvas.toDataURL('image/jpeg', 0.95);
link.click();
});
// WhatsApp
shareWhatsAppBtn.addEventListener('click', () => {
const text = encodeURIComponent(`✨ 100% Authentic Product Order!\nProduct: ${productInput.value}\nPrice: ${productPrice.value}\nWebsite: https://glamourstouch.com`);
window.open(`https://wa.me/8801712426871?text=${text}`, '_blank');
});
// n8n Auto-Post Webhook
const autoPostN8nBtn = document.getElementById('autoPostN8nBtn');
const n8nPostStatusMsg = document.getElementById('n8nPostStatusMsg');
if (autoPostN8nBtn) {
autoPostN8nBtn.addEventListener('click', async () => {
const webhookUrl = localStorage.getItem('opal_n8n_webhook');
if (!webhookUrl) {
alert('⚠️ Please configure n8n Webhook URL in Settings first!');
switchToTab('tabSettings');
return;
}
n8nPostStatusMsg.classList.remove('hidden');
n8nPostStatusMsg.style.color = '#38BDF8';
n8nPostStatusMsg.textContent = '⏳ Sending 3D poster & copy to n8n Webhook...';
autoPostN8nBtn.disabled = true;
try {
const posterDataUrl = posterCanvas.toDataURL('image/jpeg', 0.92);
const payload = {
title: productInput.value.trim() || 'Authentic K-Beauty Skincare',
price: productPrice.value.trim() || '৳ ১,০৬০',
caption: `✨ ${productInput.value.trim()} ✨\n\n💰 অফার মূল্য: ${productPrice.value.trim()}\n🛡️ ১০০% অরিজিনাল গ্যারান্টি!\n\n💬 সরাসরি WhatsApp এ অর্ডার করতে ইনবক্স করুন:\n👉 https://wa.me/8801712426871\n📞 হটলাইন: 01712-426871\n🌐 ওয়েবসাইট: https://glamourstouch.com`,
image_url: posterDataUrl,
store: "Glamour's Touch",
website: "https://glamourstouch.com",
whatsapp: "01712-426871",
timestamp: new Date().toISOString()
};
const res = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (res.ok) {
const resData = await res.json().catch(() => ({}));
n8nPostStatusMsg.style.color = '#10B981';
n8nPostStatusMsg.textContent = `✅ ${resData.message || '🎉 পোস্টটি সফলভাবে n8n-এর মাধ্যমে Facebook Page-এ পাবলিশ হয়েছে!'}`;
} else {
n8nPostStatusMsg.style.color = '#EF4444';
n8nPostStatusMsg.textContent = `❌ n8n Webhook returned HTTP ${res.status}`;
}
} catch (err) {
n8nPostStatusMsg.style.color = '#EF4444';
n8nPostStatusMsg.textContent = `❌ Connection Error: ${err.message}`;
}
autoPostN8nBtn.disabled = false;
});
}
}
// Universal Link Resolver
async function resolveProductUrl(input) {
if (!input) return null;
if (input.match(/\.(jpeg|jpg|gif|png|webp)($|\?)/i)) {
return { title: 'Authentic Product', imageUrl: input };
}
const key = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZtY2x0cmpudXZ1b29hcmt2dWZuIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzUxMzY3MDQsImV4cCI6MjA5MDcxMjcwNH0.PkSgBAZx41X4sZurfyOdxCVa01hkKTkyBhVkGzx_4y4';
const uuidMatch = input.match(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/);
if (uuidMatch) {
try {
const res = await fetch(`https://fmcltrjnuvuooarkvufn.supabase.co/rest/v1/products?id=eq.${uuidMatch[0]}&select=*`, {
headers: { 'apikey': key, 'Authorization': `Bearer ${key}` }
});
const data = await res.json();
if (data && data.length > 0) {
const p = data[0];
return {
title: p.name || 'Authentic Korean Skincare',
price: p.price ? '৳ ' + p.price : '',
imageUrl: p.image || p.image_url || (p.images && p.images[0]) || ''
};
}
} catch (e) {
console.warn('GT Supabase fetch by ID failed:', e);
}
}
try {
const cleanQuery = encodeURIComponent(input.replace(/https?:\/\/[^\s]+/g, '').trim().slice(0, 30));
if (cleanQuery) {
const res = await fetch(`https://fmcltrjnuvuooarkvufn.supabase.co/rest/v1/products?name=ilike.*${cleanQuery}*&select=*&limit=1`, {
headers: { 'apikey': key, 'Authorization': `Bearer ${key}` }
});
const data = await res.json();
if (data && data.length > 0) {
const p = data[0];
return {
title: p.name || input,
price: p.price ? '৳ ' + p.price : '',
imageUrl: p.image || p.image_url || (p.images && p.images[0]) || ''
};
}
}
} catch (e) {
console.warn('GT Supabase search by name failed:', e);
}
return { title: input, imageUrl: 'https://images.unsplash.com/photo-1556228720-195a672e8a03?w=800&h=800&fit=crop' };
}
function loadImage(src) {
return new Promise((resolve, reject) => {
let loadUrl = src;
if (src.startsWith('http://') || src.startsWith('https://')) {
loadUrl = 'https://images.weserv.nl/?url=' + encodeURIComponent(src) + '&output=jpg&q=95';
}
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => resolve(img);
img.onerror = () => {
const fallbackImg = new Image();
fallbackImg.crossOrigin = 'anonymous';
fallbackImg.onload = () => resolve(fallbackImg);
fallbackImg.onerror = () => reject(new Error('Could not load image'));
fallbackImg.src = src;
};
img.src = loadUrl;
});
}
// --- 3D Canvas Multi-Theme Rendering Engine ---
async function render3DCommercialPoster(canvas, productImg, title, price, badgeText, theme = 'obsidian_gold', aspect = '1:1', brand = 'glamourstouch') {
const ctx = canvas.getContext('2d');
const w = canvas.width;
const h = canvas.height;
// Brand Header Profiles
const BRAND_PROFILES = {
glamourstouch: {
headerTitle: "✨ GLAMOUR'S TOUCH ✨",
headerSub: '100% AUTHENTIC KOREAN COSMETICS • DERMATOLOGIST TESTED',
badgeL1: '🌿 Pure & Safe Care',
badgeL2: '🛡️ Authentic Seal',
footerSite: 'glamourstouch.com',
footerHotline: '01712-426871'
},
snehalata: {
headerTitle: '🌸 SNEHALATA AURA 🌸',
headerSub: 'PREMIUM LUXURY FASHION, SAREE & LIFESTYLE • 100% AUTHENTIC',
badgeL1: '👗 Pure Fabric Weave',
badgeL2: '✨ Size Trial Guarantee',
footerSite: 'snehalata.com',
footerHotline: '01712-426871'
},
panjabi: {
headerTitle: '👑 AURA HERITAGE PANJABI 👑',
headerSub: 'ROYAL DESIGNER PANJABI & KABLI SUITS • 100% PURE COTTON & SILK',
badgeL1: '🧵 100% Pre-Shrunk Weave',
badgeL2: '✨ Size Trial Available',
footerSite: 'panjabi.auraajenticai.cloud',
footerHotline: '01712-426871'
},
techvolt: {
headerTitle: '⚡ TECHVOLT GADGETS ⚡',
headerSub: 'OFFICIAL WARRANTY • SMART ELECTRONICS & AUDIO ACCESSORIES',
badgeL1: '🔋 High Battery Life',
badgeL2: '🛡️ 1 Year Warranty',
footerSite: 'techvolt.auraajenticai.cloud',
footerHotline: '01712-426871'
},
organic: {
headerTitle: '🍯 PRANON ORGANIC 🍯',
headerSub: '100% PURE NATURAL HONEY & UNADULTERATED ORGANIC FOODS',
badgeL1: '🌿 100% Lab Tested',
badgeL2: '🛡️ Double Money Back',
footerSite: 'organic.auraajenticai.cloud',
footerHotline: '01712-426871'
},
sneakerlab: {
headerTitle: '👟 SNEAKERLAB BD 👟',
headerSub: 'PREMIUM STREETWEAR & GENUINE LEATHER FOOTWEAR',
badgeL1: '👟 Memory Foam Cushion',
badgeL2: '✨ Doorstep Fitting',
footerSite: 'sneakers.auraajenticai.cloud',
footerHotline: '01712-426871'
},
royale: {
headerTitle: '💎 AURA ROYALE 💎',
headerSub: 'LUXURY JEWELRY, WATCHES & 24-HOUR SIGNATURE PERFUMES',
badgeL1: '💎 24h Projection',
badgeL2: '👑 Pure Luxury Finish',
footerSite: 'royale.auraajenticai.cloud',
footerHotline: '01712-426871'
},
custom: {
headerTitle: '🛍️ PREMIUM E-COMMERCE 🛍️',
headerSub: '100% ORIGINAL AUTHENTIC • CASH ON DELIVERY BANGLADESH',
badgeL1: '⭐ Premium Quality',
badgeL2: '🛡️ 100% Original',
footerSite: 'auraajenticai.cloud',
footerHotline: '01712-426871'
}
};
const brandInfo = BRAND_PROFILES[brand] || BRAND_PROFILES.glamourstouch;
// Theme palettes
const THEMES = {
obsidian_gold: {
bgCenter: '#18212D', bgMid: '#0C1117', bgOuter: '#05080C',
spotlightColor: '#FFFFFF', goldRim: '#E5B83A', ringColor: '#66E5B83A',
pedestalTop: '#FFFFFF', pedestalMid: '#EBF2F8', pedestalDark: '#1B2533'
},
rose_quartz: {
bgCenter: '#2D1824', bgMid: '#170C13', bgOuter: '#0C0509',
spotlightColor: '#FFF0F5', goldRim: '#F472B6', ringColor: '#F472B666',
pedestalTop: '#FFF5F8', pedestalMid: '#FCE7F3', pedestalDark: '#371829'
},
cyber_neon: {
bgCenter: '#0F172A', bgMid: '#060E1A', bgOuter: '#02060D',
spotlightColor: '#E0F2FE', goldRim: '#06B6D4', ringColor: '#06B6D466',
pedestalTop: '#F0FDF4', pedestalMid: '#CFFAFE', pedestalDark: '#082F49'
},
botanical_eco: {
bgCenter: '#14281E', bgMid: '#0B1711', bgOuter: '#040B07',
spotlightColor: '#F0FDF4', goldRim: '#10B981', ringColor: '#10B98166',
pedestalTop: '#F7FEE7', pedestalMid: '#DCFCE7', pedestalDark: '#064E3B'
}
};
const currentTheme = THEMES[theme] || THEMES.obsidian_gold;
// 1. Background Radial Gradient
const stageCy = aspect === '9:16' ? h * 0.46 : h * 0.44;
const bgGrad = ctx.createRadialGradient(w / 2, stageCy, 50, w / 2, stageCy, w * 0.75);
bgGrad.addColorStop(0, currentTheme.bgCenter);
bgGrad.addColorStop(0.6, currentTheme.bgMid);
bgGrad.addColorStop(1, currentTheme.bgOuter);
ctx.fillStyle = bgGrad;
ctx.fillRect(0, 0, w, h);
// 2. Spotlight
const stageCx = w / 2;
const stageRadius = w * 0.38;
const spotGrad = ctx.createRadialGradient(stageCx, stageCy, 0, stageCx, stageCy, stageRadius);
spotGrad.addColorStop(0, '#FFFFFF');
spotGrad.addColorStop(0.48, '#FFFFFF');
spotGrad.addColorStop(0.68, currentTheme.spotlightColor);
spotGrad.addColorStop(0.85, '#64748B');
spotGrad.addColorStop(1, 'transparent');
ctx.fillStyle = spotGrad;
ctx.beginPath();
ctx.arc(stageCx, stageCy, stageRadius, 0, Math.PI * 2);
ctx.fill();
// Glow Rings
ctx.strokeStyle = currentTheme.ringColor;
ctx.lineWidth = 2.5;
ctx.beginPath();
ctx.arc(stageCx, stageCy, stageRadius * 0.96, 0, Math.PI * 2);
ctx.stroke();
ctx.setLineDash([12, 12]);
ctx.beginPath();
ctx.arc(stageCx, stageCy, stageRadius * 0.91, 0, Math.PI * 2);
ctx.stroke();
ctx.setLineDash([]);
// 3. 3D Dual-Tier Podium
const baseTierY = aspect === '9:16' ? 1220 : 745;
const baseTierRx = w * 0.38;
const baseTierRy = 34;
const baseTierHeight = 26;
// Base Shadow
const baseShadow = ctx.createRadialGradient(stageCx, baseTierY + baseTierHeight + 16, 20, stageCx, baseTierY + baseTierHeight + 16, baseTierRx * 1.15);
baseShadow.addColorStop(0, 'rgba(0,0,0,0.7)');
baseShadow.addColorStop(1, 'transparent');
ctx.fillStyle = baseShadow;
drawOval(ctx, stageCx, baseTierY + baseTierHeight + baseTierRy * 0.6, baseTierRx * 1.15, baseTierRy * 1.6);
// Base Cylinder Body
const baseCylGrad = ctx.createLinearGradient(stageCx - baseTierRx, 0, stageCx + baseTierRx, 0);
baseCylGrad.addColorStop(0, '#090D12');
baseCylGrad.addColorStop(0.5, '#475569');
baseCylGrad.addColorStop(1, '#090D12');
ctx.fillStyle = baseCylGrad;
ctx.fillRect(stageCx - baseTierRx, baseTierY, baseTierRx * 2, baseTierHeight);
drawOval(ctx, stageCx, baseTierY + baseTierHeight, baseTierRx, baseTierRy);
drawOval(ctx, stageCx, baseTierY, baseTierRx, baseTierRy);
// Top Tier
const topTierY = aspect === '9:16' ? 1180 : 708;
const topTierRx = w * 0.31;
const topTierRy = 28;
const topTierHeight = 34;
const topCylGrad = ctx.createLinearGradient(stageCx - topTierRx, 0, stageCx + topTierRx, 0);
topCylGrad.addColorStop(0, '#070A0E');
topCylGrad.addColorStop(0.5, currentTheme.goldRim);
topCylGrad.addColorStop(1, '#070A0E');
ctx.fillStyle = topCylGrad;
ctx.fillRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierHeight);
drawOval(ctx, stageCx, topTierY + topTierHeight, topTierRx, topTierRy);
// Top Surface Cap
const topSurfaceGrad = ctx.createRadialGradient(stageCx, topTierY, 0, stageCx, topTierY, topTierRx);
topSurfaceGrad.addColorStop(0, currentTheme.pedestalTop);
topSurfaceGrad.addColorStop(0.5, currentTheme.pedestalMid);
topSurfaceGrad.addColorStop(1, currentTheme.pedestalDark);
ctx.fillStyle = topSurfaceGrad;
drawOval(ctx, stageCx, topTierY, topTierRx, topTierRy);
// Gold Beveled Rim
ctx.strokeStyle = currentTheme.goldRim;
ctx.lineWidth = 3.5;
strokeOval(ctx, stageCx, topTierY, topTierRx, topTierRy);
// 4. Product Scaling & Placement
const targetH = aspect === '9:16' ? 560 : 500;
const targetW = aspect === '9:16' ? 580 : 520;
const srcW = productImg.width || 500;
const srcH = productImg.height || 500;
const scale = Math.min(targetW / srcW, targetH / srcH);
const destW = srcW * scale;
const destH = srcH * scale;
const destLeft = (w - destW) / 2;
const destTop = topTierY - destH + 18;
// Floor Reflection (Multiply blend)
ctx.save();
ctx.globalCompositeOperation = 'multiply';
ctx.globalAlpha = 0.25;
ctx.translate(0, (topTierY + 6) * 2);
ctx.scale(1, -1);
ctx.drawImage(productImg, destLeft, topTierY + 6, destW, destH * 0.35);
ctx.restore();
// Contact Drop Shadow
const contactShadow = ctx.createRadialGradient(stageCx, topTierY, 10, stageCx, topTierY, destW * 0.4);
contactShadow.addColorStop(0, 'rgba(0,0,0,0.8)');
contactShadow.addColorStop(1, 'transparent');
ctx.fillStyle = contactShadow;
drawOval(ctx, stageCx, topTierY + 2, destW * 0.38, 12);
// Product Image (Multiply blended to wipe white background)
ctx.save();
ctx.globalCompositeOperation = 'multiply';
ctx.drawImage(productImg, destLeft, destTop, destW, destH);
ctx.restore();
// 5. Value Trust Badges
const badgeY1 = aspect === '9:16' ? 340 : 240;
const badgeY2 = badgeY1 + 75;
drawPillBadge(ctx, 40, badgeY1, badgeText, true, currentTheme.goldRim);
drawPillBadge(ctx, 40, badgeY2, brandInfo.badgeL1, true, currentTheme.goldRim);
drawPillBadge(ctx, w - 40, badgeY1, '⚡ Fast Delivery BD', false, currentTheme.goldRim);
drawPillBadge(ctx, w - 40, badgeY2, brandInfo.badgeL2, false, currentTheme.goldRim);
// 6. Header Ribbon
ctx.fillStyle = '#F2090D12';
ctx.fillRect(0, 0, w, 92);
ctx.strokeStyle = currentTheme.goldRim;
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(0, 92);
ctx.lineTo(w, 92);
ctx.stroke();
ctx.fillStyle = currentTheme.goldRim;
ctx.font = 'bold 32px Plus Jakarta Sans, sans-serif';
ctx.textAlign = 'center';
ctx.fillText(brandInfo.headerTitle, w / 2, 52);
ctx.fillStyle = '#FFF4D0';
ctx.font = '16px Plus Jakarta Sans, sans-serif';
ctx.fillText(brandInfo.headerSub, w / 2, 80);
// 7. Product Title Card
const cleanTitle = title.length > 60 ? title.substring(0, 58) + '...' : title;
const titleCardTop = h - (aspect === '9:16' ? 320 : 235);
const titleCardBottom = h - (aspect === '9:16' ? 150 : 128);
ctx.fillStyle = '#EA0B0E14';
roundRect(ctx, 28, titleCardTop, w - 56, titleCardBottom - titleCardTop, 18);
ctx.fill();
ctx.strokeStyle = currentTheme.goldRim + '88';
ctx.lineWidth = 2;
roundRect(ctx, 28, titleCardTop, w - 56, titleCardBottom - titleCardTop, 18);
ctx.stroke();
ctx.fillStyle = '#FFFFFF';
ctx.font = 'bold 27px Plus Jakarta Sans, Hind Siliguri, sans-serif';
ctx.textAlign = 'center';
ctx.fillText(cleanTitle, w / 2, titleCardTop + 42);
ctx.fillStyle = currentTheme.goldRim;
ctx.font = 'bold 21px Hind Siliguri, sans-serif';
ctx.fillText(`${price} • ১০০% আসল গ্যারান্টি • দ্রুত হোম ডেলিভারি`, w / 2, titleCardTop + 80);
// 8. Bottom WhatsApp Banner
const footerHeight = aspect === '9:16' ? 140 : 118;
const footerTop = h - footerHeight;
const footerGrad = ctx.createLinearGradient(0, footerTop, w, h);
footerGrad.addColorStop(0, '#25D366');
footerGrad.addColorStop(1, '#1EB855');
ctx.fillStyle = footerGrad;
ctx.fillRect(0, footerTop, w, footerHeight);
ctx.fillStyle = '#FFFFFF';
ctx.font = 'bold 32px Plus Jakarta Sans, sans-serif';
ctx.textAlign = 'left';
ctx.fillText(`💬 WhatsApp Order: ${brandInfo.footerHotline}`, 35, footerTop + 48);
ctx.fillStyle = '#053314';
ctx.font = 'bold 20px Plus Jakarta Sans, sans-serif';
ctx.fillText(`🌐 Website: ${brandInfo.footerSite} • 📞 Hotline: ${brandInfo.footerHotline}`, 35, footerTop + 90);
// QR Code
await drawWhatsAppQrOnCanvas(ctx, w - 130, footerTop + 11, 96);
// Outer Border
ctx.strokeStyle = currentTheme.goldRim + '99';
ctx.lineWidth = 6;
ctx.strokeRect(3, 3, w - 6, h - 6);
}
function drawOval(ctx, cx, cy, rx, ry) {
ctx.beginPath();
ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
ctx.fill();
}
function strokeOval(ctx, cx, cy, rx, ry) {
ctx.beginPath();
ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
ctx.stroke();
}
function roundRect(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
function drawPillBadge(ctx, x, y, text, isLeft, goldColor = '#E5B83A') {
ctx.font = 'bold 18px Plus Jakarta Sans, Hind Siliguri, sans-serif';
const textWidth = ctx.measureText(text).width;
const pillW = textWidth + 28;
const pillH = 36;
const pillX = isLeft ? x : x - pillW;
const pillY = y - 22;
ctx.fillStyle = '#D90E141B';
roundRect(ctx, pillX, pillY, pillW, pillH, 18);
ctx.fill();
ctx.strokeStyle = goldColor + '66';
ctx.lineWidth = 1.5;
roundRect(ctx, pillX, pillY, pillW, pillH, 18);
ctx.stroke();
ctx.fillStyle = '#FFF0C8';
ctx.textAlign = 'left';
ctx.fillText(text, pillX + 14, pillY + 24);
}
async function drawWhatsAppQrOnCanvas(ctx, x, y, size) {
ctx.fillStyle = '#FFFFFF';
roundRect(ctx, x - 4, y - 4, size + 8, size + 8, 10);
ctx.fill();
const qrContainer = document.getElementById('qrcodeHidden');
if (qrContainer) {
qrContainer.innerHTML = '';
new QRCode(qrContainer, {
text: 'https://wa.me/8801712426871',
width: size,
height: size,
colorDark: '#0B2E13',
colorLight: '#FFFFFF',
correctLevel: QRCode.CorrectLevel.M
});
await new Promise(r => setTimeout(r, 80));
const qrImg = qrContainer.querySelector('img') || qrContainer.querySelector('canvas');
if (qrImg) {
ctx.drawImage(qrImg, x, y, size, size);
}
}
}
// --- Customer Care & Inbox AI Dedicated Studio ---
function initInboxAI() {
const customerMsgInput = document.getElementById('inboxCustomerMsg');
const storeContextInput = document.getElementById('inboxStoreContext');
const generateBtn = document.getElementById('generateInboxReplyBtn');
const statusMsg = document.getElementById('inboxStatusMsg');
const repliesCard = document.getElementById('inboxRepliesCard');
const reply1 = document.getElementById('replyText1');
const reply2 = document.getElementById('replyText2');
const reply3 = document.getElementById('replyText3');
if (!generateBtn) return;
generateBtn.addEventListener('click', async () => {
const query = customerMsgInput.value.trim();
const storeInfo = storeContextInput.value.trim();
const apiKey = localStorage.getItem('opal_gemini_api_key') || '';
const model = localStorage.getItem('opal_selected_model') || 'gemini-2.0-flash';
if (!query) {
alert('Please enter a customer message');
return;
}
statusMsg.classList.remove('hidden');
statusMsg.textContent = '⏳ Generating 3 sweet & polite sales replies with Gemini AI...';
generateBtn.disabled = true;
try {
if (apiKey) {
const prompt = `A customer sent this message in e-commerce inbox:
'${query}'
Store Info: ${storeInfo}
Write 3 ready-to-copy customer responses in natural, sweet BENGALI (বাংলা).
Format exactly with:
---REPLY1---
(Instant polite greeting and direct answer with price & benefits)
---REPLY2---
(Order confirmation closer asking for Name, Address, and Phone number)
---REPLY3---
(1-click WhatsApp order link: https://wa.me/8801712426871 and hotline 01712-426871)`;
const result = await callGeminiApi(apiKey, model, prompt);
const parts = result.split(/---REPLY[123]---/);
reply1.textContent = (parts[1] || 'আসসালামু আলাইকুম প্রিয় কাস্টমার! আমাদের প্রডাক্টের অফার মূল্য মাত্র ৳১০৬০। এটি ১০০% আসল প্রডাক্ট।').trim();
reply2.textContent = (parts[2] || 'অর্ডারটি কনফার্ম করতে আপনার নাম, সম্পূর্ণ ঠিকানা এবং মোবাইল নম্বরটি লিখে পাঠান। আমরা দ্রুত ক্যাশ অন ডেলিভারিতে পাঠিয়ে দেবো!').trim();
reply3.textContent = (parts[3] || 'সরাসরি হোয়াটসঅ্যাপে দ্রুত অর্ডার করতে ক্লিক করুন: https://wa.me/8801712426871\nহটলাইন: 01712-426871').trim();
} else {
reply1.textContent = `আসসালামু আলাইকুম প্রিয় আপু/ভাইয়া! 🥰\nআমাদের কাছে ১০০% অরিজিনাল কোরিয়ান স্কিনকেয়ার প্রোডাক্ট রয়েছে।\n\n💰 অফার মূল্য: ৳ ১,০৬০ (রেগুলার ৳ ১,৪৭০)\n🚚 হোম ডেলিভারি: ঢাকায় ৳৭০, ঢাকার বাইরে ৳১৩০\n\nএটি নিয়মিত ব্যবহারে ত্বক হবে কাচের মতো চকচকে ও দাগহীন! 🌸`;
reply2.textContent = `অর্ডারটি কনফার্ম করতে অনুগ্রহ করে আপনার:\n১. নাম\n২. সম্পূর্ণ ঠিকানা (জেলা/থানা সহ)\n৩. মোবাইল নম্বর\n\nলিখে পাঠিয়ে দিন। আমরা দ্রুত প্রোডাক্ট পাঠিয়ে দেবো! ধন্যবাদ। 🛍️`;
reply3.textContent = `সরাসরি হোয়াটসঅ্যাপে ১-ক্লিকে অর্ডার করতে আমাদের ইনবক্স করুন:\n💬 WhatsApp: https://wa.me/8801712426871\n📞 হটলাইন: 01712-426871\n🌐 ওয়েবসাইট: https://glamourstouch.com`;
}
repliesCard.classList.remove('hidden');
statusMsg.classList.add('hidden');
repliesCard.scrollIntoView({ behavior: 'smooth' });
} catch (e) {
statusMsg.textContent = `❌ Error: ${e.message}`;
}
generateBtn.disabled = false;
});
}
// --- History Management ---
function initHistory() {
const historyContainer = document.getElementById('historyListContainer');
const clearBtn = document.getElementById('clearHistoryBtn');
function renderHistory() {
if (!historyContainer) return;
const list = JSON.parse(localStorage.getItem('opal_history') || '[]');
if (list.length === 0) {
historyContainer.innerHTML = `
<div class="empty-state">
<span class="icon-empty">📭</span>
<p>No generations yet. Create your first 3D poster or mini-app generation!</p>
</div>`;
return;
}
historyContainer.innerHTML = list.map(item => `
<div class="app-card">
<div class="app-card-top">
<div class="app-icon">${item.type === '3D Poster' ? '🎨' : '⚡'}</div>
<span class="tag-gem">${item.type}</span>
</div>
<h3>${item.title}</h3>
<p>${item.price || item.type}</p>
<div class="app-card-footer">
<span class="meta-tag">Saved at ${item.date}</span>
</div>
</div>
`).join('');
}
if (clearBtn) {
clearBtn.addEventListener('click', () => {
localStorage.removeItem('opal_history');
renderHistory();
});
}
renderHistory();
}
function saveGenerationToHistory(item) {
const list = JSON.parse(localStorage.getItem('opal_history') || '[]');
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: '"সবাই যে এই {{product}} নিয়ে এত কথা বলছে—সত্যি বলতে ইউজ করার পর আমি জাস্ট অবাক হয়ে গেছি!"' },
{ time: '0:03 - 0:07', title: '😩 Problem & Relatable Agitation', visual: 'Creator shows daily struggle or low quality alternative, shaking head.', script: '"মার্কেটে কমদামি ফেক জিনিসে টাকা নষ্ট করার চেয়ে আসল জিনিস নেওয়া কত জরুরি, সেটা এখন বুঝতে পারছি!"' },
{ time: '0:07 - 0:12', title: '✨ Product Demo & Feature Macro', visual: 'Macro close-up: Creator demonstrates {{product}}, shows premium finish and instant performance.', script: '"জাস্ট কোয়ালিটি আর ফিনিশিংটা দেখেন—১০০% প্রিমিয়াম আর আসল হওয়ার ফিলটাই আলাদা!"' },
{ time: '0:12 - 0:15', title: '🛒 Social Proof & Urgency CTA', visual: 'Creator smiles radiantly, points to screen link with cash on delivery sticker.', script: '"১০০% আসল প্রোডাক্ট ক্যাশ অন ডেলিভারিতে পেতে এখনই নিচের লিংকে মেসেজ দিন!"' }
]
},
fashion_tryon: {
name: 'Fashion OOTD & Saree Drape',
styleDescription: 'Aesthetic full-body bedroom & natural daylight mirror try-on, slow-motion fabric flow, close-up texture weave, high elegance Bangladeshi fashion presentation.',
cameraSettings: '9:16 vertical 4K 60fps, 50mm portrait lens, f/1.8 shallow depth, gentle panning shot down the length of fabric, natural afternoon window light.',
timelineTemplate: [
{ time: '0:00 - 0:03', title: '👗 OOTD Fashion Hook', visual: 'Creator steps back from mirror, doing a graceful 360-degree spin showing the gorgeous fit of {{product}}.', script: '"দাওয়াত বা স্পেশাল অকেশনে এই শাড়ি/ড্রেসটা পরে গেলে সবার চোখ আপনার দিকেই থাকবে!"' },
{ time: '0:03 - 0:07', title: '🧵 Fabric & Weave Macro Zoom', visual: 'Macro shot of hand gently gliding over the pure soft fabric, catching light reflections.', script: '"কাপড়টা কতটা সফট আর আরামদায়ক, জাস্ট ফিনিশিং আর সুতার কাজটা দেখলেই বুঝতে পারবেন!"' },
{ time: '0:07 - 0:12', title: '✨ Styling & Fitting Silhouette', visual: 'Creator styling with matching accessories, smiling with confidence in natural daylight.', script: '"শরীরে একদম পারফেক্ট ফিট হয়ে থাকে। কোনো অস্বস্তি ছাড়াই সারাদিন পরে থাকা যাবে!"' },
{ time: '0:12 - 0:15', title: '🛍️ Size Choice & 1-Click Order', visual: 'Holding boutique packaging bag, pointing to WhatsApp order button.', script: '"পছন্দের কালার ও সাইজ বুক করতে এখনই নিচে ইনবক্স করুন। ফ্রি হোম ডেলিভারি চালু আছে!"' }
]
},
panjabi_royal: {
name: 'Royal Panjabi & Kabli Festive Showcase',
styleDescription: 'Grand royal palace or luxury festive living room setting, slow-motion fabric flow, close-up thread embroidery & metallic snap buttons, confident aristocratic stance.',
cameraSettings: 'Cinematic 9:16 vertical 4K 60fps, 85mm portrait lens, f/1.8 golden hour sidelight, elegant slow pan tracking from collar embroidery down to hemline.',
timelineTemplate: [
{ time: '0:00 - 0:03', title: '👑 Royal Festive Hook', visual: 'Creator adjusts collar in front of antique mirror, turning around with a regal smile wearing {{product}}.', script: '"যেকোনো উৎসব বা বিয়ের অনুষ্ঠানে মধ্যমণি হতে পাঞ্জাবিটা হওয়া চাই একদম পারফেক্ট!"' },
{ time: '0:03 - 0:07', title: '🧵 Embroidery & Pre-Shrunk Weave', visual: 'Extreme macro zoom on hand-embroidery stitches around collar, chest placket, and luxury silk-cotton weave.', script: '"১০০% প্রি-শ্রাঙ্ক প্রিমিয়াম ফেব্রিক আর নিখুঁত সুতার কাজ—কাপড়টা গায়ে দিলে ফিলটাই অন্যরকম!"' },
{ time: '0:07 - 0:12', title: '✨ Perfect Fit & Comfort Check', visual: 'Creator buttoning snap cuff, walking gracefully in natural golden ambient light.', script: '"শরীরে একদম পারফেক্ট ফিট বসে যায়। গরমেও সারাদিন পরলে অসম্ভব আরাম পাওয়া যায়!"' },
{ time: '0:12 - 0:15', title: '📦 Size Trial & Instant COD CTA', visual: 'Holding royal luxury gift box packaging, pointing to WhatsApp 1-click booking link.', script: '"বাসায় সাইজ ট্রায়াল সুবিধা সহ ক্যাশ অন ডেলিভারিতে নিতে এখনই নিচে ইনবক্স করুন!"' }
]
},
gadget_unboxing: {
name: 'Smart Gadget Sound & Stress Test',
styleDescription: 'Futuristic desk setup with RGB neon rim light, macro lens focusing on digital display, water-resistance spray test, tactile button press response.',
cameraSettings: 'Top-down macro 4K, 120fps ultra slow-mo, cyberpunk teal & orange lighting, clean audio capturing crisp click sensations.',
timelineTemplate: [
{ time: '0:00 - 0:03', title: '⚡ Tech Power-On Hook', visual: 'Hands slicing open gadget box. Screen lights up with vibrant AMOLED colors showing {{product}}.', script: '"এই বাজেটে এত পাওয়ারফুল ফিচারস আর প্রিমিয়াম বিল্ড কোয়ালিটি—বিশ্বাসই হচ্ছিল না!"' },
{ time: '0:03 - 0:07', title: '💧 Extreme Water & Drop Test', visual: 'Spraying water mist on the gadget screen while active; wiping off cleanly without any glitch.', script: '"IP68 ওয়াটারপ্রুফ আর মেটাল বডি ফ্রেম। বৃষ্টি বা রাফ ইউজ—যেকোনো কন্ডিশনে একদম রক সলিড!"' },
{ time: '0:07 - 0:12', title: '🔋 Battery & ANC Audio Demo', visual: 'Finger tapping touch controls, smooth 60Hz UI scrolling and seamless Bluetooth connection.', script: '"এক চার্জে টানা ৭ দিনের ব্যাটারি ব্যাকআপ আর বেজ সাউন্ড কোয়ালিটি একদম নেক্সট লেভেল!"' },
{ time: '0:12 - 0:15', title: '🛡️ Official Warranty & COD CTA', visual: 'Displaying official 1-year replacement warranty card and fast dispatch flyer.', script: '"১ বছরের অফিসিয়াল রিপ্লেসমেন্ট ওয়ারেন্টি সহ ক্যাশ অন ডেলিভারিতে নিতে এখনই অর্ডার করুন!"' }
]
},
sneaker_flex: {
name: 'Sneaker Flex & Kick Test',
styleDescription: 'Street style sneakerhead perspective, dynamic footwork on pavement, slow-mo sole flexion, crisp leather crease resistance check.',
cameraSettings: 'Low-angle ground tracking shot, 4K 60fps, dynamic gimbal push-in, natural street sun flare.',
timelineTemplate: [
{ time: '0:00 - 0:03', title: '👟 Street Flex Entry', visual: 'Low angle shot of creator stepping into frame wearing {{product}}, doing a quick heel-toe flex.', script: '"স্নিকার লাভারদের জন্য এই পেয়ারটা জাস্ট আগুন! লুক আর কমফোর্ট দুটোই টপ নচ!"' },
{ time: '0:03 - 0:07', title: '🛡️ Sole Cushion & Crease Test', visual: 'Bending the sole with hands showing memory foam bounce back, no deep creases.', script: '"মেমোরি ফোম ইনসোল হওয়ায় সারাদিন হেঁটেও পায়ে কোনো ব্যথা হবে না। লেদার কোয়ালিটি ১০০% পিওর!"' },
{ time: '0:07 - 0:12', title: '🔥 Outfit Pairing Display', visual: 'Wide street shot pairing the sneakers with denim & cargo streetwear.', script: '"জিন্স কিংবা কার্গো—যেকোনো ক্যাজুয়াল আউটফিটের সাথে লুকটা একদম প্রিমিয়াম ফুটে উঠবে!"' },
{ time: '0:12 - 0:15', title: '📦 Doorstep Size Trial CTA', visual: 'Holding genuine sneaker box with size chart guarantee on screen.', script: '"হোম ডেলিভারিতে সাইজ ট্রায়াল সুবিধা সহ ক্যাশ অন ডেলিভারিতে বুক করতে এখনই মেসেজ দিন!"' }
]
},
organic_purity: {
name: 'Organic Honey & Food Purity Test',
styleDescription: 'Sunlit rustic wooden kitchen table, glass jar of pure golden honey, wooden honey dipper slow swirl, water glass drop dissolving test.',
cameraSettings: 'Macro 4K f/2.8, warm sunlit golden flare, extreme slow-mo 120fps honey dripping into water without clouding.',
timelineTemplate: [
{ time: '0:00 - 0:03', title: '🍯 Pure Nature Swirl Hook', visual: 'Wooden dipper lifting thick golden {{product}}, thick continuous thread without breaking.', script: '"খাঁটি মধুর আসল চেনার উপায় কি জানেন? এই দেখুন—এক ফোঁটাও ছিঁড়ে পড়বে না!"' },
{ time: '0:03 - 0:07', title: '🧪 Live Water Dissolve Test', visual: 'Dripping honey into clear glass of water; honey settles at bottom without mixing instantly.', script: '"পানির গ্লাসে দেওয়ার সাথে সাথেই নিচে গিয়ে জমাট বাঁধল—১০০% নির্ভেজাল ও খাঁটি প্রাকৃতিক মধু!"' },
{ time: '0:07 - 0:12', title: '🌿 Raw Aroma & Health Benefits', visual: 'Creator taking a small spoonful, expressing delight at the authentic floral aroma and taste.', script: '"প্রাকৃতিক স্বাদ আর সুবাসে ভরা। পরিবারের রোগ প্রতিরোধ ক্ষমতা বাড়াতে প্রতিদিন এক চামচই যথেষ্ট।"' },
{ time: '0:12 - 0:15', title: '🛡️ 100% Purity Guarantee CTA', visual: 'Displaying lab test report and eco-friendly packing with cash-on-delivery guarantee.', script: '"ভেজাল প্রমাণিত হলে ডাবল মানি-ব্যাক গ্যারান্টি! এখনই আসল মধু ঘরে পেতে ইনবক্স করুন।"' }
]
},
perfume_reaction: {
name: 'Luxury Perfume 24-Hour Projection',
styleDescription: 'Luxury dark obsidian backdrop, golden mist atomizer spray caught in volumetric beam of light, public compliment reactions.',
cameraSettings: 'High-speed 4K macro spray capture, anamorphic lens flare, moody golden rim lighting.',
timelineTemplate: [
{ time: '0:00 - 0:03', title: '💎 Atomizer Mist Hook', visual: 'Slow motion fine mist spray from golden luxury bottle of {{product}} against dark background.', script: '"এই পারফিউমটা দিয়ে বাইরে গেলে মানুষ ঘুরে তাকাতে বাধ্য! সুবাসটা জাস্ট আনরিয়েল!"' },
{ time: '0:03 - 0:07', title: '🌸 Scent Notes & Projection', visual: 'Creator spraying on wrist and collarbone, describing top notes of vanilla, amber and oud.', script: '"প্রিমিয়াম ফ্রেঞ্চ ও অ্যারাবিক নোটসের ব্লেন্ড। একবার দিলে জামায় সুবাস থাকে ২৪ ঘণ্টারও বেশি!"' },
{ time: '0:07 - 0:12', title: '✨ Compliment Magnet Test', visual: 'Friends and colleagues walking past, smiling and asking what perfume it is.', script: '"অফিস, পার্টি কিংবা ডেট নাইট—সব জায়গায় আপনাকে দেবে এক আকর্ষণীয় আভিজাত্য।"' },
{ time: '0:12 - 0:15', title: '🛒 Luxury Decant / Full Bottle CTA', visual: 'Luxury box and tester kit shown with WhatsApp direct 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, 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 authentic hologram seal and QR sticker.', script: '"১০০% অরিজিনাল সিকিউরিটি সিল নিশ্চিত করা আছে। প্যাকেজিংটাই তো মাথা নষ্ট!"' },
{ time: '0:07 - 0:12', title: '🧪 Luxurious Swatch / Feel', visual: 'Unboxing product, showing clean tactile premium finish.', 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 Test',
styleDescription: 'Investigative, high-retention TikTok testing format. Direct close-up testing performance 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 {{product}}, looking skeptical at claim.', script: '"সবাই যে {{product}} নিয়ে লাফালাফি করছে—আসলেই কি এটা কাজ করে নাকি শুধুই হাইপ? চলেন লাইভ টেস্ট করি!"' },
{ time: '0:03 - 0:07', title: '🧪 Live Practical Demonstration', visual: 'Close-up demonstration showing real-time action and performance.', script: '"আমরা প্র্যাক্টিক্যালি টেস্ট করে দেখছি এর কোয়ালিটি কেমন কাজ করে..."' },
{ time: '0:07 - 0:12', title: '😱 Shocking Performance Result', visual: 'Flawless output / result verified on screen.', script: '"ও মাই গড! রেজাল্ট দেখেন—দাবি একদম ১০০% সত্যি! নিজের চোখকে বিশ্বাস করতে পারছি না!"' },
{ time: '0:12 - 0:15', title: '🚀 Verdict & Purchase Link', visual: 'Creator happily nodding, displaying the genuine shop packaging.', script: '"হাইপটা একদম সত্যি! আসলটা অর্ডার করতে নিচের বাটনে এখনই ক্লিক করুন।"' }
]
},
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: '🛡️ Quality 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');
});
}
}