7222 lines
336 KiB
JavaScript
7222 lines
336 KiB
JavaScript
// Google Opal AI - Master Mini-App Studio & 3D Poster Lab Engine v5.0
|
||
|
||
const I18N_DICTIONARY = {
|
||
bn: {
|
||
brand_subtitle: "Google DeepMind • Mini-App Engine",
|
||
btn_add_miniapp: "✨ + Mini-App",
|
||
lang_btn_text: "🌐 EN",
|
||
|
||
// Poster Lab
|
||
poster_title: "3D Commercial Poster Lab",
|
||
poster_subtitle: "আসল প্রডাক্টের ছবি, ৮কে ন্যাচারাল লাইফস্টাইল ফটোগ্রাফি ও WhatsApp QR সহ বিজ্ঞাপন পোস্টার বানান",
|
||
theme_arch_label: "৮কে ন্যাচারাল ও কমার্শিয়াল স্টুডিও ফ্রেম (8K Natural & 3D Styles):",
|
||
theme_arch_badge: "32 Photorealistic & Commercial Styles",
|
||
theme_cat_all: "🔥 All (32)",
|
||
theme_cat_natural: "🌿 8K Natural (7)",
|
||
theme_cat_stage: "👑 3D Stages (20)",
|
||
theme_cat_grid: "🔲 Grid Layouts (5)",
|
||
poster_aspect_label: "পোস্টার সাইজ ও ব্র্যান্ড ওয়াটারমার্ক:",
|
||
poster_mode_label: "ডিসপ্লে মোড (Display Mode):",
|
||
mode_single_btn: "🎯 ১টি প্রোডাক্ট হিরো ৩ডি স্টেজ",
|
||
mode_multi_btn: "🔲 মাল্টি-প্রোডাক্ট গ্রিড ভিউ (৩-৪টি প্রোডাক্ট)",
|
||
trends_label: "🔥 গুগল ট্রেন্ডিং সার্চ (Google Trends 1-Click Load):",
|
||
trends_badge: "Realtime BD Trends",
|
||
product_input_label: "প্রডাক্ট লিংক বা নাম (Product Link or Name):",
|
||
open_catalog_btn: "🛍️ GT ক্যাটালগ লিস্ট (560+)",
|
||
product_input_ph: "e.g. Silk Saree, Smartwatch, Pure Honey, Sneaker or Skincare",
|
||
product_price_label: "মূল্য ও অফার (Price & Discount):",
|
||
product_price_ph: "e.g. ৳ ১,০৬০ (৳ ১,৪৭০) 28% OFF",
|
||
product_badge_label: "কাস্টম ব্যাজ টেক্সট (Trust Badge):",
|
||
product_badge_ph: "e.g. 🛡️ 100% Original Guarantee",
|
||
upload_photo_btn: "iPhone / পিসি গ্যালারি থেকে ছবি আপলোড",
|
||
clear_photo_btn: "✖ ছবি মুছুন",
|
||
photo_attached_badge: "✅ Photo Attached",
|
||
grid_layout_label: "গ্রিড লেআউট ফ্রেম (Multi-Product Grid Layout):",
|
||
grid_layout_badge: "3-4 Products Collage Engine",
|
||
grid_headline_ph: "পোস্টার মেইন হেডলাইন (e.g. ✨ 4-IN-1 MEGA COMBO)",
|
||
multi_combos_label: "🎁 ট্রেন্ডিং মাল্টি-প্যাক কম্বো (1-Click Multi Combos):",
|
||
multi_combos_badge: "Full Catalog Combos",
|
||
slot1_title: "🥇 Slot 1 (Hero/Top-Left)",
|
||
slot2_title: "🥈 Slot 2 (Top-Right)",
|
||
slot3_title: "🥉 Slot 3 (Bottom-Left)",
|
||
slot4_title: "🏅 Slot 4 (Bottom-Right)",
|
||
slot_upload_btn: "ছবি",
|
||
slot_placeholder_text: "ছবি সিলেক্ট করুন",
|
||
slot_title_ph: "প্রোডাক্ট নাম",
|
||
slot_price_ph: "মূল্য",
|
||
slot_badge_ph: "ব্যাজ",
|
||
btn_generate_poster: "Generate 3D Commercial Poster (Canvas GPU)",
|
||
poster_result_title: "✨ Commercial Ad Poster Generated",
|
||
btn_save_photos: "💾 Save to Photos",
|
||
btn_whatsapp_order: "💬 WhatsApp Order",
|
||
btn_autopost_n8n: "1-Click Auto Post to Facebook Page (via n8n)",
|
||
|
||
// Mini-Apps Hub
|
||
hub_title: "✨ Opal Mini-Apps Hub",
|
||
hub_subtitle: "সকল ক্যাটাগরির ই-কমার্সের জন্য কাস্টম এআই মিনি-অ্যাপ তৈরি ও এম্বেড করুন",
|
||
btn_create_app: "+ Create App",
|
||
cat_all: "🔥 All Niches",
|
||
cat_fashion: "👗 Fashion & Apparel",
|
||
cat_electronics: "📱 Tech & Gadgets",
|
||
cat_cosmetics: "💄 Beauty & Skincare",
|
||
cat_footwear: "👟 Shoes & Leather",
|
||
cat_organic: "🍯 Organic & Food",
|
||
cat_sales: "💬 Sales & Care",
|
||
cat_tools: "⚙️ AI Logistics",
|
||
cat_custom: "💎 Custom Apps",
|
||
empty_apps: "এই ক্যাটাগরিতে কোনো মিনি-অ্যাপ পাওয়া যায়নি। নতুন বানাতে '+ Create App' চাপুন!",
|
||
btn_embed: "📦 Embed",
|
||
btn_run: "⚡ Run",
|
||
|
||
// Builder
|
||
builder_title: "Visual Mini-App Builder",
|
||
builder_subtitle: "আপনার ক্লায়েন্ট ড্যাশবোর্ডের জন্য কয়েক ক্লিকে কাস্টম এআই মিনি-অ্যাপ তৈরি করুন",
|
||
builder_app_name: "অ্যাপের নাম (Mini-App Name):",
|
||
builder_app_name_ph: "e.g. VIP Customer Offer Generator",
|
||
builder_app_emoji: "আইকন/ইমোজি (App Icon):",
|
||
builder_app_cat: "ক্যাটাগরি (Category):",
|
||
builder_app_model: "ডিফল্ট এআই মডেল (AI Model):",
|
||
builder_app_desc: "সংক্ষিপ্ত বিবরণ (Short Description):",
|
||
builder_app_desc_ph: "e.g. বিশেষ কাস্টমারদের জন্য আকর্ষণীয় অফার মেসেজ তৈরি করে।",
|
||
builder_app_fields: "ইনপুট ফিল্ডস (Input Fields for User):",
|
||
builder_field1_ph: "Field 1 Label (e.g. Customer Name / Product)",
|
||
builder_field2_ph: "Field 2 Label (e.g. Offer / Discount / Context)",
|
||
builder_prompt_template: "এআই প্রম্পট টেমপ্লেট (Prompt Template with Variables):",
|
||
builder_prompt_template_ph: "You are an expert AI copywriter. Generate a high converting message based on {{field1}} and {{field2}} in natural Bangla.",
|
||
builder_hint: "💡 টেমপ্লেটের মধ্যে {{field1}} এবং {{field2}} স্বয়ংক্রিয়ভাবে ইউজারের ইনপুট দিয়ে প্রতিস্থাপিত হবে।",
|
||
btn_save_miniapp: "💾 Save Mini-App & Add to Hub",
|
||
btn_test_miniapp: "🧪 Test Run App",
|
||
|
||
// UGC Studio
|
||
ugc_title: "UGC Video Ads & Google Flow Studio",
|
||
ugc_subtitle: "Google Veo 3.1 ও Omni Video ইঞ্জিনের জন্য হাই-কনভার্টিং UGC স্টাইল প্রম্পট ও স্ক্রিপ্ট তৈরি করুন",
|
||
ugc_presets_label: "জনপ্রিয় UGC স্টাইল লাইব্রেরি (Select UGC Style Preset):",
|
||
ugc_card_unhinged_title: "Raw iPhone Review",
|
||
ugc_card_unhinged_desc: "রুমের আলোয় ফ্রন্ট ক্যামেরায় আনফিল্টার্ড বাস্তব রিভিউ ও প্রডাক্ট টেস্ট (Universal)।",
|
||
ugc_card_fashion_title: "Fashion OOTD & Drape",
|
||
ugc_card_fashion_desc: "শাড়ি/লেডিস ড্রেস ট্রাই-অন, ফেব্রিকে জুম, ফিটিং ও স্লো-মো ওয়াক ট্রায়াল।",
|
||
ugc_card_panjabi_title: "Royal Panjabi & Kabli",
|
||
ugc_card_panjabi_desc: "প্রিমিয়াম পাঞ্জাবি/কাবলি শোকেস, কলারের সূক্ষ্ম সুতার কাজ ও রাজকীয় ফিট।",
|
||
ugc_card_gadget_title: "Gadget Sound & Stress Test",
|
||
ugc_card_gadget_desc: "স্মার্টওয়াচ/ইয়ারবাডস আনবক্সিং, ANC সাউন্ড টেস্ট ও ওয়াটারপ্রুফ ড্রপ টেস্ট।",
|
||
ugc_card_sneaker_title: "Sneaker Flex & Kick Test",
|
||
ugc_card_sneaker_desc: "স্নিকার আনবক্সিং, সোল বেন্ড টেস্ট ও স্ট্রিট ওয়াক স্টাইলিশ লুক।",
|
||
ugc_card_organic_title: "Organic Honey Purity Test",
|
||
ugc_card_organic_desc: "১০০% খাঁটি মধুর পানির গ্লাসে দ্রবীভূত পরীক্ষা ও টেস্ট রিভিউ।",
|
||
ugc_card_perfume_title: "Luxury Perfume 24h Test",
|
||
ugc_card_perfume_desc: "পারফিউমের লং লাস্টিং সুবাস ও পাবলিক কমপ্লিমেন্ট রিয়েকশন।",
|
||
ugc_card_grwm_title: "Bathroom Mirror GRWM",
|
||
ugc_card_grwm_desc: "সকালে মুখে ড্রপ দিয়ে স্কিনকেয়ার টেক্সচার ও গ্লাস স্কিন গ্লো প্রদর্শন।",
|
||
ugc_card_asmr_title: "POV Unboxing ASMR",
|
||
ugc_card_asmr_desc: "হাতে পার্সেল খোলা, ক্রিস্পি বাবল র্যাপ ও প্রডাক্টের স্যাটিস্ফাইং সাউন্ড।",
|
||
ugc_card_skeptic_title: "Viral Claim Skeptic",
|
||
ugc_card_skeptic_desc: "\"সত্যিই কি কাজ করে?\"—হাতে-কলমে কার্যকারিতা লাইভ পরীক্ষা।",
|
||
ugc_card_founder_title: "Founder's Direct Hook",
|
||
ugc_card_founder_desc: "কুরিয়ার পার্সেলের স্তূপের সামনে দাঁড়িয়ে প্রডাক্ট কোয়ালিটি ও মানি-ব্যাক গল্প।",
|
||
ugc_prod_label: "প্রডাক্টের নাম ও ব্র্যান্ড (Product):",
|
||
ugc_prod_ph: "e.g. Medicube Collagen Jelly Cream",
|
||
ugc_aud_label: "টার্গেট অডিয়েন্স ও সমস্যা (Audience/Problem):",
|
||
ugc_aud_ph: "e.g. যাদের ত্বক খসখসে ও রোদে পোড়া দাগ রয়েছে",
|
||
ugc_persona_label: "ক্রিয়েটর টাইপ (Persona):",
|
||
ugc_duration_label: "ভিডিও দৈর্ঘ্য (Duration):",
|
||
ugc_engine_label: "এআই ভিডিও ইঞ্জিন (Target Engine):",
|
||
btn_generate_ugc: "Generate Google Flow Storyboard & Master Veo Prompt",
|
||
ugc_result_title: "🎬 UGC Video Ad Storyboard & Master Prompt",
|
||
ugc_master_prompt_label: "🎯 Master Cinematic AI Prompt for Veo 3.1 (English Prompt):",
|
||
btn_copy_master_prompt: "📋 Copy Master Prompt for Veo 3.1",
|
||
ugc_timeline_label: "⏱️ Google Flow Shot-by-Shot Timeline (Storyboard & Bengali Dialogue):",
|
||
btn_copy_complete_flow: "📋 Copy Complete Flow",
|
||
btn_send_veo: "🚀 Send to Aura Veo 3.1 Engine",
|
||
|
||
// CGI Studio
|
||
cgi_title: "3D CGI Master Prompt Studio & Catalog Library",
|
||
cgi_subtitle: "GT ও সকল ব্র্যান্ডের জন্য 8K আল্ট্রা-রিয়েলিস্টিক কমার্শিয়াল স্টুডিও প্রম্পট লাইব্রেরি",
|
||
cgi_cat_all: "🔥 All Stores",
|
||
cgi_search_ph: "🔍 Search product or ingredient (e.g. Collagen, Retinol, Silk, Smartwatch, Honey)...",
|
||
btn_cgi_copy: "📋 প্রম্পট কপি",
|
||
btn_cgi_use: "🎨 ৩ডি ল্যাবে ওপেন",
|
||
cgi_empty: "কোনো প্রম্পট পাওয়া যায়নি। অন্য ক্যাটাগরি বা কিওয়ার্ড দিয়ে সার্চ করুন।",
|
||
|
||
// Inbox AI
|
||
inbox_title: "Omnichannel Customer Care & Sales Closer AI",
|
||
inbox_subtitle: "কাস্টমারের মেসেজ দিলে ১-ক্লিকে ৩টি মিষ্টি ও হাই-কনভার্টিং উত্তর তৈরি করে",
|
||
inbox_query_label: "কাস্টমার ইনবক্সে কী লিখেছে? (Customer Query):",
|
||
inbox_query_ph: "e.g. আপনাদের কাছে কি গ্লাস স্কিন সিরাম আছে? দাম কত আর ডেলিভারি চার্জ কত?",
|
||
inbox_store_label: "দোকানের পলিসি ও হটলাইন (Store Info):",
|
||
inbox_store_ph: "Store: Glamour's Touch (glamourstouch.com), Hotline: 01712-426871...",
|
||
btn_generate_inbox: "Generate 3 Ready-to-Send Replies with Gemini AI",
|
||
reply1_header: "⚡ ১. দ্রুত ও মিষ্টি উত্তর (Instant Polite Greeting & Price)",
|
||
reply2_header: "🛍️ ২. সেলস অর্ডার কনফার্মেশন (Direct Order Closer)",
|
||
reply3_header: "💬 ৩. ১-ক্লিক WhatsApp লিঙ্ক (Instant WhatsApp Closer)",
|
||
btn_copy: "📋 Copy",
|
||
|
||
// History
|
||
history_title: "📜 Saved Generation History",
|
||
btn_clear_history: "Clear All",
|
||
history_empty: "No generations yet. Create your first 3D poster or mini-app generation!",
|
||
|
||
// Settings
|
||
settings_title: "Settings & Google AI Configuration",
|
||
settings_subtitle: "গুগল জেমিনি ২.০ ও গ্যামা ওপেন মডেল সেটআপ",
|
||
settings_apikey_label: "Google Gemini API Key (100% Free from AI Studio):",
|
||
settings_apikey_ph: "Paste your AI Studio API key (AIzaSy...)",
|
||
settings_apikey_hint: "API Key is saved securely in your browser/device local storage.",
|
||
settings_model_label: "Default AI Model (এআই মডেল):",
|
||
settings_webhook_label: "n8n Auto-Post Webhook URL (Aura Ajentic AI):",
|
||
settings_webhook_hint: "Pre-configured with your n8n cloud instance at n8n.auraajenticai.cloud",
|
||
btn_save_settings: "💾 Save Settings & Test Connection",
|
||
about_title: "💎 About Google Opal AI (iOS Edition)",
|
||
about_desc: "This web studio is engineered specifically for iPhone (iOS Safari / PWA) and client dashboards with 0ms latency, native 2D canvas GPU rendering, and official Google Gemini 2.0 AI integration.",
|
||
iphone_tips: "📲 iPhone টিপস: Safari-এর নিচে থাকা Share (📤) বাটনে ট্যাপ করে 'Add to Home Screen' চাপুন। তাহলে এটি আপনার আইফোনে একদম আসল অ্যাপের মতো ফুল-স্ক্রিনে চলবে!",
|
||
|
||
// Bottom Navigation
|
||
nav_apps: "অ্যাপস হাব",
|
||
nav_poster: "৩ডি পোস্টার",
|
||
nav_cgi: "CGI প্রম্পট",
|
||
nav_ugc: "UGC স্টুডিও",
|
||
nav_builder: "অ্যাপ মেকার",
|
||
nav_inbox: "ইনবক্স এআই",
|
||
nav_settings: "সেটিংস",
|
||
|
||
// Modals
|
||
runner_modal_title: "🚀 Mini-App Runner",
|
||
btn_runner_generate: "⚡ Generate with AI",
|
||
runner_output_title: "✨ Generated Output",
|
||
embed_modal_title: "📦 Embed in Client Dashboard",
|
||
embed_modal_desc: "আপনার ক্লায়েন্ট ড্যাশবোর্ডে (যেমন aura client dashboard) এই মিনি-অ্যাপটি ১-ক্লিকে যুক্ত করতে নিচের কোডটি কপি করুন:",
|
||
embed_iframe_label: "HTML / Iframe Embed Snippet:",
|
||
btn_copy_iframe: "📋 Copy Iframe Code",
|
||
embed_api_label: "Direct Webhook / API URL:",
|
||
btn_copy_api: "📋 Copy Direct API URL",
|
||
catalog_modal_title: "Universal E-Commerce Catalog & Store Sync",
|
||
catalog_count_default: "৫৬০+ রিয়েল প্রডাক্ট লাইব্রেরি",
|
||
btn_sync_new_store: "নতুন ক্লায়েন্ট স্টোর সিঙ্ক",
|
||
sync_panel_title: "🌐 ক্লায়েন্টের ওয়েবসাইট URL থেকে প্রডাক্ট সিঙ্ক করুন:",
|
||
btn_close_sync: "✖ বন্ধ করুন",
|
||
sync_url_ph: "e.g. https://snehalata.com বা ক্লায়েন্টের শপ লিঙ্ক...",
|
||
sync_name_ph: "স্টোরের নাম (অপশনাল)",
|
||
btn_start_sync: "⚡ সিঙ্ক করুন ও নতুন স্টোর বক্স বানান",
|
||
btn_delete_store: "🗑️ মুছুন",
|
||
catalog_search_ph: "🔍 প্রডাক্ট বা ব্র্যান্ড খুঁজুন (e.g. Medicube, Anua, Snail, Sunscreen, Serum, Cream)...",
|
||
btn_catalog_copy: "📋 কপি",
|
||
btn_catalog_use: "⚡ ৩ডি পোস্টার",
|
||
catalog_empty: "এই স্টোরে কোনো প্রোডাক্ট পাওয়া যায়নি। অন্য কি-ওয়ার্ড বা ব্র্যান্ড সিলেক্ট করুন অথবা URL দিয়ে সিঙ্ক করুন।"
|
||
},
|
||
en: {
|
||
brand_subtitle: "Google DeepMind • Mini-App Engine",
|
||
btn_add_miniapp: "✨ + Mini-App",
|
||
lang_btn_text: "🌐 বাং",
|
||
|
||
// Poster Lab
|
||
poster_title: "3D Commercial Poster Lab",
|
||
poster_subtitle: "Generate high-converting 8K natural lifestyle ad posters with authentic products & WhatsApp QR",
|
||
theme_arch_label: "8K Natural & 3D Commercial Styles:",
|
||
theme_arch_badge: "32 Photorealistic & Commercial Styles",
|
||
theme_cat_all: "🔥 All (32)",
|
||
theme_cat_natural: "🌿 8K Natural (7)",
|
||
theme_cat_stage: "👑 3D Stages (20)",
|
||
theme_cat_grid: "🔲 Grid Layouts (5)",
|
||
poster_aspect_label: "Poster Aspect Ratio & Brand Watermark:",
|
||
poster_mode_label: "Display Mode:",
|
||
mode_single_btn: "🎯 1 Product Hero 3D Stage",
|
||
mode_multi_btn: "🔲 Multi-Product Grid View (3-4 Products)",
|
||
trends_label: "🔥 Google Trending Searches (Google Trends 1-Click Load):",
|
||
trends_badge: "Realtime BD Trends",
|
||
product_input_label: "Product Link or Name:",
|
||
open_catalog_btn: "🛍️ GT Catalog List (560+)",
|
||
product_input_ph: "e.g. Silk Saree, Smartwatch, Pure Honey, Sneaker or Skincare",
|
||
product_price_label: "Price & Discount Offer:",
|
||
product_price_ph: "e.g. ৳ 1,060 (৳ 1,470) 28% OFF",
|
||
product_badge_label: "Custom Trust Badge:",
|
||
product_badge_ph: "e.g. 🛡️ 100% Original Guarantee",
|
||
upload_photo_btn: "Upload Photo from iPhone / PC Gallery",
|
||
clear_photo_btn: "✖ Remove Photo",
|
||
photo_attached_badge: "✅ Photo Attached",
|
||
grid_layout_label: "Grid Layout Frame (Multi-Product Grid Layout):",
|
||
grid_layout_badge: "3-4 Products Collage Engine",
|
||
grid_headline_ph: "Poster Main Headline (e.g. ✨ 4-IN-1 MEGA COMBO)",
|
||
multi_combos_label: "🎁 Trending Multi-Pack Combos (1-Click Multi Combos):",
|
||
multi_combos_badge: "Full Catalog Combos",
|
||
slot1_title: "🥇 Slot 1 (Hero/Top-Left)",
|
||
slot2_title: "🥈 Slot 2 (Top-Right)",
|
||
slot3_title: "🥉 Slot 3 (Bottom-Left)",
|
||
slot4_title: "🏅 Slot 4 (Bottom-Right)",
|
||
slot_upload_btn: "Photo",
|
||
slot_placeholder_text: "Select Image",
|
||
slot_title_ph: "Product Name",
|
||
slot_price_ph: "Price",
|
||
slot_badge_ph: "Badge",
|
||
btn_generate_poster: "Generate 3D Commercial Poster (Canvas GPU)",
|
||
poster_result_title: "✨ Commercial Ad Poster Generated",
|
||
btn_save_photos: "💾 Save to Photos",
|
||
btn_whatsapp_order: "💬 WhatsApp Order",
|
||
btn_autopost_n8n: "1-Click Auto Post to Facebook Page (via n8n)",
|
||
|
||
// Mini-Apps Hub
|
||
hub_title: "✨ Opal Mini-Apps Hub",
|
||
hub_subtitle: "Build & embed bespoke AI mini-apps across all e-commerce verticals",
|
||
btn_create_app: "+ Create App",
|
||
cat_all: "🔥 All Niches",
|
||
cat_fashion: "👗 Fashion & Apparel",
|
||
cat_electronics: "📱 Tech & Gadgets",
|
||
cat_cosmetics: "💄 Beauty & Skincare",
|
||
cat_footwear: "👟 Shoes & Leather",
|
||
cat_organic: "🍯 Organic & Food",
|
||
cat_sales: "💬 Sales & Care",
|
||
cat_tools: "⚙️ AI Logistics",
|
||
cat_custom: "💎 Custom Apps",
|
||
empty_apps: "No mini-apps found in this category. Click '+ Create App' to build one!",
|
||
btn_embed: "📦 Embed",
|
||
btn_run: "⚡ Run",
|
||
|
||
// Builder
|
||
builder_title: "Visual Mini-App Builder",
|
||
builder_subtitle: "Build custom AI mini-apps for your client dashboard in a few clicks",
|
||
builder_app_name: "Mini-App Name:",
|
||
builder_app_name_ph: "e.g. VIP Customer Offer Generator",
|
||
builder_app_emoji: "App Icon / Emoji:",
|
||
builder_app_cat: "Category:",
|
||
builder_app_model: "Default AI Model:",
|
||
builder_app_desc: "Short Description:",
|
||
builder_app_desc_ph: "e.g. Generates compelling offer copy for VIP customers.",
|
||
builder_app_fields: "Input Fields for User:",
|
||
builder_field1_ph: "Field 1 Label (e.g. Customer Name / Product)",
|
||
builder_field2_ph: "Field 2 Label (e.g. Offer / Discount / Context)",
|
||
builder_prompt_template: "AI Prompt Template (with Variables):",
|
||
builder_prompt_template_ph: "You are an expert AI copywriter. Generate a high converting message based on {{field1}} and {{field2}} in natural Bangla.",
|
||
builder_hint: "💡 The variables {{field1}} and {{field2}} will automatically be replaced with user input.",
|
||
btn_save_miniapp: "💾 Save Mini-App & Add to Hub",
|
||
btn_test_miniapp: "🧪 Test Run App",
|
||
|
||
// UGC Studio
|
||
ugc_title: "UGC Video Ads & Google Flow Studio",
|
||
ugc_subtitle: "Generate high-converting UGC style prompts & scripts for Google Veo 3.1 & Omni Video engines",
|
||
ugc_presets_label: "Popular UGC Style Presets Library:",
|
||
ugc_card_unhinged_title: "Raw iPhone Review",
|
||
ugc_card_unhinged_desc: "Unfiltered real-life review & product test with front camera in cozy ambient lighting.",
|
||
ugc_card_fashion_title: "Fashion OOTD & Drape",
|
||
ugc_card_fashion_desc: "Saree / dress try-on with fabric zoom, fit overview, and graceful slow-mo walk trial.",
|
||
ugc_card_panjabi_title: "Royal Panjabi & Kabli",
|
||
ugc_card_panjabi_desc: "Premium Panjabi/Kabli showcase highlighting collar embroidery details and royal drape.",
|
||
ugc_card_gadget_title: "Gadget Sound & Stress Test",
|
||
ugc_card_gadget_desc: "Smartwatch/earbuds unboxing, active ANC sound check, and water-resistance stress test.",
|
||
ugc_card_sneaker_title: "Sneaker Flex & Kick Test",
|
||
ugc_card_sneaker_desc: "Sneaker unboxing, sole flex demonstration, and on-feet streetwear styling walkthrough.",
|
||
ugc_card_organic_title: "Organic Honey Purity Test",
|
||
ugc_card_organic_desc: "100% pure raw honey water solubility glass test and authentic taste verification.",
|
||
ugc_card_perfume_title: "Luxury Perfume 24h Test",
|
||
ugc_card_perfume_desc: "Long-lasting perfume sillage test with public compliments and genuine reactions.",
|
||
ugc_card_grwm_title: "Bathroom Mirror GRWM",
|
||
ugc_card_grwm_desc: "Morning mirror routine applying skincare drops showing lightweight texture & glass skin glow.",
|
||
ugc_card_asmr_title: "POV Unboxing ASMR",
|
||
ugc_card_asmr_desc: "POV parcel opening with crisp bubble wrap peeling and satisfying tactile sound effects.",
|
||
ugc_card_skeptic_title: "Viral Claim Skeptic",
|
||
ugc_card_skeptic_desc: "\"Does it actually work?\" — Live myth-busting and hands-on efficacy challenge.",
|
||
ugc_card_founder_title: "Founder's Direct Hook",
|
||
ugc_card_founder_desc: "Founder standing in front of shipping parcel stacks sharing authentic quality & money-back promise.",
|
||
ugc_prod_label: "Product Name & Brand:",
|
||
ugc_prod_ph: "e.g. Medicube Collagen Jelly Cream",
|
||
ugc_aud_label: "Target Audience & Pain Points:",
|
||
ugc_aud_ph: "e.g. Customers with dull skin or sun damage",
|
||
ugc_persona_label: "Creator Persona:",
|
||
ugc_duration_label: "Video Duration:",
|
||
ugc_engine_label: "AI Video Engine:",
|
||
btn_generate_ugc: "Generate Google Flow Storyboard & Master Veo Prompt",
|
||
ugc_result_title: "🎬 UGC Video Ad Storyboard & Master Prompt",
|
||
ugc_master_prompt_label: "🎯 Master Cinematic AI Prompt for Veo 3.1 (English Prompt):",
|
||
btn_copy_master_prompt: "📋 Copy Master Prompt for Veo 3.1",
|
||
ugc_timeline_label: "⏱️ Google Flow Shot-by-Shot Timeline (Storyboard & Dialogue):",
|
||
btn_copy_complete_flow: "📋 Copy Complete Flow",
|
||
btn_send_veo: "🚀 Send to Aura Veo 3.1 Engine",
|
||
|
||
// CGI Studio
|
||
cgi_title: "3D CGI Master Prompt Studio & Catalog Library",
|
||
cgi_subtitle: "8K Ultra-realistic commercial studio prompt library for GT & all brands",
|
||
cgi_cat_all: "🔥 All Stores",
|
||
cgi_search_ph: "🔍 Search product or ingredient (e.g. Collagen, Retinol, Silk, Smartwatch, Honey)...",
|
||
btn_cgi_copy: "📋 Copy Prompt",
|
||
btn_cgi_use: "🎨 Open in 3D Lab",
|
||
cgi_empty: "No prompts found. Try searching with another keyword or category.",
|
||
|
||
// Inbox AI
|
||
inbox_title: "Omnichannel Customer Care & Sales Closer AI",
|
||
inbox_subtitle: "1-Click generation of 3 sweet & high-converting sales replies from customer queries",
|
||
inbox_query_label: "Customer Inbox Query:",
|
||
inbox_query_ph: "e.g. Do you have Korean glass skin serum? What is the price and delivery fee?",
|
||
inbox_store_label: "Store Info & Policies:",
|
||
inbox_store_ph: "Store: Glamour's Touch (glamourstouch.com), Hotline: 01712-426871...",
|
||
btn_generate_inbox: "Generate 3 Ready-to-Send Replies with Gemini AI",
|
||
reply1_header: "⚡ 1. Instant Polite Greeting & Price",
|
||
reply2_header: "🛍️ 2. Direct Order Closer & Address",
|
||
reply3_header: "💬 3. 1-Click WhatsApp Direct Closer",
|
||
btn_copy: "📋 Copy",
|
||
|
||
// History
|
||
history_title: "📜 Saved Generation History",
|
||
btn_clear_history: "Clear All",
|
||
history_empty: "No generations yet. Create your first 3D poster or mini-app generation!",
|
||
|
||
// Settings
|
||
settings_title: "Settings & Google AI Configuration",
|
||
settings_subtitle: "Google Gemini 2.0 & Gemma Open-Weights Configuration",
|
||
settings_apikey_label: "Google Gemini API Key (100% Free from AI Studio):",
|
||
settings_apikey_ph: "Paste your AI Studio API key (AIzaSy...)",
|
||
settings_apikey_hint: "API Key is saved securely in your browser/device local storage.",
|
||
settings_model_label: "Default AI Model:",
|
||
settings_webhook_label: "n8n Auto-Post Webhook URL (Aura Ajentic AI):",
|
||
settings_webhook_hint: "Pre-configured with your n8n cloud instance at n8n.auraajenticai.cloud",
|
||
btn_save_settings: "💾 Save Settings & Test Connection",
|
||
about_title: "💎 About Google Opal AI (iOS Edition)",
|
||
about_desc: "This web studio is engineered specifically for iPhone (iOS Safari / PWA) and client dashboards with 0ms latency, native 2D canvas GPU rendering, and official Google Gemini 2.0 AI integration.",
|
||
iphone_tips: "📲 iPhone Tip: Tap the Share (📤) button at the bottom of Safari and select 'Add to Home Screen' for a full-screen native app experience on your iPhone!",
|
||
|
||
// Bottom Navigation
|
||
nav_apps: "Apps Hub",
|
||
nav_poster: "3D Poster",
|
||
nav_cgi: "CGI Prompts",
|
||
nav_ugc: "UGC Studio",
|
||
nav_builder: "App Maker",
|
||
nav_inbox: "Inbox AI",
|
||
nav_settings: "Settings",
|
||
|
||
// Modals
|
||
runner_modal_title: "🚀 Mini-App Runner",
|
||
btn_runner_generate: "⚡ Generate with AI",
|
||
runner_output_title: "✨ Generated Output",
|
||
embed_modal_title: "📦 Embed in Client Dashboard",
|
||
embed_modal_desc: "To embed this mini-app into your client dashboard (e.g. aura client dashboard), copy the snippet below:",
|
||
embed_iframe_label: "HTML / Iframe Embed Snippet:",
|
||
btn_copy_iframe: "📋 Copy Iframe Code",
|
||
embed_api_label: "Direct Webhook / API URL:",
|
||
btn_copy_api: "📋 Copy Direct API URL",
|
||
catalog_modal_title: "Universal E-Commerce Catalog & Store Sync",
|
||
catalog_count_default: "560+ Authentic Products Library",
|
||
btn_sync_new_store: "Sync New Client Store",
|
||
sync_panel_title: "🌐 Sync Products from Client Website URL:",
|
||
btn_close_sync: "✖ Close",
|
||
sync_url_ph: "e.g. https://snehalata.com or client shop link...",
|
||
sync_name_ph: "Store Name (Optional)",
|
||
btn_start_sync: "⚡ Sync & Create Store Box",
|
||
btn_delete_store: "🗑️ Delete",
|
||
catalog_search_ph: "🔍 Search product or brand (e.g. Medicube, Anua, Snail, Sunscreen, Serum, Cream)...",
|
||
btn_catalog_copy: "📋 Copy",
|
||
btn_catalog_use: "⚡ 3D Poster",
|
||
catalog_empty: "No products found in this store. Try searching another keyword or brand, or sync via URL."
|
||
}
|
||
};
|
||
|
||
window.currentLang = localStorage.getItem('opal_lang') || 'bn';
|
||
|
||
window.applyLanguage = function(lang) {
|
||
window.currentLang = lang;
|
||
localStorage.setItem('opal_lang', lang);
|
||
const dict = I18N_DICTIONARY[lang] || I18N_DICTIONARY.bn;
|
||
|
||
// 1. Text elements
|
||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||
const key = el.getAttribute('data-i18n');
|
||
if (dict[key]) {
|
||
el.textContent = dict[key];
|
||
}
|
||
});
|
||
|
||
// 2. Placeholder elements
|
||
document.querySelectorAll('[data-i18n-ph]').forEach(el => {
|
||
const key = el.getAttribute('data-i18n-ph');
|
||
if (dict[key]) {
|
||
el.setAttribute('placeholder', dict[key]);
|
||
}
|
||
});
|
||
|
||
// 3. Title attributes
|
||
document.querySelectorAll('[data-i18n-title]').forEach(el => {
|
||
const key = el.getAttribute('data-i18n-title');
|
||
if (dict[key]) {
|
||
el.setAttribute('title', dict[key]);
|
||
}
|
||
});
|
||
|
||
// 4. Update language toggle button text
|
||
const langBtn = document.getElementById('langToggleBtn');
|
||
if (langBtn) {
|
||
langBtn.textContent = dict.lang_btn_text || (lang === 'bn' ? '🌐 EN' : '🌐 বাং');
|
||
}
|
||
|
||
// 5. Update Select Options
|
||
const gridLayoutSelect = document.getElementById('gridLayoutSelect');
|
||
if (gridLayoutSelect && gridLayoutSelect.options.length >= 4) {
|
||
if (lang === 'bn') {
|
||
gridLayoutSelect.options[0].text = "🔲 2x2 Quad Grid (৪টি প্রোডাক্ট সমান গ্রিড)";
|
||
gridLayoutSelect.options[1].text = "🏆 1 Hero + 3 Side Cards (১টি বড় + ৩টি ছোট বেন্টো)";
|
||
gridLayoutSelect.options[2].text = "🥉 1 Hero + 2 Companion (৩টি প্রোডাক্ট ট্রায়ো গ্রিড)";
|
||
gridLayoutSelect.options[3].text = "🎞️ 3-Panel Lookbook Strip (৩টি ভার্টিক্যাল কলাম)";
|
||
} else {
|
||
gridLayoutSelect.options[0].text = "🔲 2x2 Quad Grid (4 Equal Products)";
|
||
gridLayoutSelect.options[1].text = "🏆 1 Hero + 3 Side Cards (1 Hero + 3 Bento)";
|
||
gridLayoutSelect.options[2].text = "🥉 1 Hero + 2 Companion (3-Product Trio Grid)";
|
||
gridLayoutSelect.options[3].text = "🎞️ 3-Panel Lookbook Strip (3 Vertical Columns)";
|
||
}
|
||
}
|
||
|
||
// 6. Refresh Dynamic Renderers
|
||
if (typeof renderMiniApps === 'function') renderMiniApps();
|
||
if (typeof renderCgiCards === 'function') renderCgiCards();
|
||
if (typeof renderCatalogGrid === 'function') renderCatalogGrid();
|
||
if (typeof renderHistory === 'function') renderHistory();
|
||
};
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
initNavigation();
|
||
initSettings();
|
||
initCatalogBrowser();
|
||
initPosterLab();
|
||
initCgiLibrary();
|
||
initMiniAppsHub();
|
||
initMiniAppBuilder();
|
||
initUgcStudio();
|
||
initInboxAI();
|
||
initHistory();
|
||
|
||
// Apply active language across DOM on load
|
||
window.applyLanguage(window.currentLang);
|
||
});
|
||
|
||
// --- 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');
|
||
if (langBtn) {
|
||
langBtn.addEventListener('click', () => {
|
||
const nextLang = window.currentLang === 'bn' ? 'en' : 'bn';
|
||
window.applyLanguage(nextLang);
|
||
});
|
||
}
|
||
}
|
||
|
||
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}`;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// --- Google Gemini 2.0 / Gemma Quota-Optimized API Client ---
|
||
const GEMINI_CACHE = new Map();
|
||
|
||
function getCachedPromptResult(cacheKey) {
|
||
if (GEMINI_CACHE.has(cacheKey)) {
|
||
return GEMINI_CACHE.get(cacheKey);
|
||
}
|
||
try {
|
||
const stored = sessionStorage.getItem(`opal_cache_${cacheKey}`);
|
||
if (stored) {
|
||
const parsed = JSON.parse(stored);
|
||
if (Date.now() - parsed.ts < 1000 * 60 * 60 * 2) { // 2 hour cache
|
||
GEMINI_CACHE.set(cacheKey, parsed.data);
|
||
return parsed.data;
|
||
}
|
||
}
|
||
} catch (e) {}
|
||
return null;
|
||
}
|
||
|
||
function setCachedPromptResult(cacheKey, data) {
|
||
GEMINI_CACHE.set(cacheKey, data);
|
||
try {
|
||
sessionStorage.setItem(`opal_cache_${cacheKey}`, JSON.stringify({ ts: Date.now(), data }));
|
||
} catch (e) {}
|
||
}
|
||
|
||
async function callGeminiApi(apiKey, model, prompt, retries = 2) {
|
||
if (!apiKey) {
|
||
throw new Error("API Key is missing. Please configure your Google Gemini API Key in Settings.");
|
||
}
|
||
|
||
// Generate lightweight hash for cache (0 tokens consumed on repeat queries)
|
||
const cacheKey = btoa(unescape(encodeURIComponent((model || 'gemini') + ':' + prompt.trim()))).slice(0, 48);
|
||
const cached = getCachedPromptResult(cacheKey);
|
||
if (cached) {
|
||
return cached;
|
||
}
|
||
|
||
const modelHierarchy = [
|
||
model || localStorage.getItem('opal_selected_model') || 'gemini-2.0-flash',
|
||
'gemini-1.5-flash',
|
||
'gemma-2-27b-it'
|
||
];
|
||
|
||
let lastError = null;
|
||
|
||
for (const currentModel of modelHierarchy) {
|
||
for (let attempt = 0; attempt <= retries; attempt++) {
|
||
try {
|
||
const url = `https://generativelanguage.googleapis.com/v1beta/models/${currentModel}:generateContent?key=${apiKey}`;
|
||
const payload = {
|
||
contents: [{ parts: [{ text: prompt.trim() }] }],
|
||
generationConfig: {
|
||
temperature: 0.65,
|
||
maxOutputTokens: 1024,
|
||
topK: 40,
|
||
topP: 0.92
|
||
}
|
||
};
|
||
|
||
const response = await fetch(url, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(payload)
|
||
});
|
||
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
const text = data?.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
||
if (text) {
|
||
setCachedPromptResult(cacheKey, text);
|
||
return text;
|
||
}
|
||
}
|
||
|
||
const status = response.status;
|
||
const errData = await response.json().catch(() => ({}));
|
||
const errMsg = errData?.error?.message || `HTTP ${status}`;
|
||
|
||
// If rate limited (429) or server busy (503), wait with exponential backoff & failover
|
||
if (status === 429 || status === 503) {
|
||
lastError = new Error(`Quota limit reached on ${currentModel}. Retrying with model failover...`);
|
||
if (attempt < retries) {
|
||
const delay = (attempt + 1) * 1200 + Math.random() * 400;
|
||
await new Promise(r => setTimeout(r, delay));
|
||
continue;
|
||
}
|
||
break; // Move to next model in hierarchy
|
||
} else {
|
||
throw new Error(errMsg);
|
||
}
|
||
} catch (err) {
|
||
lastError = err;
|
||
if (attempt === retries) break;
|
||
await new Promise(r => setTimeout(r, 1000));
|
||
}
|
||
}
|
||
}
|
||
|
||
throw lastError || new Error("Failed to generate response after trying available AI models.");
|
||
}
|
||
|
||
// --- Curated Pre-Built Mini-Apps Suite (Universal E-Commerce) ---
|
||
const PREBUILT_MINI_APPS = [
|
||
{
|
||
id: 'gt_studio',
|
||
name: '3D Commercial Poster Lab',
|
||
nameEn: '3D Commercial Poster Lab',
|
||
emoji: '🎨',
|
||
category: 'ecommerce',
|
||
badge: '3D CANVAS',
|
||
desc: 'যেকোনো পণ্যের ছবি, ৩ডি মার্বেল স্টেজ ও WhatsApp QR সহ 4K বিজ্ঞাপন পোস্টার তৈরি করে।',
|
||
descEn: 'Generates 4K commercial ad posters with marble stage, product render & WhatsApp QR.',
|
||
steps: 'All Niches • 3D Canvas',
|
||
isPosterLab: true
|
||
},
|
||
{
|
||
id: 'fashion_stylist',
|
||
name: 'Fashion, Saree & Panjabi Styling Closer',
|
||
nameEn: 'Fashion, Saree & Panjabi Styling Closer',
|
||
emoji: '👗',
|
||
category: 'fashion',
|
||
badge: 'FASHION',
|
||
desc: 'শাড়ি, থ্রি-পিস, পাঞ্জাবি বা হুডির ফেব্রিক ডিটেইলস, সাইজ গাইড ও ম্যাচিং টিপস দিয়ে সেলস ক্লোজ করে।',
|
||
descEn: 'Closes fashion sales with fabric softness, size charts, drape advice & COD booking.',
|
||
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',
|
||
nameEn: 'Royal Panjabi & Kabli Styling Studio',
|
||
emoji: '👑',
|
||
category: 'fashion',
|
||
badge: 'ROYAL PANJABI',
|
||
desc: 'প্রিমিয়াম ডিজাইনার পাঞ্জাবি, কাবলি সেট ও কাতান/সিল্কের ফেব্রিক ডিটেইলস, সাইজ গাইড ও অকেশনের সেলস ক্লোজ করে।',
|
||
descEn: 'Showcases luxury panjabi & kabli craftsmanship, fit guarantee and festive styling.',
|
||
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',
|
||
nameEn: 'Smart Gadget & Electronics Feature Explainer',
|
||
emoji: '⚡',
|
||
category: 'electronics',
|
||
badge: 'GADGETS',
|
||
desc: 'স্মার্টওয়াচ, ইয়ারবাডস ও গ্যাজেটের ব্যাটারি লাইফ, ডিসপ্লে ও ১ বছরের ওয়ারেন্টি বুঝিয়ে সেলস আনে।',
|
||
descEn: 'Explains specs, AMOLED displays, battery life & 1-year replacement warranty.',
|
||
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',
|
||
nameEn: 'Pure Organic Food & Honey Authenticity AI',
|
||
emoji: '🍯',
|
||
category: 'organic',
|
||
badge: 'ORGANIC',
|
||
desc: 'সুন্দরবনের খাঁটি মধু, সরিষার তেল ও ঘিয়ের ১০০% নির্ভেজাল প্রমাণ ও স্বাস্থ্য উপকারিতা জানায়।',
|
||
descEn: 'Verifies pure raw honey, mustard oil & organic ghee lab tests and health benefits.',
|
||
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',
|
||
nameEn: 'Sneaker Legit Check & Footwear Closer',
|
||
emoji: '👟',
|
||
category: 'footwear',
|
||
badge: 'SNEAKERS',
|
||
desc: 'স্নিকার, লোফার ও চামড়ার জুতার প্রিমিয়াম কোয়ালিটি, কুশন কমফোর্ট ও সাইজ ট্রায়াল বুঝায়।',
|
||
descEn: 'Highlights footwear build, memory foam cushioning, street styling & doorstep trial.',
|
||
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',
|
||
nameEn: 'Customer Care & Universal Sales Closer',
|
||
emoji: '💬',
|
||
category: 'sales',
|
||
badge: 'AI CLOSER',
|
||
desc: 'ফেসবুক ও হোয়াটসঅ্যাপের কাস্টমারের প্রশ্নের ৩টি ইনস্ট্যান্ট মিষ্টি ও সেলস ক্লোজিং উত্তর বানায়।',
|
||
descEn: 'Creates 3 sweet and polite sales closer responses from any customer inbox query.',
|
||
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',
|
||
nameEn: 'Google Veo 3.1 & Omni Video Prompter',
|
||
emoji: '🎬',
|
||
category: 'social',
|
||
badge: 'VEO 3.1',
|
||
desc: 'সকল ক্যাটাগরির পণ্যের জন্য সিনেমাটিক 9:16 ভিডিও প্রম্পট, ক্যামেরা মোশন ও লাইটিং গাইড বানায়।',
|
||
descEn: 'Engineers 9:16 vertical photorealistic video prompts and camera movements for Veo 3.1.',
|
||
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',
|
||
nameEn: 'Gemini COD Fraud & Return Risk Shield',
|
||
emoji: '🛡️',
|
||
category: 'tools',
|
||
badge: 'AI SHIELD',
|
||
desc: 'কাস্টমারের ফোন নাম্বার, ঠিকানা ও অর্ডারের পরিমাণ বিশ্লেষণ করে রিটার্ন ফ্রড রিস্ক স্কোর দেয়।',
|
||
descEn: 'Analyzes phone numbers, addresses & order sizes to predict return & fraud risk.',
|
||
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',
|
||
nameEn: 'E-Commerce Viral Product Launch Kit',
|
||
emoji: '🛍️',
|
||
category: 'ecommerce',
|
||
badge: 'VIRAL',
|
||
desc: 'যেকোনো পণ্যের আকর্ষণীয় ফেসবুক পোস্ট ক্যাপশন, পেইন পয়েন্ট হুক ও অফার কপি তৈরি করে।',
|
||
descEn: 'Crafts Facebook viral ad copy, high-converting pain point hooks & discount offers.',
|
||
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',
|
||
nameEn: 'TikTok & Meta Reels Viral Hook Matrix',
|
||
emoji: '🔥',
|
||
category: 'social',
|
||
badge: 'HOOKS',
|
||
desc: 'প্রথম ৩ সেকেন্ডে কাস্টমারের চোখ আটকে ফেলার মতো ৫টি সাইকোলজিক্যাল ভাইরাল হুক তৈরি করে।',
|
||
descEn: 'Generates 5 psychological 3-second visual and audio hooks for TikTok & Reels.',
|
||
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',
|
||
nameEn: 'Flash Sale & Urgency Campaign Copywriter',
|
||
emoji: '🏷️',
|
||
category: 'sales',
|
||
badge: 'OFFER',
|
||
desc: '২৪ ঘণ্টার ফ্ল্যাশ সেল, স্টক ক্লিয়ারেন্স ও ঈদ/বৈশাখী অফারের হাই-কনভার্টিং কপি বানায়।',
|
||
descEn: 'Produces high-urgency FOMO copy for flash sales, weekend clearances & festival deals.',
|
||
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',
|
||
nameEn: 'Steadfast & Pathao Consignment Formatter',
|
||
emoji: '📦',
|
||
category: 'tools',
|
||
badge: 'LOGISTICS',
|
||
desc: 'অর্ডারের টেক্সট থেকে ১-ক্লিকে কুরিয়ার এন্ট্রি ফরম্যাট ও প্রিন্ট লেবেল তৈরি করে।',
|
||
descEn: 'Parses raw customer chat text into structured Steadfast/Pathao courier parcel labels.',
|
||
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 dict = I18N_DICTIONARY[window.currentLang] || I18N_DICTIONARY.bn;
|
||
const isEn = window.currentLang === 'en';
|
||
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>${dict.empty_apps || '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>${(isEn && app.nameEn) ? app.nameEn : app.name}</h3>
|
||
<p>${(isEn && app.descEn) ? app.descEn : (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">
|
||
${dict.btn_embed || '📦 Embed'}
|
||
</button>
|
||
<button class="btn-embed-chip" onclick="openAppRunner('${app.id}')" style="background: rgba(139, 92, 246, 0.2); color: #C084FC;">
|
||
${dict.btn_run || '⚡ 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 & dynamic store metadata
|
||
const inputs = document.querySelectorAll('.runner-input');
|
||
const selectedBrandKey = document.getElementById('brandWatermarkSelect')?.value || 'glamourstouch';
|
||
const activeBrand = getBrandProfile(selectedBrandKey);
|
||
const cleanPhone = (activeBrand.footerHotline || '01712-426871').replace(/\D/g, '');
|
||
const dynamicWaLink = `https://wa.me/88${cleanPhone}`;
|
||
|
||
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);
|
||
});
|
||
|
||
// Dynamically replace store tokens
|
||
prompt = prompt.replace(/{{brand_hotline}}/g, activeBrand.footerHotline);
|
||
prompt = prompt.replace(/{{brand_site}}/g, activeBrand.footerSite);
|
||
prompt = prompt.replace(/{{brand_name}}/g, activeBrand.headerTitle);
|
||
prompt = prompt.replace(/{{wa_link}}/g, dynamicWaLink);
|
||
prompt = prompt.replace(/https:\/\/wa\.me\/8801712426871/g, dynamicWaLink);
|
||
|
||
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` +
|
||
`৩. সরাসরি WhatsApp এ অর্ডার করতে ক্লিক করুন: ${dynamicWaLink}\n` +
|
||
`📞 হটলাইন: ${activeBrand.footerHotline} | 🌐 ওয়েবসাইট: https://${activeBrand.footerSite}\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';
|
||
let currentPosterMode = 'single'; // 'single' or 'multi_grid'
|
||
let slotAttachedBitmaps = [null, null, null, null];
|
||
|
||
const MULTI_COMBOS = {
|
||
kbeauty_4: {
|
||
brand: 'glamourstouch',
|
||
theme: 'bento_grid_luxe',
|
||
headline: '🌸 4-STEP K-BEAUTY GLASS SKIN ROUTINE',
|
||
layout: '2x2_quad',
|
||
items: [
|
||
{ title: 'Medicube Collagen Jelly Cream', price: '৳ ১,০৬০', badge: '🛡️ 100% Authentic Korean' },
|
||
{ title: 'Anua Heartleaf 77% Soothing Toner', price: '৳ ১,৪৮০', badge: '🌿 77% Soothing Care' },
|
||
{ title: 'COSRX Snail 96 Mucin Essence', price: '৳ ১,৩৫০', badge: '🐌 96% Mucin Recovery' },
|
||
{ title: 'Beauty of Joseon Sun Relief SPF50+', price: '৳ ১,১৫০', badge: '☀️ Rice + Probiotics Sun' }
|
||
]
|
||
},
|
||
panjabi_3: {
|
||
brand: 'panjabi',
|
||
theme: 'mughal_heritage',
|
||
headline: '👑 ROYAL FESTIVE COUTURE 3-PIECE TRIO',
|
||
layout: '1_hero_2_trio',
|
||
items: [
|
||
{ title: 'Aura Royal Platinum Silk Panjabi', price: '৳ ২,৪৫০', badge: '👑 100% Pre-Shrunk Weave' },
|
||
{ title: 'Aura Imperial Navy Kabli Set', price: '৳ ২,৮৫০', badge: '💎 Metallic Snap Buttons' },
|
||
{ title: 'Aura Velvet Maroon Panjabi', price: '৳ ৩,২০০', badge: '✨ Hand Zari Embroidery' },
|
||
{ title: 'Aura Classic Jacquard Panjabi', price: '৳ ২,১০০', badge: '🧵 Pure Silk Jacquard' }
|
||
]
|
||
},
|
||
tech_3: {
|
||
brand: 'techvolt',
|
||
theme: 'blueprint_cad_grid',
|
||
headline: '⚡ TECHVOLT SMART ECOSYSTEM TRIO',
|
||
layout: '1_hero_3_bento',
|
||
items: [
|
||
{ title: 'T900 Ultra Smartwatch Series 9', price: '৳ ১,৬৫০', badge: '⚡ 1 Year Official Warranty' },
|
||
{ title: 'SonicPulse ANC Studio Earbuds', price: '৳ ১,৯৫০', badge: '🔋 40h Studio Playtime' },
|
||
{ title: '65W GaN Magnetic Fast Powerbank', price: '৳ ১,২৫০', badge: '🚀 65W Turbo Charging' },
|
||
{ title: 'MagSafe Wireless Charging Pad', price: '৳ ৮৫০', badge: '🛡️ Qi Fast Certified' }
|
||
]
|
||
},
|
||
organic_3: {
|
||
brand: 'organic',
|
||
theme: 'botanical_eco',
|
||
headline: '🍯 PRANON 100% ORGANIC NATURE TRIO',
|
||
layout: '1_hero_2_trio',
|
||
items: [
|
||
{ title: 'Sundarban Pure Raw Khalsi Honey 1kg', price: '৳ ১,২৫০', badge: '🍯 100% Pure Lab Tested' },
|
||
{ title: 'Traditional Wood-Ghani Mustard Oil 1L', price: '৳ ৪৫০', badge: '🌿 Cold Pressed Purity' },
|
||
{ title: 'Aromas Pure Organic Cow Ghee 500g', price: '৳ ৯৫০', badge: '🐄 100% Grass-Fed Ghee' },
|
||
{ title: 'Natural Organic Wild Flower Honey', price: '৳ ৯৯০', badge: '🌺 Raw Forest Honey' }
|
||
]
|
||
},
|
||
sneaker_4: {
|
||
brand: 'sneakerlab',
|
||
theme: 'brutalist_street',
|
||
headline: '👟 SNEAKERLAB STREETWEAR 4-PACK',
|
||
layout: '2x2_quad',
|
||
items: [
|
||
{ title: 'StreetFire Retro High OG Kicks', price: '৳ ২,৮৫০', badge: '👟 Memory Foam Cushion' },
|
||
{ title: 'Pure Cowhide Leather Loafer', price: '৳ ৩,৪৫০', badge: '👞 100% Genuine Leather' },
|
||
{ title: 'Air Cushion Streetwear Sneaker 2026', price: '৳ ২,৪৫০', badge: '⚡ Air Bubble Shock Absorb' },
|
||
{ title: 'Urban Stealth Low-Top Canvas', price: '৳ ১,৯৫০', badge: '🔥 Vulcanized Street Sole' }
|
||
]
|
||
}
|
||
};
|
||
|
||
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');
|
||
|
||
// Mode Switcher Elements
|
||
const modeSingleBtn = document.getElementById('modeSingleBtn');
|
||
const modeMultiBtn = document.getElementById('modeMultiBtn');
|
||
const singleForm = document.getElementById('singleProductFormContainer');
|
||
const multiForm = document.getElementById('multiProductFormContainer');
|
||
const gridLayoutSelect = document.getElementById('gridLayoutSelect');
|
||
const gridMainHeadlineInput = document.getElementById('gridMainHeadlineInput');
|
||
|
||
if (modeSingleBtn && modeMultiBtn) {
|
||
modeSingleBtn.addEventListener('click', () => {
|
||
modeSingleBtn.classList.add('active');
|
||
modeMultiBtn.classList.remove('active');
|
||
currentPosterMode = 'single';
|
||
if (singleForm) singleForm.classList.remove('hidden');
|
||
if (multiForm) multiForm.classList.add('hidden');
|
||
});
|
||
|
||
modeMultiBtn.addEventListener('click', () => {
|
||
modeMultiBtn.classList.add('active');
|
||
modeSingleBtn.classList.remove('active');
|
||
currentPosterMode = 'multi_grid';
|
||
if (singleForm) singleForm.classList.add('hidden');
|
||
if (multiForm) multiForm.classList.remove('hidden');
|
||
});
|
||
}
|
||
|
||
// Grid Layout Change
|
||
if (gridLayoutSelect) {
|
||
gridLayoutSelect.addEventListener('change', () => {
|
||
const val = gridLayoutSelect.value;
|
||
const slot4 = document.getElementById('slotCard4');
|
||
if (slot4) {
|
||
if (val === '1_hero_2_trio' || val === '3_panel_strip') {
|
||
slot4.style.opacity = '0.5';
|
||
} else {
|
||
slot4.style.opacity = '1';
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// Multi-Combo Chips
|
||
const multiComboChips = document.querySelectorAll('#multiComboChips .trend-chip');
|
||
multiComboChips.forEach(chip => {
|
||
chip.addEventListener('click', () => {
|
||
multiComboChips.forEach(c => c.classList.remove('active'));
|
||
chip.classList.add('active');
|
||
const comboKey = chip.getAttribute('data-combo');
|
||
const combo = MULTI_COMBOS[comboKey];
|
||
if (combo) {
|
||
if (brandSelect && combo.brand) brandSelect.value = combo.brand;
|
||
if (gridMainHeadlineInput) gridMainHeadlineInput.value = combo.headline;
|
||
if (gridLayoutSelect && combo.layout) {
|
||
gridLayoutSelect.value = combo.layout;
|
||
gridLayoutSelect.dispatchEvent(new Event('change'));
|
||
}
|
||
|
||
// Set active theme chip
|
||
if (combo.theme) {
|
||
selectedStageTheme = combo.theme;
|
||
document.querySelectorAll('#themeSelectorGroup .theme-chip').forEach(tc => {
|
||
if (tc.getAttribute('data-theme') === combo.theme) {
|
||
tc.classList.add('active');
|
||
} else {
|
||
tc.classList.remove('active');
|
||
}
|
||
});
|
||
}
|
||
|
||
// Fill slots
|
||
combo.items.forEach((item, idx) => {
|
||
const sNum = idx + 1;
|
||
const tInput = document.getElementById(`slotTitle${sNum}`);
|
||
const pInput = document.getElementById(`slotPrice${sNum}`);
|
||
const bInput = document.getElementById(`slotBadge${sNum}`);
|
||
if (tInput) tInput.value = item.title;
|
||
if (pInput) pInput.value = item.price;
|
||
if (bInput) bInput.value = item.badge;
|
||
});
|
||
}
|
||
});
|
||
});
|
||
|
||
// Slot File Upload Listeners (Slots 1 to 4)
|
||
for (let s = 1; s <= 4; s++) {
|
||
const sIdx = s - 1;
|
||
const fileInput = document.getElementById(`slotFile${s}`);
|
||
const imgEl = document.getElementById(`slotImg${s}`);
|
||
const placeholder = document.getElementById(`slotPlaceholder${s}`);
|
||
|
||
if (fileInput) {
|
||
fileInput.addEventListener('change', (e) => {
|
||
const file = e.target.files[0];
|
||
if (file) {
|
||
const reader = new FileReader();
|
||
reader.onload = (event) => {
|
||
if (imgEl) {
|
||
imgEl.src = event.target.result;
|
||
imgEl.classList.remove('hidden');
|
||
}
|
||
if (placeholder) placeholder.classList.add('hidden');
|
||
|
||
const img = new Image();
|
||
img.onload = () => { slotAttachedBitmaps[sIdx] = img; };
|
||
img.src = event.target.result;
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// Stage Theme Category Filter Bar
|
||
const themeCategoryFilterChips = document.querySelectorAll('#themeCategoryFilter .filter-chip');
|
||
themeCategoryFilterChips.forEach(chip => {
|
||
chip.addEventListener('click', () => {
|
||
themeCategoryFilterChips.forEach(c => c.classList.remove('active'));
|
||
chip.classList.add('active');
|
||
const filterCat = chip.getAttribute('data-filter');
|
||
document.querySelectorAll('#themeSelectorGroup .theme-chip').forEach(tc => {
|
||
if (filterCat === 'all' || tc.getAttribute('data-category') === filterCat) {
|
||
tc.style.display = 'flex';
|
||
} else {
|
||
tc.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
// 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');
|
||
const themeBadgeEl = document.getElementById('posterThemeBadge');
|
||
if (themeBadgeEl && THEMES[selectedStageTheme]) {
|
||
themeBadgeEl.textContent = THEMES[selectedStageTheme].name;
|
||
}
|
||
});
|
||
});
|
||
|
||
// Trending Google Search Chips (1-Click Auto Fill)
|
||
const trendChips = document.querySelectorAll('#trendingPosterChips .trend-chip');
|
||
trendChips.forEach(chip => {
|
||
chip.addEventListener('click', () => {
|
||
trendChips.forEach(c => c.classList.remove('active'));
|
||
chip.classList.add('active');
|
||
|
||
const brand = chip.getAttribute('data-brand');
|
||
const title = chip.getAttribute('data-title');
|
||
const price = chip.getAttribute('data-price');
|
||
const badge = chip.getAttribute('data-badge');
|
||
|
||
if (brand && brandSelect) brandSelect.value = brand;
|
||
if (title && productInput) productInput.value = title;
|
||
if (price && productPrice) productPrice.value = price;
|
||
if (badge && customBadgeInput) customBadgeInput.value = badge;
|
||
});
|
||
});
|
||
|
||
let attachedImageBitmap = null;
|
||
|
||
// Photo Input change
|
||
if (photoFileInput) {
|
||
photoFileInput.addEventListener('change', (e) => {
|
||
const file = e.target.files[0];
|
||
if (file) {
|
||
const reader = new FileReader();
|
||
reader.onload = (event) => {
|
||
if (attachedPhotoImg) attachedPhotoImg.src = event.target.result;
|
||
if (photoPreviewContainer) photoPreviewContainer.classList.remove('hidden');
|
||
if (clearPhotoBtn) clearPhotoBtn.classList.remove('hidden');
|
||
|
||
const img = new Image();
|
||
img.onload = () => { attachedImageBitmap = img; };
|
||
img.src = event.target.result;
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
});
|
||
}
|
||
|
||
if (clearPhotoBtn) {
|
||
clearPhotoBtn.addEventListener('click', () => {
|
||
if (photoFileInput) photoFileInput.value = '';
|
||
attachedImageBitmap = null;
|
||
if (photoPreviewContainer) photoPreviewContainer.classList.add('hidden');
|
||
if (clearPhotoBtn) clearPhotoBtn.classList.add('hidden');
|
||
});
|
||
}
|
||
|
||
// Generate Poster (Unified Handler)
|
||
generatePosterBtn.addEventListener('click', async () => {
|
||
const aspect = aspectRatioSelect ? aspectRatioSelect.value : '1:1';
|
||
const brand = brandSelect ? brandSelect.value : 'glamourstouch';
|
||
const brandObj = getBrandProfile(brand);
|
||
|
||
posterStatusText.classList.remove('hidden');
|
||
posterStatusText.style.color = '#F59E0B';
|
||
posterStatusText.textContent = '⏳ Rendering 3D stage with GPU canvas blend...';
|
||
generatePosterBtn.disabled = true;
|
||
|
||
try {
|
||
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');
|
||
}
|
||
|
||
if (currentPosterMode === 'multi_grid') {
|
||
// --- MULTI-PRODUCT GRID RENDERING ---
|
||
const layout = gridLayoutSelect ? gridLayoutSelect.value : '2x2_quad';
|
||
const headline = gridMainHeadlineInput ? gridMainHeadlineInput.value.trim() : '✨ 4-IN-1 MEGA COMBO ROUTINE';
|
||
|
||
const productsList = [];
|
||
for (let s = 1; s <= 4; s++) {
|
||
const sIdx = s - 1;
|
||
const tInput = document.getElementById(`slotTitle${s}`);
|
||
const pInput = document.getElementById(`slotPrice${s}`);
|
||
const bInput = document.getElementById(`slotBadge${s}`);
|
||
|
||
const title = (tInput ? tInput.value.trim() : '') || `Product ${s}`;
|
||
const price = (pInput ? pInput.value.trim() : '') || '৳ ১,০৬০';
|
||
const badge = (bInput ? bInput.value.trim() : '') || '🛡️ 100% Original';
|
||
|
||
let pImg = slotAttachedBitmaps[sIdx];
|
||
if (!pImg) {
|
||
const resolved = await resolveProductUrl(title, brandObj.category || brand);
|
||
if (resolved && resolved.imageUrl) {
|
||
pImg = await loadImage(resolved.imageUrl, brandObj.category, brand, title);
|
||
} else {
|
||
pImg = await loadImage(null, brandObj.category, brand, title);
|
||
}
|
||
}
|
||
|
||
productsList.push({ title, price, badge, img: pImg });
|
||
}
|
||
|
||
await renderMultiProductGridPoster(posterCanvas, productsList, layout, headline, selectedStageTheme, aspect, brand);
|
||
|
||
const themeBadgeEl = document.getElementById('posterThemeBadge');
|
||
if (themeBadgeEl && THEMES[selectedStageTheme]) {
|
||
themeBadgeEl.textContent = THEMES[selectedStageTheme].name;
|
||
}
|
||
|
||
posterResultCard.classList.remove('hidden');
|
||
posterStatusText.classList.add('hidden');
|
||
posterResultCard.scrollIntoView({ behavior: 'smooth' });
|
||
|
||
saveGenerationToHistory({
|
||
type: '3D Multi-Product Grid Poster',
|
||
title: headline,
|
||
price: `${productsList.length} Items Bundle`,
|
||
date: new Date().toLocaleTimeString()
|
||
});
|
||
|
||
} else {
|
||
// --- SINGLE PRODUCT HERO 3D POSTER ---
|
||
const inputVal = productInput.value.trim();
|
||
const priceVal = productPrice.value.trim();
|
||
const badgeText = customBadgeInput ? customBadgeInput.value.trim() : '🇰🇷 100% Original Korea';
|
||
|
||
let productImg = attachedImageBitmap;
|
||
let title = inputVal || "Authentic Product";
|
||
|
||
if (!productImg) {
|
||
const resolved = await resolveProductUrl(inputVal, brandObj.category || brand);
|
||
if (resolved && resolved.imageUrl) {
|
||
title = resolved.title || inputVal;
|
||
productImg = await loadImage(resolved.imageUrl, brandObj.category, brand, title);
|
||
} else {
|
||
title = (resolved && resolved.title) ? resolved.title : (inputVal || "Authentic Product");
|
||
productImg = await loadImage(null, brandObj.category, brand, title);
|
||
}
|
||
}
|
||
|
||
if (productImg) {
|
||
await render3DCommercialPoster(posterCanvas, productImg, title, priceVal, badgeText, selectedStageTheme, aspect, brand);
|
||
|
||
const themeBadgeEl = document.getElementById('posterThemeBadge');
|
||
if (themeBadgeEl && THEMES[selectedStageTheme]) {
|
||
themeBadgeEl.textContent = THEMES[selectedStageTheme].name;
|
||
}
|
||
|
||
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 selectedBrand = document.getElementById('brandWatermarkSelect')?.value || 'glamourstouch';
|
||
const activeBrand = getBrandProfile(selectedBrand);
|
||
const cleanPhone = (activeBrand.footerHotline || '01712-426871').replace(/\D/g, '');
|
||
const pTitle = productInput.value.trim() || 'Authentic Product';
|
||
const text = encodeURIComponent(`✨ Hello! I want to order: ${pTitle}\nWebsite: https://${activeBrand.footerSite || 'glamourstouch.com'}\nHotline: ${activeBrand.footerHotline}`);
|
||
window.open(`https://wa.me/88${cleanPhone}?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 selectedBrand = document.getElementById('brandWatermarkSelect')?.value || 'glamourstouch';
|
||
const activeBrand = getBrandProfile(selectedBrand);
|
||
const cleanPhone = (activeBrand.footerHotline || '01712-426871').replace(/\D/g, '');
|
||
const pTitle = productInput.value.trim() || 'Authentic Product';
|
||
const pPrice = productPrice.value.trim() || '৳ ১,০৬০';
|
||
const posterDataUrl = posterCanvas.toDataURL('image/jpeg', 0.92);
|
||
|
||
const payload = {
|
||
title: pTitle,
|
||
price: pPrice,
|
||
caption: `✨ ${pTitle} ✨\n\n💰 অফার মূল্য: ${pPrice}\n🛡️ ১০০% অরিজিনাল গ্যারান্টি!\n\n💬 সরাসরি WhatsApp এ অর্ডার করতে ইনবক্স করুন:\n👉 https://wa.me/88${cleanPhone}\n📞 হটলাইন: ${activeBrand.footerHotline}\n🌐 ওয়েবসাইট: https://${activeBrand.footerSite}`,
|
||
image_url: posterDataUrl,
|
||
store: activeBrand.headerTitle || "Official Store",
|
||
website: `https://${activeBrand.footerSite}`,
|
||
whatsapp: activeBrand.footerHotline,
|
||
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;
|
||
});
|
||
}
|
||
}
|
||
|
||
// --- Dynamic Brand Profiles & Tenant Sync Engine ---
|
||
const DEFAULT_BRAND_PROFILES = {
|
||
glamourstouch: {
|
||
id: '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',
|
||
theme: 'obsidian_gold',
|
||
category: 'cosmetics'
|
||
},
|
||
panjabi: {
|
||
id: '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',
|
||
theme: 'obsidian_gold',
|
||
category: 'panjabi'
|
||
},
|
||
snehalata: {
|
||
id: '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',
|
||
theme: 'rose_quartz',
|
||
category: 'fashion'
|
||
},
|
||
techvolt: {
|
||
id: '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',
|
||
theme: 'cyber_neon',
|
||
category: 'electronics'
|
||
},
|
||
organic: {
|
||
id: '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',
|
||
theme: 'botanical_eco',
|
||
category: 'organic'
|
||
},
|
||
sneakerlab: {
|
||
id: 'sneakerlab',
|
||
headerTitle: '👟 SNEAKERLAB BD 👟',
|
||
headerSub: 'PREMIUM STREETWEAR & GENUINE LEATHER FOOTWEAR',
|
||
badgeL1: '👟 Memory Foam Cushion',
|
||
badgeL2: '✨ Doorstep Fitting',
|
||
footerSite: 'sneakers.auraajenticai.cloud',
|
||
footerHotline: '01712-426871',
|
||
theme: 'obsidian_gold',
|
||
category: 'sneakerlab'
|
||
},
|
||
royale: {
|
||
id: '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',
|
||
theme: 'obsidian_gold',
|
||
category: 'royale'
|
||
},
|
||
custom: {
|
||
id: 'custom',
|
||
headerTitle: '🛍️ UNIVERSAL MERCHANT 🛍️',
|
||
headerSub: '100% ORIGINAL AUTHENTIC • CASH ON DELIVERY BANGLADESH',
|
||
badgeL1: '⭐ Premium Quality',
|
||
badgeL2: '🛡️ 100% Original',
|
||
footerSite: 'auraajenticai.cloud',
|
||
footerHotline: '01712-426871',
|
||
theme: 'obsidian_gold',
|
||
category: 'general'
|
||
}
|
||
};
|
||
|
||
function getDynamicBrandProfiles() {
|
||
let customMap = {};
|
||
try {
|
||
const saved = localStorage.getItem('opal_custom_brands');
|
||
if (saved) customMap = JSON.parse(saved);
|
||
} catch (e) {}
|
||
return Object.assign({}, DEFAULT_BRAND_PROFILES, customMap);
|
||
}
|
||
|
||
function getBrandProfile(brandKey) {
|
||
const all = getDynamicBrandProfiles();
|
||
return all[brandKey] || all.glamourstouch;
|
||
}
|
||
|
||
// Universal Dynamic Product Resolver
|
||
async function resolveProductUrl(input, categoryHint = 'general') {
|
||
if (!input) return null;
|
||
if (input.match(/\.(jpeg|jpg|gif|png|webp)($|\?)/i) || input.startsWith('data:image/')) {
|
||
return { title: 'Authentic Product', imageUrl: input };
|
||
}
|
||
|
||
const lowerIn = input.toLowerCase().trim();
|
||
|
||
// Check 560+ real Glamour's Touch catalog
|
||
if (window.GT_CATALOG && window.GT_CATALOG.length > 0) {
|
||
const directMatch = window.GT_CATALOG.find(p => p.title.toLowerCase().includes(lowerIn) || lowerIn.includes(p.title.toLowerCase()));
|
||
if (directMatch && directMatch.image) {
|
||
return {
|
||
title: directMatch.title,
|
||
price: directMatch.price,
|
||
imageUrl: directMatch.image
|
||
};
|
||
}
|
||
}
|
||
|
||
// High-Resolution 3D CGI Commercial Master Catalog
|
||
const CGI_CATALOG = {
|
||
panjabi: { title: 'Royal Platinum Silk Designer Panjabi', imageUrl: '/assets/products/panjabi_3d_cgi.jpg' },
|
||
fashion: { title: 'Royal Silk Designer Wear', imageUrl: '/assets/products/panjabi_3d_cgi.jpg' },
|
||
saree: { title: 'Royal Silk Designer Wear', imageUrl: '/assets/products/panjabi_3d_cgi.jpg' },
|
||
cosmetics: { title: 'Medicube Collagen Jelly Cream + Hydra-Glow Serum (Korea)', imageUrl: '/assets/products/cosmetics_3d_cgi.jpg' },
|
||
beauty: { title: 'Medicube Collagen Jelly Cream + Hydra-Glow Serum (Korea)', imageUrl: '/assets/products/cosmetics_3d_cgi.jpg' },
|
||
glamourstouch: { title: 'Medicube Collagen Jelly Cream + Hydra-Glow Serum (Korea)', imageUrl: '/assets/products/cosmetics_3d_cgi.jpg' },
|
||
techvolt: { title: 'T900 Ultra Smartwatch Series 9 (AMOLED)', imageUrl: '/assets/products/watch_3d_cgi.jpg' },
|
||
electronics: { title: 'T900 Ultra Smartwatch Series 9 (AMOLED)', imageUrl: '/assets/products/watch_3d_cgi.jpg' },
|
||
gadget: { title: 'T900 Ultra Smartwatch Series 9 (AMOLED)', imageUrl: '/assets/products/watch_3d_cgi.jpg' },
|
||
watch: { title: 'T900 Ultra Smartwatch Series 9 (AMOLED)', imageUrl: '/assets/products/watch_3d_cgi.jpg' },
|
||
organic: { title: 'Sundarban Pure Raw Honey 1kg', imageUrl: '' },
|
||
honey: { title: 'Sundarban Pure Raw Honey 1kg', imageUrl: '' }
|
||
};
|
||
|
||
const hint = (categoryHint || '').toLowerCase();
|
||
|
||
for (const k of Object.keys(CGI_CATALOG)) {
|
||
if (hint.includes(k) || lowerIn.includes(k)) {
|
||
if (CGI_CATALOG[k].imageUrl) {
|
||
return {
|
||
title: input || CGI_CATALOG[k].title,
|
||
imageUrl: CGI_CATALOG[k].imageUrl
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
// Try local backend API if available
|
||
try {
|
||
const res = await fetch(`http://localhost:3000/api/trends/trending-products?category=${encodeURIComponent(categoryHint)}`);
|
||
if (res.ok) {
|
||
const data = await res.json();
|
||
if (data && data.products && data.products.length > 0) {
|
||
const match = data.products.find(p => p.name.toLowerCase().includes(input.toLowerCase()));
|
||
if (match) {
|
||
return {
|
||
title: match.name,
|
||
price: match.price,
|
||
imageUrl: match.image || ''
|
||
};
|
||
}
|
||
}
|
||
}
|
||
} catch (e) {
|
||
// Local server fetch optional
|
||
}
|
||
|
||
return { title: input, imageUrl: '' };
|
||
}
|
||
|
||
function loadImage(src, category = 'cosmetics', brand = 'glamourstouch', productTitle = 'Product') {
|
||
return new Promise((resolve) => {
|
||
if (!src) {
|
||
const placeholder = createFallbackProductCanvas(productTitle, category, brand);
|
||
return resolve(placeholder);
|
||
}
|
||
|
||
if (src.startsWith('data:')) {
|
||
const img = new Image();
|
||
img.onload = () => resolve(img);
|
||
img.onerror = () => resolve(createFallbackProductCanvas(productTitle, category, brand));
|
||
img.src = src;
|
||
return;
|
||
}
|
||
|
||
const img = new Image();
|
||
img.crossOrigin = 'anonymous';
|
||
img.onload = () => resolve(img);
|
||
img.onerror = () => {
|
||
// Try proxy
|
||
const proxyImg = new Image();
|
||
proxyImg.crossOrigin = 'anonymous';
|
||
proxyImg.onload = () => resolve(proxyImg);
|
||
proxyImg.onerror = () => {
|
||
resolve(createFallbackProductCanvas(productTitle, category, brand));
|
||
};
|
||
proxyImg.src = 'https://images.weserv.nl/?url=' + encodeURIComponent(src) + '&output=jpg&q=95';
|
||
};
|
||
img.src = src;
|
||
});
|
||
}
|
||
|
||
function roundRect(ctx, x, y, width, height, radius = 8) {
|
||
if (typeof radius === 'number') {
|
||
radius = { tl: radius, tr: radius, br: radius, bl: radius };
|
||
} else {
|
||
radius = Object.assign({ tl: 0, tr: 0, br: 0, bl: 0 }, radius);
|
||
}
|
||
ctx.beginPath();
|
||
ctx.moveTo(x + radius.tl, y);
|
||
ctx.lineTo(x + width - radius.tr, y);
|
||
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
|
||
ctx.lineTo(x + width, y + height - radius.br);
|
||
ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
|
||
ctx.lineTo(x + radius.bl, y + height);
|
||
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
|
||
ctx.lineTo(x, y + radius.tl);
|
||
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
|
||
ctx.closePath();
|
||
}
|
||
|
||
function createFallbackProductCanvas(label = 'Product', category = 'cosmetics', brandKey = 'glamourstouch') {
|
||
const c = document.createElement('canvas');
|
||
c.width = 600;
|
||
c.height = 600;
|
||
const ctx = c.getContext('2d');
|
||
ctx.clearRect(0, 0, 600, 600);
|
||
|
||
const cat = (category || brandKey || 'general').toLowerCase();
|
||
|
||
if (cat.includes('panjabi')) {
|
||
draw3DPanjabiMannequin(ctx, label);
|
||
} else if (cat.includes('cosmetic') || cat.includes('beauty') || cat.includes('glamour')) {
|
||
draw3DCosmeticsSet(ctx, label);
|
||
} else if (cat.includes('tech') || cat.includes('gadget') || cat.includes('electronic')) {
|
||
draw3DSmartwatch(ctx, label);
|
||
} else if (cat.includes('organic') || cat.includes('honey')) {
|
||
draw3DHoneyJar(ctx, label);
|
||
} else if (cat.includes('sneaker') || cat.includes('shoe') || cat.includes('footwear')) {
|
||
draw3DSneaker(ctx, label);
|
||
} else if (cat.includes('royal') || cat.includes('perfume') || cat.includes('fragrance')) {
|
||
draw3DPerfumeBottle(ctx, label);
|
||
} else if (cat.includes('fashion') || cat.includes('saree') || cat.includes('snehalata')) {
|
||
draw3DSareeMannequin(ctx, label);
|
||
} else {
|
||
draw3DCosmeticsSet(ctx, label);
|
||
}
|
||
|
||
return c;
|
||
}
|
||
|
||
// 1. 👑 3D Royal Panjabi Mannequin Renderer (Ultra CGI)
|
||
function draw3DPanjabiMannequin(ctx, label) {
|
||
// Mannequin Neck Stand (Matte Titanium & Gold Trim)
|
||
const neckGrad = ctx.createLinearGradient(260, 40, 340, 40);
|
||
neckGrad.addColorStop(0, '#090D16');
|
||
neckGrad.addColorStop(0.3, '#1E293B');
|
||
neckGrad.addColorStop(0.7, '#334155');
|
||
neckGrad.addColorStop(1, '#090D16');
|
||
ctx.fillStyle = neckGrad;
|
||
ctx.fillRect(272, 42, 56, 75);
|
||
|
||
// Brushed Gold Neck Ring (3D Bevel)
|
||
const neckRingGrad = ctx.createLinearGradient(268, 0, 332, 0);
|
||
neckRingGrad.addColorStop(0, '#78350F');
|
||
neckRingGrad.addColorStop(0.5, '#FDE68A');
|
||
neckRingGrad.addColorStop(1, '#92400E');
|
||
ctx.fillStyle = neckRingGrad;
|
||
roundRect(ctx, 268, 102, 64, 10, 4);
|
||
ctx.fill();
|
||
|
||
// Torso Silhouette (Royal Fabric with Draped Shoulders & Sleeves)
|
||
ctx.save();
|
||
|
||
// Side Sleeve Folds (3D depth behind main chest)
|
||
ctx.fillStyle = '#0F172A';
|
||
ctx.beginPath();
|
||
ctx.moveTo(140, 190);
|
||
ctx.lineTo(85, 360);
|
||
ctx.lineTo(135, 410);
|
||
ctx.lineTo(165, 330);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
ctx.beginPath();
|
||
ctx.moveTo(460, 190);
|
||
ctx.lineTo(515, 360);
|
||
ctx.lineTo(465, 410);
|
||
ctx.lineTo(435, 330);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Sleeve Embroidered Cuffs
|
||
const cuffGrad = ctx.createLinearGradient(85, 360, 135, 410);
|
||
cuffGrad.addColorStop(0, '#F59E0B');
|
||
cuffGrad.addColorStop(1, '#78350F');
|
||
ctx.strokeStyle = cuffGrad;
|
||
ctx.lineWidth = 4;
|
||
ctx.beginPath();
|
||
ctx.moveTo(85, 360); ctx.lineTo(135, 410);
|
||
ctx.moveTo(515, 360); ctx.lineTo(465, 410);
|
||
ctx.stroke();
|
||
|
||
// Main Chest & Waist Body (Royal Silk Fabric)
|
||
ctx.beginPath();
|
||
ctx.moveTo(260, 108);
|
||
ctx.bezierCurveTo(200, 118, 140, 155, 120, 205); // Left shoulder
|
||
ctx.bezierCurveTo(140, 320, 155, 440, 160, 570); // Left waist/body
|
||
ctx.lineTo(440, 570); // Bottom hem
|
||
ctx.bezierCurveTo(445, 440, 460, 320, 480, 205); // Right waist/body
|
||
ctx.bezierCurveTo(460, 155, 400, 118, 340, 108); // Right shoulder
|
||
ctx.closePath();
|
||
|
||
const fabricGrad = ctx.createLinearGradient(120, 108, 480, 570);
|
||
fabricGrad.addColorStop(0, '#0F172A');
|
||
fabricGrad.addColorStop(0.2, '#1E1B4B');
|
||
fabricGrad.addColorStop(0.45, '#312E81');
|
||
fabricGrad.addColorStop(0.75, '#1E1B4B');
|
||
fabricGrad.addColorStop(1, '#090D16');
|
||
ctx.fillStyle = fabricGrad;
|
||
ctx.fill();
|
||
|
||
// Silk Woven Jacquard Micro-Texture Lines
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.03)';
|
||
ctx.lineWidth = 1.5;
|
||
for (let jx = 130; jx < 470; jx += 12) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(jx, 120);
|
||
ctx.lineTo(jx + 20, 570);
|
||
ctx.stroke();
|
||
}
|
||
|
||
// Specular Silk Sheen & Fresnel Edge Lighting
|
||
const sheenGrad = ctx.createLinearGradient(140, 110, 320, 520);
|
||
sheenGrad.addColorStop(0, 'rgba(255, 255, 255, 0.25)');
|
||
sheenGrad.addColorStop(0.3, 'rgba(129, 140, 248, 0.15)');
|
||
sheenGrad.addColorStop(0.7, 'rgba(255, 255, 255, 0.02)');
|
||
sheenGrad.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = sheenGrad;
|
||
ctx.fill();
|
||
|
||
// Mandarin Stand Collar (3D Curved Neck Band)
|
||
ctx.beginPath();
|
||
ctx.ellipse(300, 112, 46, 17, 0, 0, Math.PI * 2);
|
||
ctx.fillStyle = '#0F172A';
|
||
ctx.fill();
|
||
|
||
// Outer Zari Gold Collar Border
|
||
const zariCollar = ctx.createLinearGradient(250, 0, 350, 0);
|
||
zariCollar.addColorStop(0, '#78350F');
|
||
zariCollar.addColorStop(0.5, '#FDE68A');
|
||
zariCollar.addColorStop(1, '#92400E');
|
||
ctx.strokeStyle = zariCollar;
|
||
ctx.lineWidth = 4;
|
||
ctx.stroke();
|
||
|
||
// Collar Zari Embroidery Stitches
|
||
ctx.fillStyle = '#FDE68A';
|
||
for (let a = 0; a < Math.PI; a += 0.28) {
|
||
const ex = 300 + Math.cos(a) * 41;
|
||
const ey = 114 + Math.sin(a) * 13;
|
||
ctx.beginPath();
|
||
ctx.arc(ex, ey, 2.2, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
}
|
||
|
||
// Vertical Placket (বোতামের পট্টি with 3D Chamfer)
|
||
const placketGrad = ctx.createLinearGradient(282, 128, 318, 128);
|
||
placketGrad.addColorStop(0, '#090D16');
|
||
placketGrad.addColorStop(0.3, '#1E1B4B');
|
||
placketGrad.addColorStop(0.7, '#312E81');
|
||
placketGrad.addColorStop(1, '#090D16');
|
||
ctx.fillStyle = placketGrad;
|
||
roundRect(ctx, 283, 126, 34, 280, 5);
|
||
ctx.fill();
|
||
|
||
// Placket Metallic Gold Border Piping
|
||
ctx.strokeStyle = zariCollar;
|
||
ctx.lineWidth = 2.5;
|
||
roundRect(ctx, 283, 126, 34, 280, 5);
|
||
ctx.stroke();
|
||
|
||
// 5 Royal Embossed Golden Buttons (3D Sphere with Specular Glint)
|
||
const buttonYs = [155, 208, 261, 314, 367];
|
||
buttonYs.forEach(by => {
|
||
// Button Drop Shadow onto Placket
|
||
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
|
||
ctx.beginPath();
|
||
ctx.arc(301, by + 2, 7.5, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// Metallic Gold Radial Gradient
|
||
const btnGrad = ctx.createRadialGradient(297, by - 2, 1, 300, by, 7.5);
|
||
btnGrad.addColorStop(0, '#FFFFFF');
|
||
btnGrad.addColorStop(0.3, '#FDE68A');
|
||
btnGrad.addColorStop(0.7, '#F59E0B');
|
||
btnGrad.addColorStop(1, '#78350F');
|
||
ctx.fillStyle = btnGrad;
|
||
ctx.beginPath();
|
||
ctx.arc(300, by, 7.5, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// Button Rim
|
||
ctx.strokeStyle = '#78350F';
|
||
ctx.lineWidth = 1;
|
||
ctx.stroke();
|
||
|
||
// Pinpoint Specular Glint
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.beginPath();
|
||
ctx.arc(297, by - 2.5, 2, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
});
|
||
|
||
// Chest Pocket & Silk Pocket Square (Folded Multi-point)
|
||
ctx.strokeStyle = '#E5B83A';
|
||
ctx.lineWidth = 3;
|
||
ctx.beginPath();
|
||
ctx.moveTo(355, 240);
|
||
ctx.lineTo(430, 240);
|
||
ctx.stroke();
|
||
|
||
// 3-Point Golden Silk Pocket Square
|
||
ctx.fillStyle = '#F59E0B';
|
||
ctx.beginPath();
|
||
ctx.moveTo(370, 240);
|
||
ctx.lineTo(385, 208); // Peak 1
|
||
ctx.lineTo(395, 222);
|
||
ctx.lineTo(405, 204); // Peak 2
|
||
ctx.lineTo(415, 224);
|
||
ctx.lineTo(422, 212); // Peak 3
|
||
ctx.lineTo(426, 240);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
ctx.strokeStyle = '#FDE68A';
|
||
ctx.lineWidth = 1.5;
|
||
ctx.stroke();
|
||
|
||
// Realistic Fabric Drape Creases & Shadows
|
||
ctx.strokeStyle = 'rgba(0, 0, 0, 0.45)';
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(180, 260);
|
||
ctx.quadraticCurveTo(230, 360, 260, 480);
|
||
ctx.moveTo(420, 260);
|
||
ctx.quadraticCurveTo(370, 360, 340, 480);
|
||
ctx.stroke();
|
||
|
||
ctx.restore();
|
||
}
|
||
|
||
// 2. ✨ 3D Luxury Cosmetics Cream Jar & Serum Duo (Ultra CGI)
|
||
function draw3DCosmeticsSet(ctx, label) {
|
||
// Main Cream Jar Body (Frosted Crystal Glass)
|
||
const jarX = 135, jarY = 230, jarW = 280, jarH = 250;
|
||
|
||
// Outer Refractive Glass Shell
|
||
const jarGrad = ctx.createLinearGradient(jarX, 0, jarX + jarW, 0);
|
||
jarGrad.addColorStop(0, '#FCE7F3');
|
||
jarGrad.addColorStop(0.15, '#FFFFFF');
|
||
jarGrad.addColorStop(0.4, '#FDF2F8');
|
||
jarGrad.addColorStop(0.7, '#FBCFE8');
|
||
jarGrad.addColorStop(0.9, '#F472B6');
|
||
jarGrad.addColorStop(1, '#9D174D');
|
||
ctx.fillStyle = jarGrad;
|
||
roundRect(ctx, jarX, jarY, jarW, jarH, 26);
|
||
ctx.fill();
|
||
|
||
// Thick Crystal Glass Base with Caustic Refraction
|
||
const glassBaseGrad = ctx.createLinearGradient(jarX, jarY + jarH - 40, jarX, jarY + jarH);
|
||
glassBaseGrad.addColorStop(0, 'rgba(255, 255, 255, 0.2)');
|
||
glassBaseGrad.addColorStop(0.7, 'rgba(255, 255, 255, 0.9)');
|
||
glassBaseGrad.addColorStop(1, 'rgba(244, 114, 182, 0.4)');
|
||
ctx.fillStyle = glassBaseGrad;
|
||
roundRect(ctx, jarX + 6, jarY + jarH - 40, jarW - 12, 34, 16);
|
||
ctx.fill();
|
||
|
||
// Inner Pink Collagen Cream Core (Subsurface Glow)
|
||
const coreGrad = ctx.createRadialGradient(jarX + jarW / 2, jarY + 120, 20, jarX + jarW / 2, jarY + 120, 110);
|
||
coreGrad.addColorStop(0, '#FFFFFF');
|
||
coreGrad.addColorStop(0.4, '#FCE7F3');
|
||
coreGrad.addColorStop(0.8, '#F472B6');
|
||
coreGrad.addColorStop(1, '#DB2777');
|
||
ctx.fillStyle = coreGrad;
|
||
roundRect(ctx, jarX + 16, jarY + 20, jarW - 32, jarH - 65, 18);
|
||
ctx.fill();
|
||
|
||
// Metallic Champagne Gold Jar Lid (Anisotropic Brushed Cylinder)
|
||
const lidX = 125, lidY = 175, lidW = 300, lidH = 68;
|
||
const lidGrad = ctx.createLinearGradient(lidX, 0, lidX + lidW, 0);
|
||
lidGrad.addColorStop(0, '#78350F');
|
||
lidGrad.addColorStop(0.18, '#FDE68A');
|
||
lidGrad.addColorStop(0.35, '#F59E0B');
|
||
lidGrad.addColorStop(0.5, '#FEF3C7');
|
||
lidGrad.addColorStop(0.68, '#F59E0B');
|
||
lidGrad.addColorStop(0.85, '#D97706');
|
||
lidGrad.addColorStop(1, '#78350F');
|
||
ctx.fillStyle = lidGrad;
|
||
roundRect(ctx, lidX, lidY, lidW, lidH, 16);
|
||
ctx.fill();
|
||
|
||
// Lid Top Specular Highlight Arc
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.75)';
|
||
ctx.fillRect(lidX + 30, lidY + 4, lidW - 60, 4);
|
||
|
||
// Minimalist Luxury Brand Label Strip
|
||
ctx.fillStyle = '#FFFFFF';
|
||
roundRect(ctx, jarX + 28, jarY + 65, jarW - 56, 95, 12);
|
||
ctx.fill();
|
||
ctx.strokeStyle = '#E5B83A';
|
||
ctx.lineWidth = 1.8;
|
||
roundRect(ctx, jarX + 28, jarY + 65, jarW - 56, 95, 12);
|
||
ctx.stroke();
|
||
|
||
ctx.fillStyle = '#831843';
|
||
ctx.font = 'bold 15px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('COLLAGEN JELLY CREAM', jarX + jarW / 2, jarY + 105);
|
||
ctx.fillStyle = '#D97706';
|
||
ctx.font = 'bold 12px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('✨ 100% PURE K-BEAUTY', jarX + jarW / 2, jarY + 132);
|
||
|
||
// Glossy Vertical Glass Shine Sweeps
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.65)';
|
||
ctx.lineWidth = 4;
|
||
ctx.beginPath();
|
||
ctx.moveTo(jarX + 22, jarY + 15);
|
||
ctx.lineTo(jarX + 22, jarY + jarH - 25);
|
||
ctx.stroke();
|
||
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.35)';
|
||
ctx.lineWidth = 2;
|
||
ctx.beginPath();
|
||
ctx.moveTo(jarX + 32, jarY + 25);
|
||
ctx.lineTo(jarX + 32, jarY + jarH - 35);
|
||
ctx.stroke();
|
||
|
||
// Accompanying Serum Dropper Bottle (Standing beside on right)
|
||
const botX = 430, botY = 190, botW = 95, botH = 285;
|
||
const botGrad = ctx.createLinearGradient(botX, 0, botX + botW, 0);
|
||
botGrad.addColorStop(0, '#831843');
|
||
botGrad.addColorStop(0.25, '#DB2777');
|
||
botGrad.addColorStop(0.6, '#F472B6');
|
||
botGrad.addColorStop(0.85, '#BE185D');
|
||
botGrad.addColorStop(1, '#500724');
|
||
ctx.fillStyle = botGrad;
|
||
roundRect(ctx, botX, botY + 45, botW, botH - 45, 18);
|
||
ctx.fill();
|
||
|
||
// Dropper Golden Collar
|
||
ctx.fillStyle = lidGrad;
|
||
roundRect(ctx, botX + 15, botY + 16, botW - 30, 32, 6);
|
||
ctx.fill();
|
||
|
||
// Rubber Pipette Bulb
|
||
const bulbGrad = ctx.createRadialGradient(botX + botW / 2 - 3, botY + 8, 2, botX + botW / 2, botY + 12, 16);
|
||
bulbGrad.addColorStop(0, '#52525B');
|
||
bulbGrad.addColorStop(1, '#18181B');
|
||
ctx.fillStyle = bulbGrad;
|
||
ctx.beginPath();
|
||
ctx.arc(botX + botW / 2, botY + 12, 16, Math.PI, 0);
|
||
ctx.fill();
|
||
|
||
// Dropper Bottle Shine Streak
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)';
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(botX + 12, botY + 55);
|
||
ctx.lineTo(botX + 12, botY + botH - 18);
|
||
ctx.stroke();
|
||
}
|
||
|
||
// 3. ⚡ 3D Titanium Smartwatch with AMOLED Display (Ultra CGI)
|
||
function draw3DSmartwatch(ctx, label) {
|
||
// Curved Silicone Sports Strap (Wrapped with 3D Depth)
|
||
const strapGrad = ctx.createLinearGradient(230, 0, 370, 0);
|
||
strapGrad.addColorStop(0, '#090D16');
|
||
strapGrad.addColorStop(0.2, '#1E293B');
|
||
strapGrad.addColorStop(0.5, '#334155');
|
||
strapGrad.addColorStop(0.8, '#1E293B');
|
||
strapGrad.addColorStop(1, '#090D16');
|
||
ctx.fillStyle = strapGrad;
|
||
|
||
// Top strap
|
||
roundRect(ctx, 235, 40, 130, 120, 18);
|
||
ctx.fill();
|
||
// Bottom strap
|
||
roundRect(ctx, 235, 435, 130, 135, 18);
|
||
ctx.fill();
|
||
|
||
// Strap Texture Ridges (3D Grooves)
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.12)';
|
||
ctx.lineWidth = 2.5;
|
||
for (let sy = 50; sy < 145; sy += 16) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(245, sy); ctx.lineTo(355, sy);
|
||
ctx.stroke();
|
||
}
|
||
for (let sy = 450; sy < 555; sy += 16) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(245, sy); ctx.lineTo(355, sy);
|
||
ctx.stroke();
|
||
}
|
||
|
||
// Titanium Watch Chassis (Aerospace Grade Brushed Metal)
|
||
const caseX = 165, caseY = 120, caseW = 270, caseH = 340;
|
||
const caseGrad = ctx.createLinearGradient(caseX, 0, caseX + caseW, 0);
|
||
caseGrad.addColorStop(0, '#1E293B');
|
||
caseGrad.addColorStop(0.25, '#64748B');
|
||
caseGrad.addColorStop(0.5, '#94A3B8');
|
||
caseGrad.addColorStop(0.75, '#475569');
|
||
caseGrad.addColorStop(1, '#0F172A');
|
||
ctx.fillStyle = caseGrad;
|
||
roundRect(ctx, caseX, caseY, caseW, caseH, 54);
|
||
ctx.fill();
|
||
|
||
// Dual-Bevel Metallic Edge Highlight
|
||
ctx.strokeStyle = '#CBD5E1';
|
||
ctx.lineWidth = 2.5;
|
||
roundRect(ctx, caseX + 2, caseY + 2, caseW - 4, caseH - 4, 52);
|
||
ctx.stroke();
|
||
|
||
// CNC Knurled Digital Crown Dial with Orange Ring
|
||
const crownX = caseX + caseW - 4, crownY = caseY + 75;
|
||
const crownGrad = ctx.createLinearGradient(crownX, 0, crownX + 18, 0);
|
||
crownGrad.addColorStop(0, '#64748B');
|
||
crownGrad.addColorStop(0.4, '#F97316');
|
||
crownGrad.addColorStop(0.7, '#FB923C');
|
||
crownGrad.addColorStop(1, '#334155');
|
||
ctx.fillStyle = crownGrad;
|
||
roundRect(ctx, crownX, crownY, 18, 62, 6);
|
||
ctx.fill();
|
||
|
||
// Deep AMOLED Screen Bezel
|
||
const scX = caseX + 18, scY = caseY + 18, scW = caseW - 36, scH = caseH - 36;
|
||
ctx.fillStyle = '#000000';
|
||
roundRect(ctx, scX, scY, scW, scH, 38);
|
||
ctx.fill();
|
||
|
||
// 2.5D Curved Sapphire Glass Specular Glare Arc
|
||
const glassGrad = ctx.createLinearGradient(scX, scY, scX + scW, scY + scH);
|
||
glassGrad.addColorStop(0, 'rgba(255, 255, 255, 0.28)');
|
||
glassGrad.addColorStop(0.25, 'rgba(255, 255, 255, 0.06)');
|
||
glassGrad.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = glassGrad;
|
||
roundRect(ctx, scX, scY, scW, scH, 38);
|
||
ctx.fill();
|
||
|
||
// UI - Glowing Cyan Digital Clock
|
||
ctx.save();
|
||
ctx.shadowColor = '#38BDF8';
|
||
ctx.shadowBlur = 14;
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = 'bold 54px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('10:08', caseX + caseW / 2, caseY + 115);
|
||
ctx.restore();
|
||
|
||
// UI - Tricolor Activity Rings (Neon Coral, Lime, Cyan)
|
||
const cx = caseX + caseW / 2, cy = caseY + 200;
|
||
|
||
// Red Ring
|
||
ctx.strokeStyle = '#EF4444';
|
||
ctx.lineWidth = 8.5;
|
||
ctx.lineCap = 'round';
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy, 48, -Math.PI / 2, Math.PI * 0.85);
|
||
ctx.stroke();
|
||
|
||
// Green Ring
|
||
ctx.strokeStyle = '#22C55E';
|
||
ctx.lineWidth = 7.5;
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy, 35, -Math.PI / 2, Math.PI * 0.55);
|
||
ctx.stroke();
|
||
|
||
// Cyan Ring
|
||
ctx.strokeStyle = '#06B6D4';
|
||
ctx.lineWidth = 6.5;
|
||
ctx.beginPath();
|
||
ctx.arc(cx, cy, 24, -Math.PI / 2, Math.PI * 0.98);
|
||
ctx.stroke();
|
||
|
||
// Heart Rate Pulse Wave & Battery Indicator
|
||
ctx.fillStyle = '#F43F5E';
|
||
ctx.font = 'bold 15px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('❤️ 78 BPM • 🔋 98%', cx, caseY + 282);
|
||
}
|
||
|
||
// 4. 🍯 3D Pure Honey Hexagonal Glass Jar (Ultra CGI)
|
||
function draw3DHoneyJar(ctx, label) {
|
||
const jarX = 155, jarY = 180, jarW = 290, jarH = 290;
|
||
|
||
// Outer Hexagonal Glass Shell with Caustic Refraction
|
||
const glassGrad = ctx.createLinearGradient(jarX, 0, jarX + jarW, 0);
|
||
glassGrad.addColorStop(0, 'rgba(255, 255, 255, 0.7)');
|
||
glassGrad.addColorStop(0.12, '#FDE68A');
|
||
glassGrad.addColorStop(0.35, '#F59E0B');
|
||
glassGrad.addColorStop(0.65, '#D97706');
|
||
glassGrad.addColorStop(0.88, '#B45309');
|
||
glassGrad.addColorStop(1, '#78350F');
|
||
ctx.fillStyle = glassGrad;
|
||
roundRect(ctx, jarX, jarY, jarW, jarH, 36);
|
||
ctx.fill();
|
||
|
||
// Pure Golden Amber Liquid Honey Core
|
||
const honeyGrad = ctx.createLinearGradient(jarX + 12, jarY + 40, jarX + 12, jarY + jarH - 12);
|
||
honeyGrad.addColorStop(0, '#FEF08A');
|
||
honeyGrad.addColorStop(0.35, '#F59E0B');
|
||
honeyGrad.addColorStop(0.7, '#D97706');
|
||
honeyGrad.addColorStop(1, '#92400E');
|
||
ctx.fillStyle = honeyGrad;
|
||
roundRect(ctx, jarX + 12, jarY + 42, jarW - 24, jarH - 54, 26);
|
||
ctx.fill();
|
||
|
||
// Honey Surface Meniscus Light Sweep
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.45)';
|
||
roundRect(ctx, jarX + 25, jarY + 46, jarW - 50, 10, 5);
|
||
ctx.fill();
|
||
|
||
// Rustic Birch Wood Lid (Turned Bevel with Wood Grain)
|
||
const lidGrad = ctx.createLinearGradient(jarX + 15, 0, jarX + jarW - 15, 0);
|
||
lidGrad.addColorStop(0, '#78350F');
|
||
lidGrad.addColorStop(0.25, '#B45309');
|
||
lidGrad.addColorStop(0.55, '#D97706');
|
||
lidGrad.addColorStop(0.85, '#92400E');
|
||
lidGrad.addColorStop(1, '#78350F');
|
||
ctx.fillStyle = lidGrad;
|
||
roundRect(ctx, jarX + 12, jarY - 45, jarW - 24, 52, 14);
|
||
ctx.fill();
|
||
|
||
// Natural Jute Twine Rope Wrapped Twice around Neck
|
||
ctx.strokeStyle = '#D97706';
|
||
ctx.lineWidth = 5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(jarX + 22, jarY + 10);
|
||
ctx.lineTo(jarX + jarW - 22, jarY + 10);
|
||
ctx.moveTo(jarX + 22, jarY + 18);
|
||
ctx.lineTo(jarX + jarW - 22, jarY + 18);
|
||
ctx.stroke();
|
||
|
||
// Viscous Golden Honey Dripping down the front
|
||
ctx.fillStyle = '#FEF08A';
|
||
ctx.beginPath();
|
||
ctx.moveTo(jarX + 85, jarY + 40);
|
||
ctx.quadraticCurveTo(jarX + 105, jarY + 130, jarX + 98, jarY + 155);
|
||
ctx.arc(jarX + 98, jarY + 162, 12, 0, Math.PI);
|
||
ctx.quadraticCurveTo(jarX + 88, jarY + 130, jarX + 75, jarY + 40);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Drip Gloss Specular Highlight
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.beginPath();
|
||
ctx.arc(jarX + 96, jarY + 160, 3.5, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// Kraft Paper Harvest Label
|
||
ctx.fillStyle = '#FEF3C7';
|
||
roundRect(ctx, jarX + 35, jarY + 100, jarW - 70, 105, 16);
|
||
ctx.fill();
|
||
ctx.strokeStyle = '#B45309';
|
||
ctx.lineWidth = 2.2;
|
||
roundRect(ctx, jarX + 35, jarY + 100, jarW - 70, 105, 16);
|
||
ctx.stroke();
|
||
|
||
ctx.fillStyle = '#78350F';
|
||
ctx.font = 'bold 18px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('100% PURE RAW HONEY', jarX + jarW / 2, jarY + 142);
|
||
ctx.fillStyle = '#B45309';
|
||
ctx.font = 'bold 12px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('🍯 SUNDARBAN FOREST HARVEST', jarX + jarW / 2, jarY + 172);
|
||
|
||
// Glass Refraction Edge Streaks
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.65)';
|
||
ctx.lineWidth = 3.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(jarX + 22, jarY + 30);
|
||
ctx.lineTo(jarX + 22, jarY + jarH - 30);
|
||
ctx.stroke();
|
||
}
|
||
|
||
// 5. 👟 Ultra-Realistic 3D CGI Streetwear Sneaker Model Renderer
|
||
function draw3DSneaker(ctx, label) {
|
||
ctx.save();
|
||
ctx.translate(20, 10);
|
||
|
||
// Deep Contact Shadow with ambient occlusion
|
||
const shadowGrad = ctx.createRadialGradient(280, 480, 20, 280, 480, 240);
|
||
shadowGrad.addColorStop(0, 'rgba(0, 0, 0, 0.92)');
|
||
shadowGrad.addColorStop(0.5, 'rgba(0, 0, 0, 0.45)');
|
||
shadowGrad.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = shadowGrad;
|
||
ctx.beginPath();
|
||
ctx.ellipse(280, 485, 230, 32, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// 1. Multi-Density Sculpted Outsole & Midsole (Thick 3D Platform)
|
||
// Base Rubber Outsole (Herringbone Grip Tread)
|
||
const treadGrad = ctx.createLinearGradient(60, 470, 500, 470);
|
||
treadGrad.addColorStop(0, '#0F172A');
|
||
treadGrad.addColorStop(0.5, '#1E293B');
|
||
treadGrad.addColorStop(1, '#090D16');
|
||
ctx.fillStyle = treadGrad;
|
||
ctx.beginPath();
|
||
ctx.moveTo(65, 470);
|
||
ctx.bezierCurveTo(90, 485, 450, 485, 495, 465);
|
||
ctx.lineTo(495, 480);
|
||
ctx.bezierCurveTo(450, 498, 90, 498, 65, 480);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Sculpted EVA Phylon Midsole (Beveled Crisp Form)
|
||
const midsoleGrad = ctx.createLinearGradient(60, 400, 500, 475);
|
||
midsoleGrad.addColorStop(0, '#FFFFFF');
|
||
midsoleGrad.addColorStop(0.3, '#F1F5F9');
|
||
midsoleGrad.addColorStop(0.6, '#CBD5E1');
|
||
midsoleGrad.addColorStop(1, '#94A3B8');
|
||
ctx.fillStyle = midsoleGrad;
|
||
|
||
ctx.beginPath();
|
||
ctx.moveTo(60, 465);
|
||
ctx.bezierCurveTo(80, 410, 140, 415, 220, 420); // Forefoot curve
|
||
ctx.bezierCurveTo(270, 425, 340, 420, 390, 410); // Arch
|
||
ctx.bezierCurveTo(440, 400, 480, 415, 498, 455); // Heel counter
|
||
ctx.bezierCurveTo(470, 478, 100, 480, 60, 465); // Bottom contour
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Midsole Specular Bevel Line
|
||
ctx.strokeStyle = '#FFFFFF';
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(70, 450);
|
||
ctx.bezierCurveTo(140, 422, 360, 422, 490, 445);
|
||
ctx.stroke();
|
||
|
||
// 2. Translucent 3D Air-Max Cushion Window in Heel
|
||
ctx.save();
|
||
const airX = 350, airY = 422, airW = 110, airH = 32;
|
||
// Inner chamber depth
|
||
ctx.fillStyle = '#0F172A';
|
||
roundRect(ctx, airX, airY, airW, airH, 10);
|
||
ctx.fill();
|
||
|
||
// Glowing Cyan/Blue Gas Chamber
|
||
const airGlow = ctx.createLinearGradient(airX, 0, airX + airW, 0);
|
||
airGlow.addColorStop(0, '#0284C7');
|
||
airGlow.addColorStop(0.5, '#38BDF8');
|
||
airGlow.addColorStop(1, '#06B6D4');
|
||
ctx.fillStyle = airGlow;
|
||
roundRect(ctx, airX + 3, airY + 3, airW - 6, airH - 6, 8);
|
||
ctx.fill();
|
||
|
||
// Air Chamber Internal Support Pillars
|
||
ctx.fillStyle = '#E0F2FE';
|
||
for (let px = airX + 18; px < airX + airW - 10; px += 22) {
|
||
roundRect(ctx, px, airY + 4, 7, airH - 8, 3);
|
||
ctx.fill();
|
||
}
|
||
|
||
// Outer Translucent Glass Highlight
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.75)';
|
||
ctx.lineWidth = 2;
|
||
roundRect(ctx, airX, airY, airW, airH, 10);
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
|
||
// 3. Sneaker Upper (Layered Suede, Textured Mesh & Premium Nubuck)
|
||
// Base Upper Body
|
||
const upperGrad = ctx.createLinearGradient(70, 200, 480, 440);
|
||
upperGrad.addColorStop(0, '#0F172A');
|
||
upperGrad.addColorStop(0.3, '#1E293B');
|
||
upperGrad.addColorStop(0.65, '#334155');
|
||
upperGrad.addColorStop(1, '#090D16');
|
||
ctx.fillStyle = upperGrad;
|
||
|
||
ctx.beginPath();
|
||
ctx.moveTo(68, 450);
|
||
ctx.bezierCurveTo(75, 360, 140, 320, 210, 335); // Toe curve
|
||
ctx.bezierCurveTo(245, 280, 285, 230, 335, 220); // Eyestay / Tongue line
|
||
ctx.bezierCurveTo(385, 210, 425, 250, 450, 305); // Ankle collar
|
||
ctx.bezierCurveTo(475, 345, 485, 395, 482, 440); // Heel spine
|
||
ctx.bezierCurveTo(420, 420, 160, 420, 68, 450); // Bottom joining midsole
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Suede Mudguard Overlay (Toe Box)
|
||
const mudguardGrad = ctx.createLinearGradient(70, 340, 210, 440);
|
||
mudguardGrad.addColorStop(0, '#1E293B');
|
||
mudguardGrad.addColorStop(0.7, '#0F172A');
|
||
mudguardGrad.addColorStop(1, '#020617');
|
||
ctx.fillStyle = mudguardGrad;
|
||
ctx.beginPath();
|
||
ctx.moveTo(68, 450);
|
||
ctx.bezierCurveTo(72, 380, 120, 350, 185, 360);
|
||
ctx.bezierCurveTo(200, 395, 195, 425, 180, 445);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
ctx.strokeStyle = '#475569';
|
||
ctx.lineWidth = 1.5;
|
||
ctx.stroke();
|
||
|
||
// Breathable Mesh Toe Vamp Texture
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.08)';
|
||
ctx.lineWidth = 1.2;
|
||
for (let mx = 90; mx < 180; mx += 8) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(mx, 365);
|
||
ctx.lineTo(mx + 10, 420);
|
||
ctx.stroke();
|
||
}
|
||
|
||
// Padded Ankle Collar (Fabric Lining)
|
||
ctx.fillStyle = '#020617';
|
||
ctx.beginPath();
|
||
ctx.ellipse(390, 270, 42, 60, -Math.PI / 6, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
ctx.strokeStyle = '#64748B';
|
||
ctx.lineWidth = 3;
|
||
ctx.stroke();
|
||
|
||
// Padded Tongue with SneakerLab Logo Badge
|
||
const tongueGrad = ctx.createLinearGradient(270, 220, 335, 310);
|
||
tongueGrad.addColorStop(0, '#334155');
|
||
tongueGrad.addColorStop(1, '#0F172A');
|
||
ctx.fillStyle = tongueGrad;
|
||
ctx.beginPath();
|
||
ctx.moveTo(270, 250);
|
||
ctx.lineTo(315, 215);
|
||
ctx.lineTo(345, 235);
|
||
ctx.lineTo(310, 295);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Woven Tongue Badge
|
||
ctx.fillStyle = '#F43F5E';
|
||
roundRect(ctx, 290, 215, 38, 20, 4);
|
||
ctx.fill();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold 8px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('AIR 26', 309, 228);
|
||
|
||
// 4. 3D Embossed Dynamic Neon Swoosh / Lightning Crest
|
||
ctx.save();
|
||
ctx.shadowColor = '#F43F5E';
|
||
ctx.shadowBlur = 18;
|
||
const swooshGrad = ctx.createLinearGradient(160, 410, 430, 320);
|
||
swooshGrad.addColorStop(0, '#F43F5E');
|
||
swooshGrad.addColorStop(0.5, '#FB7185');
|
||
swooshGrad.addColorStop(1, '#FDA4AF');
|
||
ctx.fillStyle = swooshGrad;
|
||
|
||
ctx.beginPath();
|
||
ctx.moveTo(170, 400);
|
||
ctx.quadraticCurveTo(280, 420, 435, 320);
|
||
ctx.quadraticCurveTo(310, 440, 170, 400);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Swoosh Specular Edge Glint
|
||
ctx.strokeStyle = '#FFFFFF';
|
||
ctx.lineWidth = 2;
|
||
ctx.beginPath();
|
||
ctx.moveTo(180, 398);
|
||
ctx.quadraticCurveTo(285, 418, 430, 322);
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
|
||
// 5. 3D Tubular Laces & Chrome Metal Eyelets
|
||
const eyelets = [
|
||
{ x: 235, y: 345, ex: 265, ey: 335 },
|
||
{ x: 255, y: 320, ex: 285, ey: 308 },
|
||
{ x: 275, y: 295, ex: 305, ey: 280 },
|
||
{ x: 295, y: 270, ex: 325, ey: 255 },
|
||
{ x: 315, y: 245, ex: 345, ey: 230 }
|
||
];
|
||
|
||
eyelets.forEach(pt => {
|
||
// Chrome Eyelet Ring
|
||
ctx.fillStyle = '#CBD5E1';
|
||
ctx.beginPath(); ctx.arc(pt.x, pt.y, 4.5, 0, Math.PI * 2); ctx.fill();
|
||
ctx.fillStyle = '#0F172A';
|
||
ctx.beginPath(); ctx.arc(pt.x, pt.y, 2.5, 0, Math.PI * 2); ctx.fill();
|
||
|
||
ctx.fillStyle = '#CBD5E1';
|
||
ctx.beginPath(); ctx.arc(pt.ex, pt.ey, 4.5, 0, Math.PI * 2); ctx.fill();
|
||
ctx.fillStyle = '#0F172A';
|
||
ctx.beginPath(); ctx.arc(pt.ex, pt.ey, 2.5, 0, Math.PI * 2); ctx.fill();
|
||
|
||
// Woven Lace Cable with 3D Drop Shadow
|
||
ctx.save();
|
||
ctx.shadowColor = 'rgba(0,0,0,0.5)';
|
||
ctx.shadowBlur = 4;
|
||
ctx.shadowOffsetY = 2;
|
||
ctx.strokeStyle = '#FFFFFF';
|
||
ctx.lineWidth = 5.5;
|
||
ctx.lineCap = 'round';
|
||
ctx.beginPath();
|
||
ctx.moveTo(pt.x, pt.y);
|
||
ctx.quadraticCurveTo((pt.x + pt.ex) / 2, (pt.y + pt.ey) / 2 - 4, pt.ex, pt.ey);
|
||
ctx.stroke();
|
||
|
||
// Lace highlight
|
||
ctx.strokeStyle = '#E2E8F0';
|
||
ctx.lineWidth = 2;
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
});
|
||
|
||
ctx.restore();
|
||
}
|
||
|
||
// 6. 💎 3D Luxury Perfume Crystal Bottle Renderer
|
||
function draw3DPerfumeBottle(ctx, label) {
|
||
const bx = 180, by = 210, bw = 240, bh = 280;
|
||
|
||
// Crystal Glass Body
|
||
const glassGrad = ctx.createLinearGradient(bx, 0, bx + bw, 0);
|
||
glassGrad.addColorStop(0, '#581C87');
|
||
glassGrad.addColorStop(0.2, '#A855F7');
|
||
glassGrad.addColorStop(0.5, '#F3E8FF');
|
||
glassGrad.addColorStop(0.8, '#9333EA');
|
||
glassGrad.addColorStop(1, '#3B0764');
|
||
ctx.fillStyle = glassGrad;
|
||
roundRect(ctx, bx, by, bw, bh, 24);
|
||
ctx.fill();
|
||
|
||
// Amber/Violet Perfume Liquid Core
|
||
ctx.fillStyle = '#7E22CE';
|
||
roundRect(ctx, bx + 16, by + 30, bw - 32, bh - 50, 16);
|
||
ctx.fill();
|
||
|
||
// Golden Collar & Atomizer
|
||
const goldGrad = ctx.createLinearGradient(bx + 70, 0, bx + bw - 70, 0);
|
||
goldGrad.addColorStop(0, '#78350F');
|
||
goldGrad.addColorStop(0.5, '#FDE68A');
|
||
goldGrad.addColorStop(1, '#92400E');
|
||
ctx.fillStyle = goldGrad;
|
||
roundRect(ctx, bx + 80, by - 35, bw - 160, 40, 6);
|
||
ctx.fill();
|
||
|
||
// Crystal Faceted Cap
|
||
ctx.fillStyle = '#E9D5FF';
|
||
roundRect(ctx, bx + 70, by - 110, bw - 140, 80, 10);
|
||
ctx.fill();
|
||
ctx.strokeStyle = '#FFFFFF';
|
||
ctx.lineWidth = 2;
|
||
roundRect(ctx, bx + 70, by - 110, bw - 140, 80, 10);
|
||
ctx.stroke();
|
||
|
||
// Gold Perfume Label
|
||
ctx.fillStyle = '#0F172A';
|
||
roundRect(ctx, bx + 35, by + 90, bw - 70, 90, 10);
|
||
ctx.fill();
|
||
ctx.strokeStyle = '#F59E0B';
|
||
ctx.lineWidth = 2;
|
||
roundRect(ctx, bx + 35, by + 90, bw - 70, 90, 10);
|
||
ctx.stroke();
|
||
|
||
ctx.fillStyle = '#F59E0B';
|
||
ctx.font = 'bold 18px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('OUD ROYALE', bx + bw / 2, by + 130);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold 11px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('EAU DE PARFUM • 100ML', bx + bw / 2, by + 155);
|
||
}
|
||
|
||
// 7. 👗 3D Luxury Saree Mannequin Renderer
|
||
function draw3DSareeMannequin(ctx, label) {
|
||
// Torso base
|
||
draw3DPanjabiMannequin(ctx, label);
|
||
|
||
// Saree Zari Pallu Drape across shoulder
|
||
ctx.save();
|
||
ctx.fillStyle = '#BE185D';
|
||
ctx.beginPath();
|
||
ctx.moveTo(130, 360);
|
||
ctx.quadraticCurveTo(240, 260, 400, 120);
|
||
ctx.lineTo(440, 150);
|
||
ctx.quadraticCurveTo(260, 320, 150, 460);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Gold Floral Zari Border
|
||
ctx.strokeStyle = '#FDE68A';
|
||
ctx.lineWidth = 6;
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
}
|
||
|
||
// 8. 🛍️ 3D Commercial Gift Box Renderer
|
||
function draw3DCommercialGiftBox(ctx, label) {
|
||
draw3DCosmeticsSet(ctx, label);
|
||
}
|
||
|
||
// Bokeh Sparkle Particles Helper
|
||
function drawSparkleBokeh(ctx, w, h, goldColor) {
|
||
const particles = [
|
||
{ x: w * 0.18, y: h * 0.22, r: 3, a: 0.7 },
|
||
{ x: w * 0.82, y: h * 0.28, r: 2.5, a: 0.8 },
|
||
{ x: w * 0.12, y: h * 0.55, r: 2, a: 0.6 },
|
||
{ x: w * 0.88, y: h * 0.62, r: 3.5, a: 0.85 },
|
||
{ x: w * 0.25, y: h * 0.72, r: 2.2, a: 0.5 },
|
||
{ x: w * 0.76, y: h * 0.78, r: 2.8, a: 0.75 },
|
||
{ x: w * 0.5, y: h * 0.15, r: 4, a: 0.9 }
|
||
];
|
||
|
||
particles.forEach(p => {
|
||
ctx.save();
|
||
ctx.fillStyle = goldColor;
|
||
ctx.globalAlpha = p.a;
|
||
ctx.beginPath();
|
||
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
if (p.r >= 3) {
|
||
ctx.strokeStyle = '#FFFFFF';
|
||
ctx.lineWidth = 1;
|
||
ctx.beginPath();
|
||
ctx.moveTo(p.x - p.r * 2.5, p.y);
|
||
ctx.lineTo(p.x + p.r * 2.5, p.y);
|
||
ctx.moveTo(p.x, p.y - p.r * 2.5);
|
||
ctx.lineTo(p.x, p.y + p.r * 2.5);
|
||
ctx.stroke();
|
||
}
|
||
ctx.restore();
|
||
});
|
||
}
|
||
|
||
// Reusable Authentic 3-Finder QR Code Tile Renderer
|
||
function drawQRCodeTile(ctx, qrX, qrY, qrS) {
|
||
ctx.save();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.strokeStyle = 'rgba(0,0,0,0.12)';
|
||
ctx.lineWidth = 1;
|
||
ctx.beginPath();
|
||
ctx.roundRect(qrX, qrY, qrS, qrS, 8);
|
||
ctx.fill();
|
||
ctx.stroke();
|
||
|
||
const drawFinder = (fx, fy) => {
|
||
ctx.fillStyle = '#000000';
|
||
ctx.fillRect(fx, fy, 20, 20);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillRect(fx + 3, fy + 3, 14, 14);
|
||
ctx.fillStyle = '#000000';
|
||
ctx.fillRect(fx + 6, fy + 6, 8, 8);
|
||
};
|
||
|
||
// 3 standard QR position detection patterns
|
||
drawFinder(qrX + 6, qrY + 6); // Top-Left
|
||
drawFinder(qrX + qrS - 26, qrY + 6); // Top-Right
|
||
drawFinder(qrX + 6, qrY + qrS - 26); // Bottom-Left
|
||
|
||
// Data matrix pattern simulation
|
||
ctx.fillStyle = '#000000';
|
||
for (let r = 0; r < 7; r++) {
|
||
for (let c = 0; c < 7; c++) {
|
||
if ((r < 3 && c < 3) || (r < 3 && c > 3) || (r > 3 && c < 3)) continue;
|
||
if ((r * 7 + c + 3) % 2 === 0 || (r + c * 3) % 3 === 0) {
|
||
ctx.fillRect(qrX + 28 + (c - 3) * 5, qrY + 28 + (r - 3) * 5, 3.5, 3.5);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Timing lines
|
||
for (let i = 28; i < qrS - 28; i += 4) {
|
||
if ((i / 4) % 2 === 0) {
|
||
ctx.fillRect(qrX + i, qrY + 14, 2.5, 2.5);
|
||
ctx.fillRect(qrX + 14, qrY + i, 2.5, 2.5);
|
||
}
|
||
}
|
||
ctx.restore();
|
||
}
|
||
|
||
// --- 8K Photorealistic Natural & Lifestyle Procedural Canvas Engines ---
|
||
function renderNaturalWoodGrain(ctx, x, y, width, height, isWalnut = false) {
|
||
ctx.save();
|
||
const baseGrad = ctx.createLinearGradient(0, y, 0, y + height);
|
||
if (isWalnut) {
|
||
baseGrad.addColorStop(0, '#3D2619');
|
||
baseGrad.addColorStop(0.3, '#2A180E');
|
||
baseGrad.addColorStop(0.7, '#1B0F08');
|
||
baseGrad.addColorStop(1, '#120904');
|
||
} else {
|
||
// Scandinavian Warm Honey Oak
|
||
baseGrad.addColorStop(0, '#D8BA94');
|
||
baseGrad.addColorStop(0.25, '#C9A982');
|
||
baseGrad.addColorStop(0.65, '#B28E66');
|
||
baseGrad.addColorStop(1, '#8C6842');
|
||
}
|
||
ctx.fillStyle = baseGrad;
|
||
ctx.fillRect(x, y, width, height);
|
||
|
||
// Top Tabletop Bevel Edge Highlight (Specular reflection from window)
|
||
ctx.fillStyle = isWalnut ? 'rgba(255, 220, 180, 0.28)' : 'rgba(255, 255, 255, 0.55)';
|
||
ctx.fillRect(x, y, width, 3.5);
|
||
|
||
// Organic Wood Grain Fibers & Growth Rings
|
||
ctx.strokeStyle = isWalnut ? 'rgba(25, 12, 6, 0.40)' : 'rgba(120, 85, 48, 0.28)';
|
||
ctx.lineWidth = 1.2;
|
||
for (let gy = y + 8; gy < y + height; gy += 7) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(x, gy);
|
||
const cp1x = x + width * 0.32;
|
||
const cp1y = gy + Math.sin(gy * 0.08) * 8;
|
||
const cp2x = x + width * 0.68;
|
||
const cp2y = gy - Math.cos(gy * 0.06) * 7;
|
||
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x + width, gy + Math.sin(gy * 0.05) * 5);
|
||
ctx.stroke();
|
||
}
|
||
|
||
// Realistic Wood Plank Seams
|
||
ctx.strokeStyle = isWalnut ? 'rgba(10, 5, 2, 0.70)' : 'rgba(90, 60, 30, 0.50)';
|
||
ctx.lineWidth = 2.2;
|
||
for (let px = x + 340; px < x + width; px += 360) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(px, y);
|
||
ctx.lineTo(px, y + height);
|
||
ctx.stroke();
|
||
// Soft shadow on one side of seam
|
||
ctx.fillStyle = 'rgba(0, 0, 0, 0.15)';
|
||
ctx.fillRect(px + 2, y, 4, height);
|
||
}
|
||
ctx.restore();
|
||
}
|
||
|
||
function renderNaturalSunlightBeams(ctx, w, h, intensity = 0.35, color = 'rgba(255, 248, 225, 0.35)') {
|
||
ctx.save();
|
||
ctx.globalCompositeOperation = 'screen';
|
||
const sunbeams = [
|
||
{ x1: w * -0.12, y1: 20, w1: 220, x2: w * 0.48, y2: h, w2: 480, alpha: 0.42 },
|
||
{ x1: w * 0.12, y1: 0, w1: 160, x2: w * 0.78, y2: h, w2: 400, alpha: 0.34 },
|
||
{ x1: w * 0.38, y1: 0, w1: 120, x2: w * 0.96, y2: h, w2: 300, alpha: 0.28 }
|
||
];
|
||
sunbeams.forEach(sb => {
|
||
const grad = ctx.createLinearGradient(sb.x1, sb.y1, sb.x2, sb.y2);
|
||
grad.addColorStop(0, color.replace(/[\d\.]+\)$/, `${sb.alpha * intensity * 2.2})`));
|
||
grad.addColorStop(0.35, color.replace(/[\d\.]+\)$/, `${sb.alpha * intensity * 1.6})`));
|
||
grad.addColorStop(0.75, color.replace(/[\d\.]+\)$/, `${sb.alpha * intensity * 0.7})`));
|
||
grad.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = grad;
|
||
ctx.beginPath();
|
||
ctx.moveTo(sb.x1, sb.y1);
|
||
ctx.lineTo(sb.x1 + sb.w1, sb.y1);
|
||
ctx.lineTo(sb.x2 + sb.w2, sb.y2);
|
||
ctx.lineTo(sb.x2, sb.y2);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
});
|
||
ctx.restore();
|
||
}
|
||
|
||
function renderBotanicalLeafShadows(ctx, w, h) {
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(18, 48, 28, 0.16)';
|
||
// Left Monstera Leaf Silhouette
|
||
ctx.beginPath();
|
||
ctx.ellipse(w * 0.16, h * 0.26, 130, 240, Math.PI / 3.2, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
// Cutout fenestration holes on leaf
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.08)';
|
||
ctx.beginPath();
|
||
ctx.ellipse(w * 0.18, h * 0.24, 30, 70, Math.PI / 3.5, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// Right Palm Fronds
|
||
ctx.fillStyle = 'rgba(18, 48, 28, 0.13)';
|
||
for (let i = 0; i < 6; i++) {
|
||
ctx.beginPath();
|
||
ctx.ellipse(w * 0.82 + i * 22, h * 0.18 + i * 32, 35, 170, -Math.PI / 3.8 + i * 0.08, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
}
|
||
ctx.restore();
|
||
}
|
||
|
||
function renderTravertineTexture(ctx, cx, cy, rx, ry, h = 36) {
|
||
ctx.save();
|
||
// Soft base shadow
|
||
const baseSh = ctx.createRadialGradient(cx, cy + h + 18, 10, cx, cy + h + 18, rx * 1.18);
|
||
baseSh.addColorStop(0, 'rgba(45, 35, 25, 0.45)');
|
||
baseSh.addColorStop(0.5, 'rgba(45, 35, 25, 0.18)');
|
||
baseSh.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = baseSh;
|
||
ctx.beginPath();
|
||
ctx.ellipse(cx, cy + h + 18, rx * 1.18, ry * 1.35, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// Front Chamfer / Vertical Face
|
||
const faceGrad = ctx.createLinearGradient(cx - rx, 0, cx + rx, 0);
|
||
faceGrad.addColorStop(0, '#D4C4AE');
|
||
faceGrad.addColorStop(0.5, '#E5D6C2');
|
||
faceGrad.addColorStop(1, '#C6B59E');
|
||
ctx.fillStyle = faceGrad;
|
||
ctx.fillRect(cx - rx, cy, rx * 2, h);
|
||
|
||
// Porous stone cavities on front face
|
||
ctx.fillStyle = 'rgba(110, 95, 80, 0.35)';
|
||
for (let px = cx - rx + 25; px < cx + rx - 25; px += 40) {
|
||
const py = cy + 10 + (Math.sin(px * 0.05) * 8);
|
||
ctx.beginPath();
|
||
ctx.ellipse(px, py, 4 + Math.cos(px) * 2, 2.5, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
}
|
||
|
||
// Top Stone Surface
|
||
const topGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, rx);
|
||
topGrad.addColorStop(0, '#FAF7F2');
|
||
topGrad.addColorStop(0.6, '#EFEAE1');
|
||
topGrad.addColorStop(1, '#DED6C7');
|
||
ctx.fillStyle = topGrad;
|
||
ctx.beginPath();
|
||
ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// Mineral stone edge bevel
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.75)';
|
||
ctx.lineWidth = 2.8;
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
}
|
||
|
||
function renderRealisticContactShadow(ctx, cx, cy, rx, ry, sunAngle = 45) {
|
||
ctx.save();
|
||
// 1. Tight Ambient Occlusion Contact Line
|
||
const tightAO = ctx.createRadialGradient(cx, cy, 5, cx, cy, rx * 0.72);
|
||
tightAO.addColorStop(0, 'rgba(12, 6, 2, 0.90)');
|
||
tightAO.addColorStop(0.35, 'rgba(18, 9, 4, 0.68)');
|
||
tightAO.addColorStop(0.7, 'rgba(35, 20, 10, 0.28)');
|
||
tightAO.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = tightAO;
|
||
ctx.beginPath();
|
||
ctx.ellipse(cx, cy, rx * 0.72, ry * 0.72, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// 2. Directional Cast Shadow (Angled towards bottom-right)
|
||
const castOffsetX = rx * 0.28;
|
||
const castOffsetY = ry * 0.38;
|
||
const castShadow = ctx.createRadialGradient(cx + castOffsetX, cy + castOffsetY, 15, cx + castOffsetX, cy + castOffsetY, rx * 1.15);
|
||
castShadow.addColorStop(0, 'rgba(22, 14, 8, 0.58)');
|
||
castShadow.addColorStop(0.5, 'rgba(28, 16, 9, 0.26)');
|
||
castShadow.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = castShadow;
|
||
ctx.beginPath();
|
||
ctx.ellipse(cx + castOffsetX, cy + castOffsetY, rx * 1.15, ry * 0.95, Math.PI / 12, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// 3. Wide Ambient Penumbra
|
||
const penumbra = ctx.createRadialGradient(cx, cy + 6, rx * 0.5, cx, cy + 6, rx * 1.55);
|
||
penumbra.addColorStop(0, 'rgba(35, 22, 14, 0.22)');
|
||
penumbra.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = penumbra;
|
||
ctx.beginPath();
|
||
ctx.ellipse(cx, cy + 6, rx * 1.55, ry * 1.25, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
ctx.restore();
|
||
}
|
||
|
||
function renderWaterDewDroplets(ctx, cx, cy, rx, ry) {
|
||
ctx.save();
|
||
const drops = [
|
||
{ x: cx - rx * 0.48, y: cy - ry * 0.32, r: 4.5 },
|
||
{ x: cx + rx * 0.58, y: cy + ry * 0.22, r: 6.0 },
|
||
{ x: cx - rx * 0.28, y: cy + ry * 0.42, r: 3.5 },
|
||
{ x: cx + rx * 0.38, y: cy - ry * 0.42, r: 5.0 },
|
||
{ x: cx + rx * 0.68, y: cy - ry * 0.12, r: 3.8 }
|
||
];
|
||
drops.forEach(d => {
|
||
// Drop Shadow
|
||
ctx.fillStyle = 'rgba(0, 0, 0, 0.35)';
|
||
ctx.beginPath();
|
||
ctx.ellipse(d.x + 1.8, d.y + 1.8, d.r, d.r * 0.65, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
// Water Body
|
||
const dropGrad = ctx.createRadialGradient(d.x - 1, d.y - 1, 0.5, d.x, d.y, d.r);
|
||
dropGrad.addColorStop(0, 'rgba(255, 255, 255, 0.95)');
|
||
dropGrad.addColorStop(0.4, 'rgba(235, 248, 255, 0.72)');
|
||
dropGrad.addColorStop(0.9, 'rgba(180, 225, 245, 0.42)');
|
||
dropGrad.addColorStop(1, 'rgba(100, 165, 205, 0.85)');
|
||
ctx.fillStyle = dropGrad;
|
||
ctx.beginPath();
|
||
ctx.arc(d.x, d.y, d.r, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
// Specular Highlight
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.beginPath();
|
||
ctx.arc(d.x - d.r * 0.35, d.y - d.r * 0.35, d.r * 0.32, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
});
|
||
ctx.restore();
|
||
}
|
||
|
||
function renderSilkFabricDrape(ctx, w, h, stageCy, isBurgundy = true) {
|
||
ctx.save();
|
||
const fabricTopY = stageCy - 30;
|
||
const fabricGrad = ctx.createLinearGradient(0, fabricTopY, 0, h);
|
||
if (isBurgundy) {
|
||
fabricGrad.addColorStop(0, '#4A0D25');
|
||
fabricGrad.addColorStop(0.3, '#7A1840');
|
||
fabricGrad.addColorStop(0.6, '#38091B');
|
||
fabricGrad.addColorStop(1, '#1A040C');
|
||
} else {
|
||
fabricGrad.addColorStop(0, '#B8860B');
|
||
fabricGrad.addColorStop(0.3, '#E6C25E');
|
||
fabricGrad.addColorStop(0.6, '#8C6207');
|
||
fabricGrad.addColorStop(1, '#4A3302');
|
||
}
|
||
ctx.fillStyle = fabricGrad;
|
||
|
||
// Fluid Bezier Wave Drapes
|
||
ctx.beginPath();
|
||
ctx.moveTo(0, fabricTopY + 80);
|
||
ctx.bezierCurveTo(w * 0.25, fabricTopY - 25, w * 0.45, fabricTopY + 130, w * 0.70, fabricTopY + 45);
|
||
ctx.bezierCurveTo(w * 0.85, fabricTopY + 15, w * 0.95, fabricTopY + 65, w, fabricTopY + 55);
|
||
ctx.lineTo(w, h);
|
||
ctx.lineTo(0, h);
|
||
ctx.closePath();
|
||
ctx.fill();
|
||
|
||
// Silk Highlights on wave peaks
|
||
ctx.strokeStyle = isBurgundy ? 'rgba(244, 114, 182, 0.45)' : 'rgba(254, 240, 138, 0.55)';
|
||
ctx.lineWidth = 3.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.05, fabricTopY + 92);
|
||
ctx.bezierCurveTo(w * 0.25, fabricTopY - 5, w * 0.45, fabricTopY + 105, w * 0.70, fabricTopY + 48);
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
}
|
||
|
||
// --- 3D Canvas Multi-Theme Master CGI & 8K Natural Rendering Engine (32 Distinct Styles) ---
|
||
const THEMES = {
|
||
// 🌿 8K NATURAL & LIFESTYLE COMMERCIAL STYLES (NEW)
|
||
natural_scandi_wood: {
|
||
name: "8K Scandinavian Oak & Soft Linen",
|
||
category: "natural",
|
||
isNatural: true,
|
||
naturalType: "scandi_wood",
|
||
bgCenter: '#FAF6F0', bgMid: '#EFEAE1', bgOuter: '#DDD5C7',
|
||
sunlightColor: 'rgba(255, 248, 230, 0.38)',
|
||
woodType: 'oak',
|
||
accentColor: '#8C6D46',
|
||
goldRim: '#A07D54', goldAccent: '#F5EFE6',
|
||
borderStyle: 'natural_nordic'
|
||
},
|
||
natural_botanical_sun: {
|
||
name: "8K Botanical Morning & Dew",
|
||
category: "natural",
|
||
isNatural: true,
|
||
naturalType: "botanical_sun",
|
||
bgCenter: '#F4F9F4', bgMid: '#E5EFE5', bgOuter: '#D2DFD2',
|
||
sunlightColor: 'rgba(255, 250, 220, 0.42)',
|
||
accentColor: '#059669',
|
||
goldRim: '#10B981', goldAccent: '#6EE7B7',
|
||
borderStyle: 'natural_botanical'
|
||
},
|
||
natural_kbeauty_glow: {
|
||
name: "8K K-Beauty Travertine & Glass Glow",
|
||
category: "natural",
|
||
isNatural: true,
|
||
naturalType: "kbeauty_travertine",
|
||
bgCenter: '#FAF8F5', bgMid: '#F2ECE1', bgOuter: '#E2D8C7',
|
||
sunlightColor: 'rgba(255, 245, 235, 0.40)',
|
||
accentColor: '#DB2777',
|
||
goldRim: '#F472B6', goldAccent: '#FCE7F3',
|
||
borderStyle: 'natural_kbeauty'
|
||
},
|
||
natural_warm_cafe: {
|
||
name: "8K Artisan Dark Walnut & Café",
|
||
category: "natural",
|
||
isNatural: true,
|
||
naturalType: "warm_cafe",
|
||
bgCenter: '#2C1E17', bgMid: '#1C120D', bgOuter: '#0C0704',
|
||
sunlightColor: 'rgba(251, 191, 36, 0.28)',
|
||
woodType: 'walnut',
|
||
accentColor: '#F59E0B',
|
||
goldRim: '#D97706', goldAccent: '#FDE68A',
|
||
borderStyle: 'natural_cafe'
|
||
},
|
||
natural_sunlit_travertine: {
|
||
name: "8K Sun-Kissed Terracotta & Sand",
|
||
category: "natural",
|
||
isNatural: true,
|
||
naturalType: "sunlit_sand",
|
||
bgCenter: '#FAF5EE', bgMid: '#EFE3D0', bgOuter: '#DECDB5',
|
||
sunlightColor: 'rgba(254, 215, 170, 0.48)',
|
||
accentColor: '#EA580C',
|
||
goldRim: '#F97316', goldAccent: '#FFEDD5',
|
||
borderStyle: 'natural_terracotta'
|
||
},
|
||
natural_minimal_flatlay: {
|
||
name: "8K Minimalist Studio Flatlay",
|
||
category: "natural",
|
||
isNatural: true,
|
||
naturalType: "minimal_flatlay",
|
||
bgCenter: '#F8F9FA', bgMid: '#EDEFF2', bgOuter: '#DFE3E8',
|
||
sunlightColor: 'rgba(255, 255, 255, 0.50)',
|
||
accentColor: '#2563EB',
|
||
goldRim: '#3B82F6', goldAccent: '#DBEAFE',
|
||
borderStyle: 'natural_flatlay'
|
||
},
|
||
natural_velvet_drape: {
|
||
name: "8K Royal Mulberry Silk & Velvet",
|
||
category: "natural",
|
||
isNatural: true,
|
||
naturalType: "velvet_drape",
|
||
bgCenter: '#2B0818', bgMid: '#18040C', bgOuter: '#080104',
|
||
sunlightColor: 'rgba(254, 243, 199, 0.32)',
|
||
accentColor: '#F59E0B',
|
||
goldRim: '#EAB308', goldAccent: '#FEF08A',
|
||
borderStyle: 'natural_silk'
|
||
},
|
||
|
||
// 👑 3D COMMERCIAL STAGES & PODIUMS
|
||
obsidian_gold: {
|
||
name: "Obsidian & 24K Gold",
|
||
category: "stage",
|
||
bgCenter: '#141D29', bgMid: '#0A0E15', bgOuter: '#020305',
|
||
beamTop: 'rgba(255, 255, 255, 0.40)', beamMid: 'rgba(224, 231, 255, 0.22)', beamLow: 'rgba(199, 210, 254, 0.08)',
|
||
haloCenter: 'rgba(224, 231, 255, 0.25)', haloMid: 'rgba(147, 197, 253, 0.10)',
|
||
goldRim: '#E5B83A', goldAccent: '#FDE68A',
|
||
pedestalTop: '#1E293B', pedestalMid: '#0F172A', pedestalDark: '#020617',
|
||
cylStart: '#78350F', cylMid: '#FDE68A', cylEnd: '#78350F',
|
||
borderStyle: 'gold_rim'
|
||
},
|
||
mughal_heritage: {
|
||
name: "Mughal Royal Palace Arch",
|
||
category: "stage",
|
||
bgCenter: '#2A1508', bgMid: '#180B04', bgOuter: '#070301',
|
||
beamTop: 'rgba(254, 243, 199, 0.45)', beamMid: 'rgba(251, 191, 36, 0.25)', beamLow: 'rgba(180, 83, 9, 0.10)',
|
||
haloCenter: 'rgba(253, 230, 138, 0.35)', haloMid: 'rgba(217, 119, 6, 0.15)',
|
||
goldRim: '#F59E0B', goldAccent: '#FDE68A',
|
||
pedestalTop: '#451A03', pedestalMid: '#291002', pedestalDark: '#120701',
|
||
cylStart: '#78350F', cylMid: '#FDE68A', cylEnd: '#78350F',
|
||
borderStyle: 'mughal_arch'
|
||
},
|
||
brutalist_street: {
|
||
name: "Brutalist Urban Street",
|
||
bgCenter: '#1E1E1E', bgMid: '#121212', bgOuter: '#080808',
|
||
beamTop: 'rgba(250, 204, 21, 0.35)', beamMid: 'rgba(234, 179, 8, 0.18)', beamLow: 'rgba(161, 98, 7, 0.08)',
|
||
haloCenter: 'rgba(250, 204, 21, 0.22)', haloMid: 'rgba(202, 138, 4, 0.10)',
|
||
goldRim: '#FACC15', goldAccent: '#FEF08A',
|
||
pedestalTop: '#3F3F46', pedestalMid: '#27272A', pedestalDark: '#18181B',
|
||
cylStart: '#EAB308', cylMid: '#18181B', cylEnd: '#EAB308',
|
||
borderStyle: 'hazard_stamp'
|
||
},
|
||
cyber_neon: {
|
||
name: "Cyber Neon Matrix",
|
||
bgCenter: '#0F1E2E', bgMid: '#070E18', bgOuter: '#020408',
|
||
beamTop: 'rgba(240, 249, 255, 0.40)', beamMid: 'rgba(186, 230, 253, 0.22)', beamLow: 'rgba(6, 182, 212, 0.08)',
|
||
haloCenter: 'rgba(56, 189, 248, 0.25)', haloMid: 'rgba(6, 182, 212, 0.10)',
|
||
goldRim: '#06B6D4', goldAccent: '#38BDF8',
|
||
pedestalTop: '#082F49', pedestalMid: '#031E30', pedestalDark: '#020B12',
|
||
cylStart: '#082F49', cylMid: '#38BDF8', cylEnd: '#082F49',
|
||
borderStyle: 'neon_grid'
|
||
},
|
||
editorial_vogue: {
|
||
name: "Vogue High-Fashion Editorial",
|
||
bgCenter: '#1E1B18', bgMid: '#110F0D', bgOuter: '#050403',
|
||
beamTop: 'rgba(255, 255, 255, 0.50)', beamMid: 'rgba(245, 245, 244, 0.25)', beamLow: 'rgba(214, 211, 209, 0.08)',
|
||
haloCenter: 'rgba(250, 250, 249, 0.28)', haloMid: 'rgba(168, 162, 158, 0.10)',
|
||
goldRim: '#E7E5E4', goldAccent: '#FFFFFF',
|
||
pedestalTop: '#292524', pedestalMid: '#1C1917', pedestalDark: '#0C0A09',
|
||
cylStart: '#44403C', cylMid: '#E7E5E4', cylEnd: '#292524',
|
||
borderStyle: 'vogue_mag'
|
||
},
|
||
botanical_eco: {
|
||
name: "Botanical Zen Garden",
|
||
bgCenter: '#12241A', bgMid: '#09140E', bgOuter: '#020503',
|
||
beamTop: 'rgba(240, 253, 244, 0.40)', beamMid: 'rgba(187, 247, 208, 0.22)', beamLow: 'rgba(16, 185, 129, 0.08)',
|
||
haloCenter: 'rgba(52, 211, 153, 0.25)', haloMid: 'rgba(16, 185, 129, 0.10)',
|
||
goldRim: '#10B981', goldAccent: '#6EE7B7',
|
||
pedestalTop: '#064E3B', pedestalMid: '#022C22', pedestalDark: '#011711',
|
||
cylStart: '#064E3B', cylMid: '#6EE7B7', cylEnd: '#064E3B',
|
||
borderStyle: 'eco_leaves'
|
||
},
|
||
holographic_prism: {
|
||
name: "Holographic Prism Chromatic",
|
||
bgCenter: '#18122B', bgMid: '#0E0B1A', bgOuter: '#040308',
|
||
beamTop: 'rgba(232, 121, 249, 0.40)', beamMid: 'rgba(129, 140, 248, 0.22)', beamLow: 'rgba(56, 189, 248, 0.08)',
|
||
haloCenter: 'rgba(244, 114, 182, 0.30)', haloMid: 'rgba(168, 85, 247, 0.12)',
|
||
goldRim: '#C084FC', goldAccent: '#F0ABFC',
|
||
pedestalTop: '#3B0764', pedestalMid: '#1E1B4B', pedestalDark: '#090514',
|
||
cylStart: '#9333EA', cylMid: '#38BDF8', cylEnd: '#EC4899',
|
||
borderStyle: 'prism_spectrum'
|
||
},
|
||
tokyo_synthwave: {
|
||
name: "Tokyo Synthwave Neon Sunset",
|
||
bgCenter: '#1E0B36', bgMid: '#100520', bgOuter: '#04010A',
|
||
beamTop: 'rgba(244, 114, 182, 0.45)', beamMid: 'rgba(168, 85, 247, 0.24)', beamLow: 'rgba(56, 189, 248, 0.10)',
|
||
haloCenter: 'rgba(244, 63, 94, 0.30)', haloMid: 'rgba(168, 85, 247, 0.14)',
|
||
goldRim: '#F43F5E', goldAccent: '#38BDF8',
|
||
pedestalTop: '#3B0764', pedestalMid: '#18022B', pedestalDark: '#080010',
|
||
cylStart: '#A21CAF', cylMid: '#F43F5E', cylEnd: '#0284C7',
|
||
borderStyle: 'synthwave_grid'
|
||
},
|
||
frost_titanium: {
|
||
name: "Frost Arctic Titanium Ice",
|
||
bgCenter: '#132337', bgMid: '#0A131F', bgOuter: '#03060B',
|
||
beamTop: 'rgba(224, 242, 254, 0.50)', beamMid: 'rgba(186, 230, 253, 0.26)', beamLow: 'rgba(125, 211, 252, 0.09)',
|
||
haloCenter: 'rgba(224, 242, 254, 0.35)', haloMid: 'rgba(56, 189, 248, 0.14)',
|
||
goldRim: '#38BDF8', goldAccent: '#E0F2FE',
|
||
pedestalTop: '#0C4A6E', pedestalMid: '#082F49', pedestalDark: '#021420',
|
||
cylStart: '#0369A1', cylMid: '#E0F2FE', cylEnd: '#0C4A6E',
|
||
borderStyle: 'frost_ice'
|
||
},
|
||
vip_blackcard: {
|
||
name: "VIP Platinum Blackcard",
|
||
bgCenter: '#141417', bgMid: '#0A0A0C', bgOuter: '#020203',
|
||
beamTop: 'rgba(255, 255, 255, 0.35)', beamMid: 'rgba(212, 212, 216, 0.18)', beamLow: 'rgba(113, 113, 122, 0.06)',
|
||
haloCenter: 'rgba(228, 228, 231, 0.22)', haloMid: 'rgba(161, 161, 170, 0.08)',
|
||
goldRim: '#D4AF37', goldAccent: '#F3E5AB',
|
||
pedestalTop: '#18181B', pedestalMid: '#09090B', pedestalDark: '#000000',
|
||
cylStart: '#52525B', cylMid: '#D4AF37', cylEnd: '#27272A',
|
||
borderStyle: 'blackcard_crest'
|
||
},
|
||
sunset_amber: {
|
||
name: "Sunset Amber Golden Hour",
|
||
bgCenter: '#381608', bgMid: '#200C04', bgOuter: '#0A0301',
|
||
beamTop: 'rgba(254, 215, 170, 0.50)', beamMid: 'rgba(251, 146, 60, 0.26)', beamLow: 'rgba(234, 88, 12, 0.10)',
|
||
haloCenter: 'rgba(253, 186, 116, 0.35)', haloMid: 'rgba(249, 115, 22, 0.15)',
|
||
goldRim: '#FB923C', goldAccent: '#FED7AA',
|
||
pedestalTop: '#7C2D12', pedestalMid: '#431407', pedestalDark: '#1C0602',
|
||
cylStart: '#C2410C', cylMid: '#FED7AA', cylEnd: '#7C2D12',
|
||
borderStyle: 'sunset_rays'
|
||
},
|
||
flash_sale_matrix: {
|
||
name: "Flash Sale Matrix Energy",
|
||
bgCenter: '#260B0B', bgMid: '#140404', bgOuter: '#050101',
|
||
beamTop: 'rgba(248, 113, 113, 0.50)', beamMid: 'rgba(239, 68, 68, 0.28)', beamLow: 'rgba(185, 28, 28, 0.12)',
|
||
haloCenter: 'rgba(252, 165, 165, 0.35)', haloMid: 'rgba(239, 68, 68, 0.15)',
|
||
goldRim: '#EF4444', goldAccent: '#FCA5A5',
|
||
pedestalTop: '#7F1D1D', pedestalMid: '#450A0A', pedestalDark: '#1C0202',
|
||
cylStart: '#B91C1C', cylMid: '#F87171', cylEnd: '#7F1D1D',
|
||
borderStyle: 'flash_energy'
|
||
},
|
||
velvet_burgundy: {
|
||
name: "Velvet Royal Burgundy",
|
||
bgCenter: '#2D0A1E', bgMid: '#180410', bgOuter: '#060104',
|
||
beamTop: 'rgba(251, 207, 232, 0.40)', beamMid: 'rgba(244, 114, 182, 0.22)', beamLow: 'rgba(190, 24, 93, 0.08)',
|
||
haloCenter: 'rgba(244, 114, 182, 0.28)', haloMid: 'rgba(157, 23, 77, 0.12)',
|
||
goldRim: '#DB2777', goldAccent: '#FBCFE8',
|
||
pedestalTop: '#500724', pedestalMid: '#2B0413', pedestalDark: '#120108',
|
||
cylStart: '#9D174D', cylMid: '#F472B6', cylEnd: '#500724',
|
||
borderStyle: 'velvet_ripples'
|
||
},
|
||
rose_quartz: {
|
||
name: "Rose Quartz & Silk",
|
||
bgCenter: '#261220', bgMid: '#140810', bgOuter: '#050204',
|
||
beamTop: 'rgba(255, 240, 245, 0.40)', beamMid: 'rgba(253, 232, 241, 0.22)', beamLow: 'rgba(244, 114, 182, 0.08)',
|
||
haloCenter: 'rgba(251, 207, 232, 0.28)', haloMid: 'rgba(244, 114, 182, 0.12)',
|
||
goldRim: '#F472B6', goldAccent: '#FCE7F3',
|
||
pedestalTop: '#FFF1F2', pedestalMid: '#FCE7F3', pedestalDark: '#371829',
|
||
cylStart: '#831843', cylMid: '#F472B6', cylEnd: '#831843',
|
||
borderStyle: 'rose_waves'
|
||
},
|
||
midnight_sapphire: {
|
||
name: "Midnight Sapphire Crystal",
|
||
bgCenter: '#0B1B3D', bgMid: '#060E21', bgOuter: '#02050E',
|
||
beamTop: 'rgba(191, 219, 254, 0.45)', beamMid: 'rgba(96, 165, 250, 0.22)', beamLow: 'rgba(37, 99, 235, 0.08)',
|
||
haloCenter: 'rgba(147, 197, 253, 0.30)', haloMid: 'rgba(59, 130, 246, 0.12)',
|
||
goldRim: '#60A5FA', goldAccent: '#BFDBFE',
|
||
pedestalTop: '#1E3A8A', pedestalMid: '#172554', pedestalDark: '#0A1128',
|
||
cylStart: '#1E3A8A', cylMid: '#93C5FD', cylEnd: '#172554',
|
||
borderStyle: 'sapphire_glow'
|
||
},
|
||
nordic_minimal: {
|
||
name: "Nordic Minimalist Lightbox",
|
||
bgCenter: '#2D3748', bgMid: '#1A202C', bgOuter: '#0D1117',
|
||
beamTop: 'rgba(255, 255, 255, 0.45)', beamMid: 'rgba(226, 232, 240, 0.25)', beamLow: 'rgba(148, 163, 184, 0.08)',
|
||
haloCenter: 'rgba(241, 245, 249, 0.30)', haloMid: 'rgba(148, 163, 184, 0.12)',
|
||
goldRim: '#CBD5E1', goldAccent: '#F8FAFC',
|
||
pedestalTop: '#E2E8F0', pedestalMid: '#94A3B8', pedestalDark: '#334155',
|
||
cylStart: '#475569', cylMid: '#CBD5E1', cylEnd: '#334155',
|
||
borderStyle: 'nordic_clean'
|
||
},
|
||
art_deco_gilded: {
|
||
name: "Art Deco Gilded Gatsby",
|
||
bgCenter: '#1A150D', bgMid: '#0E0B07', bgOuter: '#040302',
|
||
beamTop: 'rgba(254, 240, 138, 0.45)', beamMid: 'rgba(234, 179, 8, 0.22)', beamLow: 'rgba(161, 98, 7, 0.08)',
|
||
haloCenter: 'rgba(254, 240, 138, 0.32)', haloMid: 'rgba(202, 138, 4, 0.12)',
|
||
goldRim: '#EAB308', goldAccent: '#FEF08A',
|
||
pedestalTop: '#292010', pedestalMid: '#161108', pedestalDark: '#0A0703',
|
||
cylStart: '#854D0E', cylMid: '#FEF08A', cylEnd: '#854D0E',
|
||
borderStyle: 'art_deco_fan'
|
||
},
|
||
cosmic_nebula: {
|
||
name: "Cosmic Nebula Orbit",
|
||
bgCenter: '#200E3B', bgMid: '#100624', bgOuter: '#04010D',
|
||
beamTop: 'rgba(216, 180, 254, 0.45)', beamMid: 'rgba(168, 85, 247, 0.22)', beamLow: 'rgba(107, 33, 168, 0.08)',
|
||
haloCenter: 'rgba(192, 132, 252, 0.32)', haloMid: 'rgba(147, 51, 234, 0.14)',
|
||
goldRim: '#C084FC', goldAccent: '#F3E8FF',
|
||
pedestalTop: '#3B0764', pedestalMid: '#1E1B4B', pedestalDark: '#0B0518',
|
||
cylStart: '#7E22CE', cylMid: '#E879F9', cylEnd: '#3B0764',
|
||
borderStyle: 'cosmic_stars'
|
||
},
|
||
kraft_artisan: {
|
||
name: "Kraft Artisan Workshop",
|
||
bgCenter: '#2B1E14', bgMid: '#1A120B', bgOuter: '#0C0804',
|
||
beamTop: 'rgba(254, 243, 199, 0.40)', beamMid: 'rgba(217, 119, 6, 0.20)', beamLow: 'rgba(146, 64, 14, 0.08)',
|
||
haloCenter: 'rgba(253, 230, 138, 0.28)', haloMid: 'rgba(180, 83, 9, 0.12)',
|
||
goldRim: '#D97706', goldAccent: '#FDE68A',
|
||
pedestalTop: '#451A03', pedestalMid: '#291002', pedestalDark: '#170801',
|
||
cylStart: '#78350F', cylMid: '#D97706', cylEnd: '#451A03',
|
||
borderStyle: 'kraft_stamp'
|
||
},
|
||
arcade_retro: {
|
||
name: "Arcade Cyber Pixel",
|
||
bgCenter: '#10172A', bgMid: '#060B18', bgOuter: '#010309',
|
||
beamTop: 'rgba(56, 189, 248, 0.45)', beamMid: 'rgba(244, 63, 94, 0.22)', beamLow: 'rgba(168, 85, 247, 0.08)',
|
||
haloCenter: 'rgba(56, 189, 248, 0.30)', haloMid: 'rgba(244, 63, 94, 0.14)',
|
||
goldRim: '#FACC15', goldAccent: '#38BDF8',
|
||
pedestalTop: '#0F172A', pedestalMid: '#020617', pedestalDark: '#000000',
|
||
cylStart: '#0284C7', cylMid: '#FACC15', cylEnd: '#E11D48',
|
||
borderStyle: 'pixel_grid'
|
||
},
|
||
bento_grid_luxe: {
|
||
name: "Apple Bento Spec Grid",
|
||
bgCenter: '#161922', bgMid: '#0D1017', bgOuter: '#05070B',
|
||
beamTop: 'rgba(255, 255, 255, 0.40)', beamMid: 'rgba(224, 231, 255, 0.20)', beamLow: 'rgba(148, 163, 184, 0.08)',
|
||
haloCenter: 'rgba(224, 231, 255, 0.28)', haloMid: 'rgba(148, 163, 184, 0.12)',
|
||
goldRim: '#38BDF8', goldAccent: '#F8FAFC',
|
||
pedestalTop: '#1E293B', pedestalMid: '#0F172A', pedestalDark: '#020617',
|
||
cylStart: '#334155', cylMid: '#38BDF8', cylEnd: '#0F172A',
|
||
borderStyle: 'bento_grid'
|
||
},
|
||
swiss_modular_grid: {
|
||
name: "Swiss Bauhaus Modular Grid",
|
||
bgCenter: '#18181B', bgMid: '#0F0F12', bgOuter: '#060608',
|
||
beamTop: 'rgba(255, 255, 255, 0.45)', beamMid: 'rgba(244, 63, 94, 0.20)', beamLow: 'rgba(255, 255, 255, 0.06)',
|
||
haloCenter: 'rgba(255, 255, 255, 0.25)', haloMid: 'rgba(244, 63, 94, 0.10)',
|
||
goldRim: '#F43F5E', goldAccent: '#FFFFFF',
|
||
pedestalTop: '#27272A', pedestalMid: '#18181B', pedestalDark: '#09090B',
|
||
cylStart: '#E11D48', cylMid: '#FFFFFF', cylEnd: '#18181B',
|
||
borderStyle: 'swiss_grid'
|
||
},
|
||
blueprint_cad_grid: {
|
||
name: "Industrial CAD Blueprint Grid",
|
||
bgCenter: '#0A2540', bgMid: '#061727', bgOuter: '#020B14',
|
||
beamTop: 'rgba(56, 189, 248, 0.45)', beamMid: 'rgba(14, 165, 233, 0.22)', beamLow: 'rgba(2, 132, 199, 0.08)',
|
||
haloCenter: 'rgba(56, 189, 248, 0.32)', haloMid: 'rgba(14, 165, 233, 0.12)',
|
||
goldRim: '#38BDF8', goldAccent: '#BAE6FD',
|
||
pedestalTop: '#0C4A6E', pedestalMid: '#082F49', pedestalDark: '#031926',
|
||
cylStart: '#0284C7', cylMid: '#BAE6FD', cylEnd: '#0C4A6E',
|
||
borderStyle: 'cad_blueprint'
|
||
},
|
||
polaroid_film_grid: {
|
||
name: "Vintage Filmstrip Gallery Grid",
|
||
bgCenter: '#1C1613', bgMid: '#100C0A', bgOuter: '#050302',
|
||
beamTop: 'rgba(254, 243, 199, 0.40)', beamMid: 'rgba(217, 119, 6, 0.20)', beamLow: 'rgba(180, 83, 9, 0.08)',
|
||
haloCenter: 'rgba(253, 230, 138, 0.28)', haloMid: 'rgba(217, 119, 6, 0.12)',
|
||
goldRim: '#D97706', goldAccent: '#FDE68A',
|
||
pedestalTop: '#29180E', pedestalMid: '#160D07', pedestalDark: '#080402',
|
||
cylStart: '#78350F', cylMid: '#FDE68A', cylEnd: '#29180E',
|
||
borderStyle: 'film_strip'
|
||
},
|
||
cyber_hud_grid: {
|
||
name: "Tron Cyber HUD Telemetry Grid",
|
||
bgCenter: '#0A192F', bgMid: '#050D1A', bgOuter: '#010408',
|
||
beamTop: 'rgba(0, 255, 204, 0.45)', beamMid: 'rgba(6, 182, 212, 0.22)', beamLow: 'rgba(2, 132, 199, 0.08)',
|
||
haloCenter: 'rgba(0, 255, 204, 0.35)', haloMid: 'rgba(6, 182, 212, 0.14)',
|
||
goldRim: '#00FFCC', goldAccent: '#A7F3D0',
|
||
pedestalTop: '#064E3B', pedestalMid: '#022C22', pedestalDark: '#011711',
|
||
cylStart: '#059669', cylMid: '#00FFCC', cylEnd: '#064E3B',
|
||
borderStyle: 'tron_hud'
|
||
}
|
||
};
|
||
|
||
async function render3DCommercialPoster(canvas, productImg, title, price, badgeText, theme = 'obsidian_gold', aspect = '1:1', brand = 'glamourstouch', customOverrides = null) {
|
||
const ctx = canvas.getContext('2d');
|
||
const w = canvas.width;
|
||
const h = canvas.height;
|
||
|
||
const baseBrand = getBrandProfile(brand);
|
||
const brandInfo = Object.assign({}, baseBrand, customOverrides || {});
|
||
const currentTheme = THEMES[theme] || THEMES.obsidian_gold;
|
||
|
||
// ================= 8K NATURAL & LIFESTYLE PHOTOGRAPHY PIPELINE =================
|
||
if (currentTheme.isNatural) {
|
||
const nType = currentTheme.naturalType;
|
||
const isDarkTheme = (nType === 'warm_cafe' || nType === 'velvet_drape');
|
||
const stageY = aspect === '9:16' ? h * 0.62 : h * 0.58;
|
||
|
||
// 1. Natural Ambient Plaster / Linen Backdrop
|
||
const naturalGrad = ctx.createLinearGradient(0, 0, w, h);
|
||
naturalGrad.addColorStop(0, currentTheme.bgCenter);
|
||
naturalGrad.addColorStop(0.5, currentTheme.bgMid);
|
||
naturalGrad.addColorStop(1, currentTheme.bgOuter);
|
||
ctx.fillStyle = naturalGrad;
|
||
ctx.fillRect(0, 0, w, h);
|
||
|
||
// 2. Natural Sunbeams (God Rays) from top-left
|
||
renderNaturalSunlightBeams(ctx, w, h, 0.45, currentTheme.sunlightColor || 'rgba(255, 248, 225, 0.35)');
|
||
|
||
// 3. Botanical Leaf Shadows if applicable
|
||
if (nType === 'botanical_sun' || nType === 'kbeauty_travertine') {
|
||
renderBotanicalLeafShadows(ctx, w, h);
|
||
}
|
||
|
||
// 4. Natural Surface Tabletop / Slab
|
||
const tableTopY = aspect === '9:16' ? h * 0.65 : h * 0.60;
|
||
const tableH = h - tableTopY;
|
||
if (nType === 'scandi_wood' || nType === 'warm_cafe') {
|
||
renderNaturalWoodGrain(ctx, 0, tableTopY, w, tableH, nType === 'warm_cafe');
|
||
} else if (nType === 'kbeauty_travertine' || nType === 'botanical_sun') {
|
||
renderTravertineTexture(ctx, w * 0.60, tableTopY + 45, w * 0.36, 32, 42);
|
||
} else if (nType === 'sunlit_sand') {
|
||
ctx.save();
|
||
const sandGrad = ctx.createLinearGradient(0, tableTopY, 0, h);
|
||
sandGrad.addColorStop(0, '#EAD7BE');
|
||
sandGrad.addColorStop(0.4, '#DCBF9E');
|
||
sandGrad.addColorStop(1, '#C7A37E');
|
||
ctx.fillStyle = sandGrad;
|
||
ctx.fillRect(0, tableTopY, w, tableH);
|
||
renderTravertineTexture(ctx, w * 0.60, tableTopY + 45, w * 0.36, 30, 38);
|
||
ctx.restore();
|
||
} else if (nType === 'minimal_flatlay') {
|
||
ctx.save();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillRect(35, 95, w - 70, h - 205);
|
||
ctx.strokeStyle = 'rgba(0,0,0,0.08)';
|
||
ctx.lineWidth = 1.2;
|
||
ctx.strokeRect(35, 95, w - 70, h - 205);
|
||
const crops = [{ x: 25, y: 85 }, { x: w - 25, y: 85 }, { x: 25, y: h - 100 }, { x: w - 25, y: h - 100 }];
|
||
crops.forEach(c => {
|
||
ctx.beginPath(); ctx.moveTo(c.x - 10, c.y); ctx.lineTo(c.x + 10, c.y); ctx.stroke();
|
||
ctx.beginPath(); ctx.moveTo(c.x, c.y - 10); ctx.lineTo(c.x, c.y + 10); ctx.stroke();
|
||
});
|
||
ctx.restore();
|
||
} else if (nType === 'velvet_drape') {
|
||
renderSilkFabricDrape(ctx, w, h, tableTopY, true);
|
||
}
|
||
|
||
// 5. Intelligent Product Cutout & Placement on Natural Tabletop
|
||
if (productImg) {
|
||
const pSize = aspect === '9:16' ? 700 : 540;
|
||
// Position product on the right side of the canvas, resting solidly on the table
|
||
const pCenterX = aspect === '9:16' ? (w / 2) : (w * 0.62);
|
||
const groundY = aspect === '9:16' ? (h * 0.74) : (h * 0.73);
|
||
const pLeft = pCenterX - pSize / 2;
|
||
const pTop = groundY - pSize * 0.88;
|
||
|
||
// Realistic Soft Contact Occlusion Shadow directly on the wood/stone surface
|
||
renderRealisticContactShadow(ctx, pCenterX, groundY, pSize * 0.38, 22, 45);
|
||
|
||
// Smart Cutout Matting (Removes pure white backdrops & smoothly feathers photo edges)
|
||
// Smart Cutout Matting (Removes pure white/dark studio backdrops & smoothly feathers photo edges)
|
||
const pCan = document.createElement('canvas');
|
||
pCan.width = productImg.width || 600;
|
||
pCan.height = productImg.height || 600;
|
||
const pCtx = pCan.getContext('2d');
|
||
pCtx.drawImage(productImg, 0, 0, pCan.width, pCan.height);
|
||
|
||
try {
|
||
const imgData = pCtx.getImageData(0, 0, pCan.width, pCan.height);
|
||
const d = imgData.data;
|
||
const pw = pCan.width;
|
||
const ph = pCan.height;
|
||
const featherDist = 24; // Pixels from border to smoothly fade
|
||
|
||
// Sample 7 border points to detect background color
|
||
let sampleR = 0, sampleG = 0, sampleB = 0, sampleCount = 0;
|
||
const cornerCoords = [
|
||
[2, 2], [pw - 3, 2], [2, ph - 3], [pw - 3, ph - 3],
|
||
[Math.floor(pw / 2), 2], [2, Math.floor(ph / 2)], [pw - 3, Math.floor(ph / 2)]
|
||
];
|
||
cornerCoords.forEach(([cx, cy]) => {
|
||
const ci = (cy * pw + cx) * 4;
|
||
if (d[ci + 3] > 100) {
|
||
sampleR += d[ci];
|
||
sampleG += d[ci + 1];
|
||
sampleB += d[ci + 2];
|
||
sampleCount++;
|
||
}
|
||
});
|
||
|
||
const hasBgSample = sampleCount > 0;
|
||
const bgR = hasBgSample ? sampleR / sampleCount : 255;
|
||
const bgG = hasBgSample ? sampleG / sampleCount : 255;
|
||
const bgB = hasBgSample ? sampleB / sampleCount : 255;
|
||
const bgBrightness = bgR * 0.299 + bgG * 0.587 + bgB * 0.114;
|
||
|
||
for (let y = 0; y < ph; y++) {
|
||
for (let x = 0; x < pw; x++) {
|
||
const i = (y * pw + x) * 4;
|
||
if (d[i + 3] === 0) continue;
|
||
|
||
const r = d[i], g = d[i + 1], b = d[i + 2];
|
||
const brightness = (r * 0.299 + g * 0.587 + b * 0.114);
|
||
const maxC = Math.max(r, g, b);
|
||
const minC = Math.min(r, g, b);
|
||
|
||
// 1. Remove white/light grey studio background
|
||
if (brightness > 224 && (maxC - minC) < 28) {
|
||
if (brightness >= 242) {
|
||
d[i + 3] = 0;
|
||
} else {
|
||
const alphaFactor = (242 - brightness) / 18;
|
||
d[i + 3] = Math.round(d[i + 3] * Math.max(0, alphaFactor));
|
||
}
|
||
}
|
||
// 2. Remove dark studio background if border was dark
|
||
else if (bgBrightness < 50 && brightness < 45 && (maxC - minC) < 25) {
|
||
if (brightness <= 24) {
|
||
d[i + 3] = 0;
|
||
} else {
|
||
const alphaFactor = (brightness - 24) / 21;
|
||
d[i + 3] = Math.round(d[i + 3] * Math.max(0, alphaFactor));
|
||
}
|
||
}
|
||
// 3. Match detected uniform background color distance
|
||
else if (hasBgSample && !isDarkTheme) {
|
||
const colorDist = Math.sqrt(
|
||
Math.pow(r - bgR, 2) + Math.pow(g - bgG, 2) + Math.pow(b - bgB, 2)
|
||
);
|
||
if (colorDist < 28) {
|
||
d[i + 3] = 0;
|
||
} else if (colorDist < 46) {
|
||
const alphaFactor = (colorDist - 28) / 18;
|
||
d[i + 3] = Math.round(d[i + 3] * alphaFactor);
|
||
}
|
||
}
|
||
|
||
// 4. Smooth edge feathering for non-cutout square borders
|
||
if (d[i + 3] > 0) {
|
||
const distLeft = x;
|
||
const distRight = pw - 1 - x;
|
||
const distTop = y;
|
||
const distBottom = ph - 1 - y;
|
||
const minDist = Math.min(distLeft, distRight, distTop, distBottom);
|
||
|
||
if (minDist < featherDist) {
|
||
const edgeFade = Math.pow(minDist / featherDist, 1.2);
|
||
d[i + 3] = Math.round(d[i + 3] * edgeFade);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
pCtx.putImageData(imgData, 0, 0);
|
||
} catch (e) {
|
||
// Fallback radial fade if cross-origin image blocks pixel read
|
||
pCtx.globalCompositeOperation = 'destination-in';
|
||
const fadeGrad = pCtx.createRadialGradient(
|
||
pCan.width / 2, pCan.height * 0.48, pCan.width * 0.38,
|
||
pCan.width / 2, pCan.height * 0.48, pCan.width * 0.495
|
||
);
|
||
fadeGrad.addColorStop(0, 'rgba(0,0,0,1)');
|
||
fadeGrad.addColorStop(0.90, 'rgba(0,0,0,1)');
|
||
fadeGrad.addColorStop(1, 'rgba(0,0,0,0)');
|
||
pCtx.fillStyle = fadeGrad;
|
||
pCtx.fillRect(0, 0, pCan.width, pCan.height);
|
||
}
|
||
|
||
ctx.save();
|
||
ctx.shadowColor = isDarkTheme ? 'rgba(0, 0, 0, 0.70)' : 'rgba(30, 15, 5, 0.35)';
|
||
ctx.shadowBlur = 26;
|
||
ctx.shadowOffsetY = 14;
|
||
ctx.drawImage(pCan, pLeft, pTop, pSize, pSize);
|
||
ctx.restore();
|
||
|
||
if (nType === 'botanical_sun' || nType === 'kbeauty_travertine') {
|
||
renderWaterDewDroplets(ctx, pCenterX, groundY + 14, pSize * 0.32, 22);
|
||
}
|
||
}
|
||
|
||
// 6. TOP EDITORIAL BRAND MASTHEAD (Airy, Sophisticated, Unboxed)
|
||
ctx.save();
|
||
const brandName = (brandInfo.headerTitle || brandInfo.id || "GLAMOUR'S TOUCH")
|
||
.replace(/[^\w\s\u0980-\u09FF']/gi, '').trim().toUpperCase();
|
||
|
||
// Brand Spaced Lettering
|
||
ctx.fillStyle = isDarkTheme ? '#FDE68A' : '#2A1A0E';
|
||
ctx.font = 'bold 20px Playfair Display, Georgia, serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`◈ ${brandName}`, 42, 45);
|
||
|
||
// Editorial Collection Subhead
|
||
let collectionTag = 'SCANDINAVIAN OAK STUDIO // 8K NATURAL LIFESTYLE';
|
||
if (nType === 'botanical_sun') collectionTag = 'BOTANICAL MORNING SUN // 100% ORGANIC FORMULA';
|
||
else if (nType === 'kbeauty_travertine') collectionTag = 'K-BEAUTY TRAVERTINE EDITORIAL // GLASS SKIN';
|
||
else if (nType === 'warm_cafe') collectionTag = 'ARTISAN DARK WALNUT // COZY BOUTIQUE LIFESTYLE';
|
||
else if (nType === 'sunlit_sand') collectionTag = 'SUN-KISSED TERRACOTTA // RAW MINERAL CRAFT';
|
||
else if (nType === 'minimal_flatlay') collectionTag = 'STUDIO FLATLAY PRO // SCALE 1:1 AUTHENTIC';
|
||
else if (nType === 'velvet_drape') collectionTag = 'ROYAL MULBERRY SILK // HAUTE COUTURE EDITION';
|
||
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(253, 230, 138, 0.75)' : currentTheme.accentColor;
|
||
ctx.font = 'bold 11px Consolas, monospace';
|
||
ctx.fillText(`EST. 2026 • ${collectionTag}`, 42, 68);
|
||
|
||
// Delicate Top Hairline Divider
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.35)' : 'rgba(160, 125, 84, 0.35)';
|
||
ctx.lineWidth = 1;
|
||
ctx.beginPath();
|
||
ctx.moveTo(42, 78);
|
||
ctx.lineTo(w - 42, 78);
|
||
ctx.stroke();
|
||
|
||
// Top-Right Luxury Artisan Medallion Seal
|
||
const sealX = w - 80;
|
||
const sealY = 48;
|
||
ctx.strokeStyle = isDarkTheme ? '#FDE68A' : currentTheme.goldRim;
|
||
ctx.lineWidth = 1.5;
|
||
ctx.beginPath();
|
||
ctx.arc(sealX, sealY, 26, 0, Math.PI * 2);
|
||
ctx.stroke();
|
||
|
||
ctx.beginPath();
|
||
ctx.arc(sealX, sealY, 22, 0, Math.PI * 2);
|
||
ctx.stroke();
|
||
|
||
ctx.fillStyle = isDarkTheme ? '#FDE68A' : currentTheme.accentColor;
|
||
ctx.font = 'bold 8.5px Consolas, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('8K PURE', sealX, sealY - 4);
|
||
ctx.fillText('STUDIO', sealX, sealY + 7);
|
||
ctx.restore();
|
||
|
||
// 7. EDITORIAL PRODUCT TITLE & STORYTELLING (Repositioned to Airy Left Zone)
|
||
const textLeft = 42;
|
||
const titleMaxWidth = aspect === '9:16' ? (w - 84) : (w * 0.44);
|
||
let curY = aspect === '9:16' ? 115 : 108;
|
||
|
||
// Eyebrow Tag
|
||
ctx.save();
|
||
ctx.fillStyle = isDarkTheme ? '#F59E0B' : currentTheme.accentColor;
|
||
ctx.font = 'bold 11.5px Consolas, monospace';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText('◈ 01 // FEATURED BOTANICAL HARVEST', textLeft, curY);
|
||
curY += 28;
|
||
|
||
// Main Product Title (Auto line-wrapped high-fashion typography)
|
||
ctx.fillStyle = isDarkTheme ? '#FFFFFF' : '#181109';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '36px' : '30px') + ' Playfair Display, Hind Siliguri, serif';
|
||
|
||
// Line wrapping helper
|
||
const words = title.split(' ');
|
||
let currentLine = '';
|
||
const titleLines = [];
|
||
for (let i = 0; i < words.length; i++) {
|
||
const testLine = currentLine ? `${currentLine} ${words[i]}` : words[i];
|
||
const testWidth = ctx.measureText(testLine).width;
|
||
if (testWidth > titleMaxWidth && i > 0) {
|
||
titleLines.push(currentLine);
|
||
currentLine = words[i];
|
||
if (titleLines.length >= 3) {
|
||
currentLine += '...';
|
||
break;
|
||
}
|
||
} else {
|
||
currentLine = testLine;
|
||
}
|
||
}
|
||
if (currentLine) titleLines.push(currentLine);
|
||
|
||
titleLines.forEach(line => {
|
||
// Soft text glow for maximum legibility against bright sunbeams
|
||
ctx.save();
|
||
ctx.shadowColor = isDarkTheme ? 'rgba(0,0,0,0.85)' : 'rgba(255,255,255,0.95)';
|
||
ctx.shadowBlur = 12;
|
||
ctx.fillText(line, textLeft, curY);
|
||
ctx.restore();
|
||
curY += (aspect === '9:16' ? 44 : 38);
|
||
});
|
||
|
||
// Formula & Benefits Subtitle
|
||
ctx.fillStyle = isDarkTheme ? '#E2E8F0' : '#4B382A';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '15px' : '13.5px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.fillText('✦ 100% Active Formula • ✦ 24h Deep Moisture', textLeft, curY);
|
||
curY += 32;
|
||
|
||
// 8. ARTISAN LUXURY PRICE & DISCOUNT TAG (Parsed Cleanly)
|
||
let rawPrice = price || '৳ ১,০৬০';
|
||
let discountTag = '28% OFF';
|
||
let regPriceStr = '৳ ১,৪৭০';
|
||
|
||
const dMatch = rawPrice.match(/(\d+%\s*OFF)/i);
|
||
if (dMatch) discountTag = dMatch[1].toUpperCase();
|
||
|
||
const rMatch = rawPrice.match(/\(([^)]+)\)/);
|
||
if (rMatch) regPriceStr = rMatch[1];
|
||
|
||
let cleanOfferPrice = rawPrice
|
||
.replace(/\([^)]+\)/g, '')
|
||
.replace(/\d+%\s*OFF/gi, '')
|
||
.trim();
|
||
if (!cleanOfferPrice) cleanOfferPrice = '৳ ১,০৬০';
|
||
|
||
const priceCardY = curY;
|
||
const priceCardW = aspect === '9:16' ? (w - 84) : 260;
|
||
const priceCardH = 76;
|
||
|
||
ctx.save();
|
||
// Frosted linen card
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(25, 14, 8, 0.88)' : 'rgba(255, 255, 255, 0.92)';
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.40)' : 'rgba(160, 125, 84, 0.35)';
|
||
ctx.lineWidth = 1.2;
|
||
ctx.beginPath();
|
||
ctx.roundRect(textLeft, priceCardY, priceCardW, priceCardH, 14);
|
||
ctx.fill();
|
||
ctx.stroke();
|
||
|
||
// Main Offer Price
|
||
ctx.fillStyle = isDarkTheme ? '#FDE68A' : '#047857';
|
||
ctx.font = '900 28px Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(cleanOfferPrice, textLeft + 16, priceCardY + 40);
|
||
|
||
// Regular Price Strikethrough Sub-line
|
||
ctx.fillStyle = isDarkTheme ? '#94A3B8' : '#78716C';
|
||
ctx.font = '600 12.5px Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.fillText(`Regular: ${regPriceStr}`, textLeft + 16, priceCardY + 62);
|
||
|
||
// Mini Discount Capsule on Right of Price Card
|
||
const discX = textLeft + priceCardW - 90;
|
||
ctx.fillStyle = isDarkTheme ? '#B45309' : '#059669';
|
||
ctx.beginPath();
|
||
ctx.roundRect(discX, priceCardY + 16, 76, 28, 14);
|
||
ctx.fill();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold 11.5px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(discountTag, discX + 38, priceCardY + 34);
|
||
ctx.restore();
|
||
|
||
curY += priceCardH + 18;
|
||
|
||
// 9. BOTANICAL TRUST BADGES (Rich Vertical Feature Badges on Left)
|
||
const isEn = (window.currentLang === 'en');
|
||
const trustBadgesList = [
|
||
{
|
||
icon: '🌿',
|
||
title: isEn ? (badgeText || '100% Pure Botanical Formula') : (badgeText || '১০০% ভেষজ ও অর্গানিক ফর্মুলা'),
|
||
sub: isEn ? 'No Harmful Chemicals • Paraben Free' : 'কোন ক্ষতিকর কেমিক্যাল নেই • প্যারাবেন ফ্রি'
|
||
},
|
||
{
|
||
icon: '🛡️',
|
||
title: brandInfo.badgeL1 || (isEn ? 'Official Store Guarantee' : 'অফিসিয়াল ব্র্যান্ড গ্যারান্টি'),
|
||
sub: isEn ? '100% Original Authentic Seal' : '১০০% অরিজিনাল অথেনটিক সিল'
|
||
},
|
||
{
|
||
icon: '⚡',
|
||
title: brandInfo.badgeL2 || (isEn ? 'Fast Express Dispatch' : 'দ্রুত হোম ডেলিভারি'),
|
||
sub: isEn ? 'Same-Day Cash on Delivery BD' : 'ক্যাশ অন ডেলিভারি সুবিধা সারা দেশে'
|
||
}
|
||
];
|
||
|
||
trustBadgesList.forEach(b => {
|
||
ctx.save();
|
||
const badgeBoxW = aspect === '9:16' ? (w - 84) : 260;
|
||
const badgeBoxH = 44;
|
||
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(30, 18, 10, 0.82)' : 'rgba(255, 255, 255, 0.88)';
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.35)' : 'rgba(160, 125, 84, 0.30)';
|
||
ctx.lineWidth = 1;
|
||
ctx.beginPath();
|
||
ctx.roundRect(textLeft, curY, badgeBoxW, badgeBoxH, 10);
|
||
ctx.fill();
|
||
ctx.stroke();
|
||
|
||
// Icon & Title
|
||
ctx.fillStyle = isDarkTheme ? '#FDE68A' : '#1E140A';
|
||
ctx.font = 'bold 12.5px Hind Siliguri, Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`${b.icon} ${b.title}`, textLeft + 12, curY + 20);
|
||
|
||
// Sub-line
|
||
ctx.fillStyle = isDarkTheme ? '#94A3B8' : '#78716C';
|
||
ctx.font = '600 10.5px Hind Siliguri, Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(b.sub, textLeft + 30, curY + 35);
|
||
|
||
ctx.restore();
|
||
curY += badgeBoxH + 10;
|
||
});
|
||
|
||
// 10. 3-COLUMN LUXURY VALUE PROPOSITION STRIP (Fills the lower tabletop beautifully!)
|
||
const stripY = aspect === '9:16' ? 1640 : (h - 200);
|
||
const stripH = 76;
|
||
const stripGap = 16;
|
||
const stripCardW = (w - 84 - stripGap * 2) / 3;
|
||
|
||
let f1Title = isEn ? '100% Pure & Authentic' : '১০০% বিশুদ্ধ ও আসল';
|
||
let f1Sub = isEn ? 'Lab Certified Active Purity' : 'ল্যাব টেস্টেড ১০০% কোয়ালিটি';
|
||
let f2Title = isEn ? 'Money-Back Guarantee' : 'মানি-ব্যাক গ্যারান্টি';
|
||
let f2Sub = isEn ? '100% Original Sealed Box' : 'অফিসিয়াল ইনট্যাক্ট সিল প্যাক';
|
||
let f3Title = isEn ? 'Cash on Delivery' : 'ক্যাশ অন ডেলিভারি';
|
||
let f3Sub = isEn ? 'Fast 24-48h Doorstep BD' : '২৪-৪৮ ঘণ্টার মধ্যে সারা দেশে';
|
||
|
||
if (brandInfo.category === 'electronics') {
|
||
f1Title = isEn ? '1 Year Official Warranty' : '১ বছরের অফিশিয়াল ওয়ারেন্টি';
|
||
f1Sub = isEn ? 'Official Replacement Support' : 'দ্রুত রিপ্লেসমেন্ট গ্যারান্টি';
|
||
} else if (brandInfo.category === 'panjabi' || brandInfo.category === 'fashion') {
|
||
f1Title = isEn ? 'Premium Pure Weave' : 'প্রিমিয়াম সুতার নিখুঁত কাজ';
|
||
f1Sub = isEn ? 'Pre-Shrunk Royal Drape' : 'কালার ও সাইজ ট্রায়াল সুবিধা';
|
||
} else if (brandInfo.category === 'sneakerlab') {
|
||
f1Title = isEn ? '100% Cowhide Leather' : '১০০% জেনুইন লেদার সোল';
|
||
f1Sub = isEn ? 'Doorstep Fitting Available' : 'হাতে পেয়ে সাইজ ট্রায়াল';
|
||
}
|
||
|
||
const lowerFeatures = [
|
||
{ icon: '🌿', title: f1Title, sub: f1Sub },
|
||
{ icon: '🛡️', title: f2Title, sub: f2Sub },
|
||
{ icon: '🚚', title: f3Title, sub: f3Sub }
|
||
];
|
||
|
||
lowerFeatures.forEach((feat, fIdx) => {
|
||
const fx = textLeft + fIdx * (stripCardW + stripGap);
|
||
ctx.save();
|
||
// Frosted Card Body
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(25, 14, 8, 0.90)' : 'rgba(255, 255, 255, 0.92)';
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.40)' : 'rgba(160, 125, 84, 0.35)';
|
||
ctx.lineWidth = 1.2;
|
||
ctx.beginPath();
|
||
ctx.roundRect(fx, stripY, stripCardW, stripH, 14);
|
||
ctx.fill();
|
||
ctx.stroke();
|
||
|
||
// Feature Icon & Title
|
||
ctx.fillStyle = isDarkTheme ? '#FDE68A' : '#1E140A';
|
||
ctx.font = 'bold 12.5px Hind Siliguri, Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(`${feat.icon} ${feat.title}`, fx + stripCardW / 2, stripY + 32);
|
||
|
||
// Feature Subtitle
|
||
ctx.fillStyle = isDarkTheme ? '#94A3B8' : '#78716C';
|
||
ctx.font = '600 10.5px Hind Siliguri, Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(feat.sub, fx + stripCardW / 2, stripY + 54);
|
||
|
||
ctx.restore();
|
||
});
|
||
|
||
// 11. EDITORIAL TRANSLUCENT FOOTER (Minimalist, Floating, No Solid Clunky Green Bar!)
|
||
const footerHeight = aspect === '9:16' ? 120 : 100;
|
||
const footerTop = h - footerHeight;
|
||
|
||
ctx.save();
|
||
// Frosted Glass Footer Background
|
||
const footGrad = ctx.createLinearGradient(0, footerTop, 0, h);
|
||
if (isDarkTheme) {
|
||
footGrad.addColorStop(0, 'rgba(15, 8, 4, 0.94)');
|
||
footGrad.addColorStop(1, 'rgba(8, 4, 2, 0.98)');
|
||
} else {
|
||
footGrad.addColorStop(0, 'rgba(255, 255, 255, 0.88)');
|
||
footGrad.addColorStop(1, 'rgba(247, 243, 235, 0.96)');
|
||
}
|
||
ctx.fillStyle = footGrad;
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
|
||
// Subtle Champagne Gold Top Hairline
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.50)' : 'rgba(160, 125, 84, 0.40)';
|
||
ctx.lineWidth = 1.2;
|
||
ctx.beginPath();
|
||
ctx.moveTo(0, footerTop);
|
||
ctx.lineTo(w, footerTop);
|
||
ctx.stroke();
|
||
|
||
// WhatsApp Call-to-Action
|
||
ctx.fillStyle = isDarkTheme ? '#10B981' : '#047857';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '26px' : '23px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`💬 WhatsApp Order: ${brandInfo.footerHotline}`, 42, footerTop + (aspect === '9:16' ? 44 : 38));
|
||
|
||
// Website & Hotline
|
||
ctx.fillStyle = isDarkTheme ? '#94A3B8' : '#64748B';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '16px' : '14.5px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(`🌐 ${brandInfo.footerSite} • 📞 ${brandInfo.footerHotline} • 🚚 Cash on Delivery BD`, 42, footerTop + (aspect === '9:16' ? 78 : 68));
|
||
|
||
// Sleek White QR Code Tile
|
||
const qrS = aspect === '9:16' ? 76 : 68;
|
||
const qrX = w - qrS - 42;
|
||
const qrY = footerTop + (footerHeight - qrS) / 2;
|
||
drawQRCodeTile(ctx, qrX, qrY, qrS);
|
||
|
||
ctx.restore();
|
||
|
||
// Subtle Outer Frame Border
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.45)' : 'rgba(160, 125, 84, 0.35)';
|
||
ctx.lineWidth = 3;
|
||
ctx.strokeRect(2, 2, w - 4, h - 4);
|
||
|
||
return; // Done with 8K natural rendering
|
||
}
|
||
|
||
// 1. Studio Radial Backdrop (3D CGI Stages)
|
||
const stageCy = aspect === '9:16' ? h * 0.45 : h * 0.44;
|
||
const bgGrad = ctx.createRadialGradient(w / 2, stageCy, 40, w / 2, stageCy, w * 0.85);
|
||
bgGrad.addColorStop(0, currentTheme.bgCenter);
|
||
bgGrad.addColorStop(0.5, currentTheme.bgMid);
|
||
bgGrad.addColorStop(1, currentTheme.bgOuter);
|
||
ctx.fillStyle = bgGrad;
|
||
ctx.fillRect(0, 0, w, h);
|
||
|
||
// 1.1 RADICALLY DISTINCT THEME BACKGROUND ARCHITECTURES
|
||
if (theme === 'bento_grid_luxe') {
|
||
// Apple Bento Box 4-Card Spec Grid
|
||
ctx.save();
|
||
// Subtle Dotted Matrix Grid
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.08)';
|
||
for (let dx = 30; dx < w; dx += 30) {
|
||
for (let dy = 110; dy < h - 120; dy += 30) {
|
||
ctx.beginPath(); ctx.arc(dx, dy, 1.2, 0, Math.PI * 2); ctx.fill();
|
||
}
|
||
}
|
||
// Bento Card 1: Large Center-Left Hero Box
|
||
const heroBoxW = w * 0.58;
|
||
const heroBoxH = aspect === '9:16' ? 1160 : 635;
|
||
ctx.fillStyle = 'rgba(15, 23, 42, 0.70)';
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.28)';
|
||
ctx.lineWidth = 1.8;
|
||
ctx.beginPath(); ctx.roundRect(40, 115, heroBoxW, heroBoxH, 18); ctx.fill(); ctx.stroke();
|
||
|
||
// Bento Card 2: Top-Right Rating & Sales Card
|
||
const rightBoxX = 40 + heroBoxW + 20;
|
||
const rightBoxW = w - rightBoxX - 40;
|
||
const rightBox1H = aspect === '9:16' ? 360 : 195;
|
||
ctx.fillStyle = 'rgba(15, 23, 42, 0.75)';
|
||
ctx.strokeStyle = 'rgba(250, 204, 21, 0.35)';
|
||
ctx.beginPath(); ctx.roundRect(rightBoxX, 115, rightBoxW, rightBox1H, 18); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#FACC15';
|
||
ctx.font = 'bold 22px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('★ 5.0 RATED', rightBoxX + 22, 160);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = '600 15px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('★★★★★ TOP SELLER', rightBoxX + 22, 195);
|
||
ctx.fillStyle = '#94A3B8';
|
||
ctx.font = '13px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('Over 5,000+ Verified Orders in BD', rightBoxX + 22, 230);
|
||
|
||
// Bento Card 3: Middle-Right Feature & Authenticity Card
|
||
const rightBox2Y = 115 + rightBox1H + 20;
|
||
const rightBox2H = aspect === '9:16' ? 360 : 195;
|
||
ctx.fillStyle = 'rgba(15, 23, 42, 0.75)';
|
||
ctx.strokeStyle = 'rgba(16, 185, 129, 0.35)';
|
||
ctx.beginPath(); ctx.roundRect(rightBoxX, rightBox2Y, rightBoxW, rightBox2H, 18); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#34D399';
|
||
ctx.font = 'bold 20px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('🛡️ 100% ORIGINAL', rightBoxX + 22, rightBox2Y + 45);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = '600 15px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('⚡ Fast Dispatch BD', rightBoxX + 22, rightBox2Y + 80);
|
||
ctx.fillStyle = '#94A3B8';
|
||
ctx.font = '13px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('Money-Back Guarantee', rightBoxX + 22, rightBox2Y + 115);
|
||
|
||
// Bento Card 4: Bottom-Right Hotline Card
|
||
const rightBox3Y = rightBox2Y + rightBox2H + 20;
|
||
const rightBox3H = (115 + heroBoxH) - rightBox3Y;
|
||
if (rightBox3H > 60) {
|
||
ctx.fillStyle = 'rgba(15, 23, 42, 0.75)';
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.35)';
|
||
ctx.beginPath(); ctx.roundRect(rightBoxX, rightBox3Y, rightBoxW, rightBox3H, 18); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = 'bold 18px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('💬 24/7 SUPPORT', rightBoxX + 22, rightBox3Y + 38);
|
||
ctx.fillStyle = '#E2E8F0';
|
||
ctx.font = '600 13px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(`Hotline: ${brandInfo.footerHotline}`, rightBoxX + 22, rightBox3Y + 68);
|
||
}
|
||
ctx.restore();
|
||
} else if (theme === 'swiss_modular_grid') {
|
||
// Swiss Bauhaus Architectural 4-Quadrant Precision Grid
|
||
ctx.save();
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.20)';
|
||
ctx.lineWidth = 1.5;
|
||
// Horizontal cross rule
|
||
ctx.beginPath(); ctx.moveTo(40, stageCy - 80); ctx.lineTo(w - 40, stageCy - 80); ctx.stroke();
|
||
// Vertical cross rule
|
||
ctx.beginPath(); ctx.moveTo(w * 0.55, 110); ctx.lineTo(w * 0.55, h - 130); ctx.stroke();
|
||
// Central Crosshair
|
||
ctx.strokeStyle = '#F43F5E';
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.55 - 15, stageCy - 80); ctx.lineTo(w * 0.55 + 15, stageCy - 80);
|
||
ctx.moveTo(w * 0.55, stageCy - 80 - 15); ctx.lineTo(w * 0.55, stageCy - 80 + 15);
|
||
ctx.stroke();
|
||
|
||
// Quadrant Indices
|
||
ctx.fillStyle = '#F43F5E';
|
||
ctx.font = '900 14px Consolas, monospace';
|
||
ctx.fillText('[ 01 // ARCHIVE ]', 50, 135);
|
||
ctx.fillText('[ 02 // SPECIFICATION ]', w * 0.55 + 20, 135);
|
||
ctx.fillText('[ 03 // HERO_STAGE ]', 50, stageCy - 55);
|
||
ctx.fillText('[ 04 // COMMERCIAL_VAL ]', w * 0.55 + 20, stageCy - 55);
|
||
|
||
// Vertical Barcode in Quadrant 2
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillRect(w - 75, 150, 35, 120);
|
||
ctx.fillStyle = '#000000';
|
||
for (let bx = 0; bx < 30; bx += 3) {
|
||
if ((bx % 2 === 0)) ctx.fillRect(w - 72 + bx, 155, 2, 110);
|
||
}
|
||
ctx.restore();
|
||
} else if (theme === 'blueprint_cad_grid') {
|
||
// Industrial CAD Blueprint Engineering Grid with Caliper Dimensions
|
||
ctx.save();
|
||
// Major & Minor Cyan Grid lines
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.08)';
|
||
ctx.lineWidth = 1;
|
||
for (let gx = 0; gx < w; gx += 15) {
|
||
ctx.beginPath(); ctx.moveTo(gx, 0); ctx.lineTo(gx, h); ctx.stroke();
|
||
}
|
||
for (let gy = 0; gy < h; gy += 15) {
|
||
ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(w, gy); ctx.stroke();
|
||
}
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.22)';
|
||
ctx.lineWidth = 1.5;
|
||
for (let gx = 0; gx < w; gx += 60) {
|
||
ctx.beginPath(); ctx.moveTo(gx, 0); ctx.lineTo(gx, h); ctx.stroke();
|
||
}
|
||
for (let gy = 0; gy < h; gy += 60) {
|
||
ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(w, gy); ctx.stroke();
|
||
}
|
||
|
||
// CAD Caliper Dimension Line across Top
|
||
const dimY = 145;
|
||
ctx.strokeStyle = '#38BDF8';
|
||
ctx.lineWidth = 2;
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.18, dimY); ctx.lineTo(w * 0.82, dimY);
|
||
ctx.moveTo(w * 0.18, dimY - 10); ctx.lineTo(w * 0.18, dimY + 10);
|
||
ctx.moveTo(w * 0.82, dimY - 10); ctx.lineTo(w * 0.82, dimY + 10);
|
||
ctx.stroke();
|
||
|
||
ctx.fillStyle = '#0284C7';
|
||
ctx.fillRect(w / 2 - 80, dimY - 12, 160, 24);
|
||
ctx.fillStyle = '#E0F2FE';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('|← 320.0 mm →|', w / 2, dimY + 5);
|
||
|
||
// CAD Angle Caliper & Title Block
|
||
ctx.textAlign = 'left';
|
||
ctx.fillStyle = '#BAE6FD';
|
||
ctx.font = 'bold 12px Consolas, monospace';
|
||
ctx.fillText('TOLERANCE: ±0.01 mm // ANGLE: ∠ 90°', 45, h - 145);
|
||
ctx.textAlign = 'right';
|
||
ctx.fillText('DWG: CAD-2026 // REV: A1 // PASS', w - 45, h - 145);
|
||
ctx.restore();
|
||
} else if (theme === 'polaroid_film_grid') {
|
||
// 35mm Filmstrip Contact Sheet Grid with Perforations
|
||
ctx.save();
|
||
// Film Perforation Sprocket Holes
|
||
const sprocH = 18;
|
||
const sprocW = 14;
|
||
ctx.fillStyle = '#000000';
|
||
ctx.strokeStyle = '#D97706';
|
||
ctx.lineWidth = 1;
|
||
for (let sy = 10; sy < h - 20; sy += 38) {
|
||
// Left sprocket
|
||
ctx.fillRect(12, sy, sprocW, sprocH);
|
||
ctx.strokeRect(12, sy, sprocW, sprocH);
|
||
// Right sprocket
|
||
ctx.fillRect(w - 26, sy, sprocW, sprocH);
|
||
ctx.strokeRect(w - 26, sy, sprocW, sprocH);
|
||
}
|
||
// Film Edge Barcode & Frame Counter
|
||
ctx.fillStyle = '#D97706';
|
||
ctx.font = 'bold 12px Consolas, monospace';
|
||
ctx.fillText('KODAK 400TX // 24A', 40, 125);
|
||
ctx.textAlign = 'right';
|
||
ctx.fillText('ISO 400 • FRAME 24', w - 40, 125);
|
||
ctx.restore();
|
||
} else if (theme === 'cyber_hud_grid') {
|
||
// Tron Cyber HUD 4-Corner Telemetry Pods
|
||
ctx.save();
|
||
// 4 Corner Telemetry Pods
|
||
const podW = 190;
|
||
const podH = 85;
|
||
// Top-Left Pod
|
||
ctx.fillStyle = 'rgba(6, 78, 59, 0.45)';
|
||
ctx.strokeStyle = '#00FFCC'; ctx.lineWidth = 1.5;
|
||
ctx.strokeRect(45, 120, podW, podH);
|
||
ctx.fillStyle = '#00FFCC'; ctx.font = 'bold 12px Consolas, monospace';
|
||
ctx.fillText('SYS.HEALTH: 100%', 55, 145);
|
||
// Green Bar Graph
|
||
ctx.fillStyle = '#059669'; ctx.fillRect(55, 155, 140, 8);
|
||
ctx.fillStyle = '#00FFCC'; ctx.fillRect(55, 155, 110, 8);
|
||
ctx.fillStyle = '#A7F3D0'; ctx.fillText('STATUS: OPTIMAL', 55, 185);
|
||
|
||
// Top-Right Pod
|
||
ctx.strokeStyle = '#00FFCC';
|
||
ctx.strokeRect(w - podW - 45, 120, podW, podH);
|
||
ctx.fillStyle = '#00FFCC';
|
||
ctx.fillText('RADAR_GPS // BD', w - podW - 35, 145);
|
||
// Circular Radar Sweep
|
||
ctx.beginPath(); ctx.arc(w - 90, 165, 20, 0, Math.PI * 2); ctx.stroke();
|
||
ctx.beginPath(); ctx.moveTo(w - 90, 145); ctx.lineTo(w - 90, 185); ctx.stroke();
|
||
ctx.beginPath(); ctx.moveTo(w - 110, 165); ctx.lineTo(w - 70, 165); ctx.stroke();
|
||
|
||
// Bottom-Left Equalizer Bars
|
||
ctx.strokeStyle = '#00FFCC';
|
||
ctx.strokeRect(45, h - podH - 140, podW, podH);
|
||
ctx.fillStyle = '#00FFCC';
|
||
ctx.fillText('TELEMETRY_FREQ', 55, h - podH - 120);
|
||
const eqBars = [25, 45, 30, 60, 40, 55, 35, 65, 50, 40, 60, 30];
|
||
eqBars.forEach((bh, bidx) => {
|
||
ctx.fillStyle = '#00FFCC';
|
||
ctx.fillRect(55 + bidx * 12, h - 150 - bh * 0.4, 8, bh * 0.4);
|
||
});
|
||
|
||
// Bottom-Right Encryption Pod
|
||
ctx.strokeStyle = '#00FFCC';
|
||
ctx.strokeRect(w - podW - 45, h - podH - 140, podW, podH);
|
||
ctx.fillStyle = '#00FFCC';
|
||
ctx.fillText('SECURE: 256-BIT', w - podW - 35, h - podH - 120);
|
||
ctx.fillStyle = '#A7F3D0'; ctx.font = '10px Consolas, monospace';
|
||
ctx.fillText('HEX: 0x8F4A9C', w - podW - 35, h - podH - 95);
|
||
ctx.fillText('HASH: OK // VERIFIED', w - podW - 35, h - podH - 75);
|
||
ctx.restore();
|
||
} else if (theme === 'mughal_heritage') {
|
||
// Grand Mughal Cusped Arch with Hanging Brass Lanterns & Arabesque Jali Lattice
|
||
ctx.save();
|
||
// Arabesque Jali lattice background grid
|
||
ctx.strokeStyle = 'rgba(245, 158, 11, 0.08)';
|
||
ctx.lineWidth = 1;
|
||
for (let jx = 40; jx < w; jx += 45) {
|
||
for (let jy = 100; jy < h - 120; jy += 45) {
|
||
ctx.strokeRect(jx, jy, 30, 30);
|
||
ctx.beginPath(); ctx.arc(jx + 15, jy + 15, 12, 0, Math.PI * 2); ctx.stroke();
|
||
}
|
||
}
|
||
// Outer Grand Cusped Arch
|
||
ctx.strokeStyle = 'rgba(245, 158, 11, 0.45)';
|
||
ctx.lineWidth = 6;
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.12, h * 0.72);
|
||
ctx.lineTo(w * 0.12, h * 0.32);
|
||
ctx.quadraticCurveTo(w * 0.22, h * 0.12, w * 0.5, h * 0.09);
|
||
ctx.quadraticCurveTo(w * 0.78, h * 0.12, w * 0.88, h * 0.32);
|
||
ctx.lineTo(w * 0.88, h * 0.72);
|
||
ctx.stroke();
|
||
|
||
// Inner Arch Gold Accent
|
||
ctx.strokeStyle = 'rgba(253, 230, 138, 0.30)';
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.16, h * 0.70);
|
||
ctx.lineTo(w * 0.16, h * 0.34);
|
||
ctx.quadraticCurveTo(w * 0.25, h * 0.15, w * 0.5, h * 0.12);
|
||
ctx.quadraticCurveTo(w * 0.75, h * 0.15, w * 0.84, h * 0.34);
|
||
ctx.lineTo(w * 0.84, h * 0.70);
|
||
ctx.stroke();
|
||
|
||
// Hanging Brass Lanterns
|
||
const lanternPositions = [w * 0.22, w * 0.78];
|
||
lanternPositions.forEach(lx => {
|
||
ctx.strokeStyle = 'rgba(245, 158, 11, 0.6)';
|
||
ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.moveTo(lx, 94); ctx.lineTo(lx, 210); ctx.stroke();
|
||
// Lantern Body
|
||
ctx.fillStyle = '#78350F';
|
||
ctx.fillRect(lx - 12, 210, 24, 30);
|
||
ctx.fillStyle = '#FDE68A';
|
||
ctx.beginPath(); ctx.arc(lx, 225, 8, 0, Math.PI * 2); ctx.fill();
|
||
ctx.strokeStyle = '#F59E0B'; ctx.strokeRect(lx - 12, 210, 24, 30);
|
||
});
|
||
ctx.restore();
|
||
} else if (theme === 'brutalist_street') {
|
||
// Industrial Brutalist Concrete Grid, Diagonal Hazard Corners, Stencil Watermarks & Tech Reticles
|
||
ctx.save();
|
||
// Top & Bottom Diagonal Caution Hazard Stripes
|
||
const stripeW = 28;
|
||
ctx.fillStyle = '#FACC15';
|
||
for (let hx = 0; hx < w; hx += stripeW * 2) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(hx, 0); ctx.lineTo(hx + stripeW, 0);
|
||
ctx.lineTo(hx + stripeW - 20, 24); ctx.lineTo(hx - 20, 24);
|
||
ctx.closePath(); ctx.fill();
|
||
}
|
||
// Tech Coordinates & Watermark
|
||
ctx.fillStyle = 'rgba(250, 204, 21, 0.08)';
|
||
ctx.font = '900 75px Impact, Arial Black, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('HEAVYWEIGHT // 2026', w / 2, stageCy - 120);
|
||
|
||
ctx.fillStyle = 'rgba(250, 204, 21, 0.30)';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText('[ LAT: 23.8103° N // LON: 90.4125° E ]', 45, 125);
|
||
ctx.textAlign = 'right';
|
||
ctx.fillText('[ SPEC_ID: BST-8820 // AUTHENTIC ]', w - 45, 125);
|
||
|
||
// Crosshair Reticles
|
||
const reticles = [{ x: 50, y: 160 }, { x: w - 50, y: 160 }, { x: 50, y: h - 140 }, { x: w - 50, y: h - 140 }];
|
||
ctx.strokeStyle = 'rgba(250, 204, 21, 0.45)';
|
||
ctx.lineWidth = 1.5;
|
||
reticles.forEach(r => {
|
||
ctx.beginPath();
|
||
ctx.moveTo(r.x - 12, r.y); ctx.lineTo(r.x + 12, r.y);
|
||
ctx.moveTo(r.x, r.y - 12); ctx.lineTo(r.x, r.y + 12);
|
||
ctx.stroke();
|
||
ctx.strokeRect(r.x - 6, r.y - 6, 12, 12);
|
||
});
|
||
ctx.restore();
|
||
} else if (theme === 'cyber_neon') {
|
||
// 3D Isometric Cyber Grid receding to horizon, digital scanlines, telemetry HUD
|
||
ctx.save();
|
||
const horizonY = aspect === '9:16' ? 1120 : 710;
|
||
// Perspective Floor Grid
|
||
ctx.strokeStyle = 'rgba(6, 182, 212, 0.32)';
|
||
ctx.lineWidth = 1.8;
|
||
for (let gx = -w * 0.4; gx <= w * 1.4; gx += 75) {
|
||
ctx.beginPath(); ctx.moveTo(w / 2, horizonY - 140); ctx.lineTo(gx, h); ctx.stroke();
|
||
}
|
||
for (let gy = horizonY - 80; gy < h; gy += 42) {
|
||
ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(w, gy); ctx.stroke();
|
||
}
|
||
// Horizontal Scanlines
|
||
ctx.fillStyle = 'rgba(6, 182, 212, 0.04)';
|
||
for (let sy = 0; sy < h; sy += 6) {
|
||
ctx.fillRect(0, sy, w, 2);
|
||
}
|
||
// Glowing Neon Target Rings
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.25)';
|
||
ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.arc(w / 2, stageCy - 30, 260, 0, Math.PI * 2); ctx.stroke();
|
||
ctx.strokeStyle = 'rgba(244, 63, 94, 0.20)';
|
||
ctx.beginPath(); ctx.arc(w / 2, stageCy - 30, 285, 0, Math.PI * 2); ctx.stroke();
|
||
// Telemetry text
|
||
ctx.fillStyle = '#06B6D4';
|
||
ctx.font = 'bold 12px Consolas, monospace';
|
||
ctx.fillText('SYS.STATUS // ONLINE [ 4K_UHD ]', 45, 125);
|
||
ctx.textAlign = 'right';
|
||
ctx.fillText('FREQ: 144Hz // QUANTUM_CORE', w - 45, 125);
|
||
ctx.restore();
|
||
} else if (theme === 'editorial_vogue') {
|
||
// Vogue Haute Magazine Watermark & Fine Swiss Gridlines
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
|
||
ctx.font = '900 160px Playfair Display, Georgia, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('V O G U E', w / 2, stageCy - 80);
|
||
|
||
// Fine Swiss Hairlines
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.12)';
|
||
ctx.lineWidth = 1;
|
||
ctx.beginPath(); ctx.moveTo(40, 110); ctx.lineTo(w - 40, 110); ctx.stroke();
|
||
ctx.beginPath(); ctx.moveTo(40, h - 130); ctx.lineTo(w - 40, h - 130); ctx.stroke();
|
||
// Minimalist Corner crop marks
|
||
const crops = [{ x: 25, y: 105 }, { x: w - 25, y: 105 }, { x: 25, y: h - 115 }, { x: w - 25, y: h - 115 }];
|
||
crops.forEach(c => {
|
||
ctx.beginPath(); ctx.moveTo(c.x - 8, c.y); ctx.lineTo(c.x + 8, c.y); ctx.stroke();
|
||
ctx.beginPath(); ctx.moveTo(c.x, c.y - 8); ctx.lineTo(c.x, c.y + 8); ctx.stroke();
|
||
});
|
||
ctx.restore();
|
||
} else if (theme === 'botanical_eco') {
|
||
// Botanical Tropical Leaves & Soft God Rays
|
||
ctx.save();
|
||
// Morning Sunbeams
|
||
ctx.globalCompositeOperation = 'screen';
|
||
const sunbeam = ctx.createRadialGradient(w * 0.2, 80, 10, w * 0.2, 80, 500);
|
||
sunbeam.addColorStop(0, 'rgba(110, 231, 183, 0.35)');
|
||
sunbeam.addColorStop(0.6, 'rgba(16, 185, 129, 0.10)');
|
||
sunbeam.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = sunbeam;
|
||
ctx.beginPath(); ctx.arc(w * 0.2, 80, 500, 0, Math.PI * 2); ctx.fill();
|
||
|
||
// Tropical Foliage Silhouettes at top corners
|
||
ctx.fillStyle = 'rgba(6, 78, 59, 0.35)';
|
||
// Left monstera leaf silhouette
|
||
ctx.beginPath();
|
||
ctx.ellipse(90, 180, 80, 120, Math.PI / 4, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
// Right leaf silhouette
|
||
ctx.beginPath();
|
||
ctx.ellipse(w - 90, 200, 75, 110, -Math.PI / 4, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
ctx.restore();
|
||
} else if (theme === 'tokyo_synthwave') {
|
||
// Segmented Retrowave Glowing Sun & Retro Laser Floor
|
||
ctx.save();
|
||
const horizonY = aspect === '9:16' ? 1120 : 710;
|
||
// Retrowave Sun Disc
|
||
const sunY = horizonY - 100;
|
||
const sunR = 150;
|
||
const sunGrad = ctx.createLinearGradient(0, sunY - sunR, 0, sunY + sunR);
|
||
sunGrad.addColorStop(0, '#FACC15');
|
||
sunGrad.addColorStop(0.5, '#F43F5E');
|
||
sunGrad.addColorStop(1, '#9333EA');
|
||
ctx.fillStyle = sunGrad;
|
||
ctx.beginPath(); ctx.arc(w / 2, sunY, sunR, Math.PI, 0); ctx.fill();
|
||
// Sun horizontal slice lines
|
||
ctx.fillStyle = '#100520';
|
||
for (let sl = 0; sl < 6; sl++) {
|
||
ctx.fillRect(w / 2 - sunR, sunY - 40 + sl * 14, sunR * 2, 4 + sl * 1.5);
|
||
}
|
||
// Laser Floor Grid
|
||
ctx.strokeStyle = 'rgba(244, 63, 94, 0.35)';
|
||
ctx.lineWidth = 1.8;
|
||
for (let gx = -w * 0.5; gx <= w * 1.5; gx += 80) {
|
||
ctx.beginPath(); ctx.moveTo(w / 2, horizonY); ctx.lineTo(gx, h); ctx.stroke();
|
||
}
|
||
for (let gy = horizonY; gy < h; gy += 42) {
|
||
ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(w, gy); ctx.stroke();
|
||
}
|
||
ctx.restore();
|
||
} else if (theme === 'holographic_prism') {
|
||
// Iridescent Caustic Dispersion Beams & Floating Gem Shards
|
||
ctx.save();
|
||
ctx.globalCompositeOperation = 'screen';
|
||
// Rainbow dispersion rays
|
||
const colors = ['rgba(236,72,153,0.2)', 'rgba(168,85,247,0.2)', 'rgba(56,189,248,0.2)', 'rgba(52,211,153,0.2)'];
|
||
colors.forEach((c, idx) => {
|
||
const ray = ctx.createLinearGradient(0, 0, w, h);
|
||
ray.addColorStop(0, 'transparent');
|
||
ray.addColorStop(0.3 + idx * 0.15, c);
|
||
ray.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = ray;
|
||
ctx.fillRect(0, 0, w, h);
|
||
});
|
||
// Gem Shards
|
||
ctx.strokeStyle = 'rgba(240, 171, 252, 0.4)';
|
||
ctx.lineWidth = 1.5;
|
||
const shards = [{x: w*0.18, y: 220, s: 20}, {x: w*0.82, y: 240, s: 24}, {x: w*0.14, y: 480, s: 18}, {x: w*0.86, y: 500, s: 22}];
|
||
shards.forEach(sh => {
|
||
ctx.beginPath();
|
||
ctx.moveTo(sh.x, sh.y - sh.s); ctx.lineTo(sh.x + sh.s, sh.y);
|
||
ctx.lineTo(sh.x, sh.y + sh.s); ctx.lineTo(sh.x - sh.s, sh.y);
|
||
ctx.closePath(); ctx.stroke();
|
||
});
|
||
ctx.restore();
|
||
} else if (theme === 'frost_titanium') {
|
||
// Sub-Zero Ice Crystals, Frosted Vignette & Cryo Fog
|
||
ctx.save();
|
||
ctx.strokeStyle = 'rgba(186, 230, 253, 0.35)';
|
||
ctx.lineWidth = 1.5;
|
||
const flakes = [{x: w*0.15, y: 180, r: 16}, {x: w*0.85, y: 220, r: 20}, {x: w*0.2, y: 520, r: 14}, {x: w*0.8, y: 550, r: 18}];
|
||
flakes.forEach(f => {
|
||
for (let a = 0; a < 6; a++) {
|
||
const rad = (a * Math.PI) / 3;
|
||
ctx.beginPath();
|
||
ctx.moveTo(f.x, f.y);
|
||
ctx.lineTo(f.x + Math.cos(rad) * f.r, f.y + Math.sin(rad) * f.r);
|
||
ctx.stroke();
|
||
}
|
||
});
|
||
ctx.restore();
|
||
} else if (theme === 'vip_blackcard') {
|
||
// Carbon Fiber Weave Texture & Gold Concentric Luxury Rings
|
||
ctx.save();
|
||
ctx.strokeStyle = 'rgba(212, 175, 55, 0.12)';
|
||
ctx.lineWidth = 1;
|
||
for (let r = 80; r <= 420; r += 45) {
|
||
ctx.beginPath(); ctx.arc(w / 2, stageCy, r, 0, Math.PI * 2); ctx.stroke();
|
||
}
|
||
ctx.fillStyle = 'rgba(212, 175, 55, 0.06)';
|
||
ctx.font = '900 80px Cinzel, Times New Roman, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('CENTURION', w / 2, stageCy - 100);
|
||
ctx.restore();
|
||
} else if (theme === 'sunset_amber') {
|
||
// Giant Sunset Sun Disc & Heat Haze
|
||
ctx.save();
|
||
const sunGrad = ctx.createRadialGradient(w / 2, stageCy - 60, 20, w / 2, stageCy - 60, 260);
|
||
sunGrad.addColorStop(0, 'rgba(251, 146, 60, 0.55)');
|
||
sunGrad.addColorStop(0.5, 'rgba(234, 88, 12, 0.20)');
|
||
sunGrad.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = sunGrad;
|
||
ctx.beginPath(); ctx.arc(w / 2, stageCy - 60, 260, 0, Math.PI * 2); ctx.fill();
|
||
ctx.restore();
|
||
} else if (theme === 'flash_sale_matrix') {
|
||
// High-Voltage Lightning Bolts & Speed Flares
|
||
ctx.save();
|
||
ctx.strokeStyle = 'rgba(239, 68, 68, 0.45)';
|
||
ctx.lineWidth = 3;
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.08, 120); ctx.lineTo(w * 0.24, 260); ctx.lineTo(w * 0.16, 380); ctx.lineTo(w * 0.30, 540);
|
||
ctx.stroke();
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.92, 140); ctx.lineTo(w * 0.76, 290); ctx.lineTo(w * 0.84, 420); ctx.lineTo(w * 0.70, 580);
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
} else if (theme === 'art_deco_gilded') {
|
||
// 1920s Gatsby Art Deco Fan & Sunburst Geometric Lines
|
||
ctx.save();
|
||
ctx.strokeStyle = 'rgba(234, 179, 8, 0.25)';
|
||
ctx.lineWidth = 1.5;
|
||
for (let ang = -Math.PI * 0.75; ang <= -Math.PI * 0.25; ang += 0.06) {
|
||
ctx.beginPath();
|
||
ctx.moveTo(w / 2, h * 0.75);
|
||
ctx.lineTo(w / 2 + Math.cos(ang) * w, h * 0.75 + Math.sin(ang) * w);
|
||
ctx.stroke();
|
||
}
|
||
// Art deco concentric diamonds
|
||
[100, 180, 260].forEach(d => {
|
||
ctx.beginPath();
|
||
ctx.moveTo(w / 2, stageCy - d); ctx.lineTo(w / 2 + d * 1.3, stageCy);
|
||
ctx.lineTo(w / 2, stageCy + d); ctx.lineTo(w / 2 - d * 1.3, stageCy);
|
||
ctx.closePath(); ctx.stroke();
|
||
});
|
||
ctx.restore();
|
||
} else if (theme === 'cosmic_nebula') {
|
||
// Swirling Nebula Clouds & Planetary Gravity Rings
|
||
ctx.save();
|
||
ctx.globalCompositeOperation = 'screen';
|
||
const neb1 = ctx.createRadialGradient(w * 0.25, stageCy - 80, 30, w * 0.25, stageCy - 80, 320);
|
||
neb1.addColorStop(0, 'rgba(168, 85, 247, 0.45)');
|
||
neb1.addColorStop(0.6, 'rgba(236, 72, 153, 0.15)');
|
||
neb1.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = neb1;
|
||
ctx.beginPath(); ctx.arc(w * 0.25, stageCy - 80, 320, 0, Math.PI * 2); ctx.fill();
|
||
|
||
// Orbital Ring
|
||
ctx.strokeStyle = 'rgba(192, 132, 252, 0.35)';
|
||
ctx.lineWidth = 2.5;
|
||
ctx.beginPath();
|
||
ctx.ellipse(w / 2, stageCy, w * 0.42, 70, -0.3, 0, Math.PI * 2);
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
} else if (theme === 'arcade_retro') {
|
||
// 8-Bit Pixel Grid & Marquee Stars
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(56, 189, 248, 0.05)';
|
||
for (let px = 0; px < w; px += 24) {
|
||
for (let py = 100; py < h - 120; py += 24) {
|
||
if ((px + py) % 48 === 0) ctx.fillRect(px, py, 18, 18);
|
||
}
|
||
}
|
||
ctx.restore();
|
||
}
|
||
|
||
// 2. Volumetric Softbox Light Beam
|
||
const beamBottomY = aspect === '9:16' ? 1150 : 730;
|
||
ctx.save();
|
||
ctx.globalCompositeOperation = 'screen';
|
||
const beamGrad = ctx.createLinearGradient(w / 2, 94, w / 2, beamBottomY);
|
||
beamGrad.addColorStop(0, currentTheme.beamTop);
|
||
beamGrad.addColorStop(0.25, currentTheme.beamMid);
|
||
beamGrad.addColorStop(0.65, currentTheme.beamLow);
|
||
beamGrad.addColorStop(1, 'rgba(0, 0, 0, 0)');
|
||
ctx.fillStyle = beamGrad;
|
||
ctx.beginPath();
|
||
ctx.moveTo(w * 0.34, 94); ctx.lineTo(w * 0.66, 94);
|
||
ctx.lineTo(w * 0.86, beamBottomY); ctx.lineTo(w * 0.14, beamBottomY);
|
||
ctx.closePath(); ctx.fill();
|
||
|
||
// Halo Glow behind product
|
||
const haloY = aspect === '9:16' ? 750 : 420;
|
||
const haloR = aspect === '9:16' ? 420 : 280;
|
||
const haloGrad = ctx.createRadialGradient(w / 2, haloY, 15, w / 2, haloY, haloR);
|
||
haloGrad.addColorStop(0, currentTheme.haloCenter);
|
||
haloGrad.addColorStop(0.5, currentTheme.haloMid);
|
||
haloGrad.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = haloGrad;
|
||
ctx.beginPath(); ctx.arc(w / 2, haloY, haloR, 0, Math.PI * 2); ctx.fill();
|
||
ctx.restore();
|
||
|
||
// Floating Stardust Particles
|
||
const particles = [
|
||
{ x: w * 0.18, y: h * 0.21, r: 3.5, a: 0.85 },
|
||
{ x: w * 0.82, y: h * 0.25, r: 4.0, a: 0.90 },
|
||
{ x: w * 0.13, y: h * 0.44, r: 2.5, a: 0.60 },
|
||
{ x: w * 0.87, y: h * 0.48, r: 3.2, a: 0.75 },
|
||
{ x: w * 0.24, y: h * 0.62, r: 2.2, a: 0.50 },
|
||
{ x: w * 0.77, y: h * 0.65, r: 3.5, a: 0.80 },
|
||
{ x: w * 0.50, y: h * 0.14, r: 4.5, a: 0.95 }
|
||
];
|
||
particles.forEach(p => {
|
||
ctx.save();
|
||
ctx.fillStyle = currentTheme.goldAccent;
|
||
ctx.globalAlpha = p.a;
|
||
ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); ctx.fill();
|
||
ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 1;
|
||
ctx.beginPath();
|
||
ctx.moveTo(p.x - p.r * 2.5, p.y); ctx.lineTo(p.x + p.r * 2.5, p.y);
|
||
ctx.moveTo(p.x, p.y - p.r * 2.5); ctx.lineTo(p.x, p.y + p.r * 2.5);
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
});
|
||
|
||
// 3. RADICALLY DISTINCT 3D ARCHITECTURAL PODIUMS
|
||
let stageCx = w / 2;
|
||
if (theme === 'bento_grid_luxe') {
|
||
stageCx = 40 + (w * 0.58) / 2;
|
||
} else if (theme === 'swiss_modular_grid') {
|
||
stageCx = 40 + (w * 0.55 - 40) / 2;
|
||
}
|
||
|
||
const topTierY = aspect === '9:16' ? 1160 : 705;
|
||
const topTierRx = theme === 'bento_grid_luxe' || theme === 'swiss_modular_grid' ? w * 0.24 : (aspect === '9:16' ? w * 0.32 : w * 0.30);
|
||
const topTierRy = aspect === '9:16' ? 26 : 24;
|
||
const topTierH = aspect === '9:16' ? 36 : 35;
|
||
const baseTierY = aspect === '9:16' ? 1200 : 740;
|
||
const baseTierRx = aspect === '9:16' ? w * 0.38 : w * 0.36;
|
||
const baseTierRy = aspect === '9:16' ? 32 : 30;
|
||
const baseTierH = aspect === '9:16' ? 26 : 24;
|
||
|
||
if (theme === 'bento_grid_luxe') {
|
||
// Apple Bento Floating Frosted Glass Riser
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(0,0,0,0.70)';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + 15, topTierRx * 1.05, topTierRy * 1.1, 0, 0, Math.PI * 2); ctx.fill();
|
||
// Glass Disc Body
|
||
ctx.fillStyle = 'rgba(30, 41, 59, 0.85)';
|
||
ctx.fillRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierH);
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.45)'; ctx.lineWidth = 2;
|
||
ctx.strokeRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierH);
|
||
// Cap
|
||
ctx.fillStyle = '#0F172A';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
} else if (theme === 'blueprint_cad_grid') {
|
||
// Industrial CAD Isometric Riser with Wireframe Grid
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(0,0,0,0.92)';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + 25, topTierRx * 1.1, topTierRy * 1.2, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.fillStyle = '#082F49';
|
||
ctx.fillRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierH);
|
||
ctx.strokeStyle = '#38BDF8'; ctx.lineWidth = 1.8;
|
||
// CAD Grid lines on riser
|
||
for (let px = stageCx - topTierRx; px <= stageCx + topTierRx; px += 25) {
|
||
ctx.beginPath(); ctx.moveTo(px, topTierY); ctx.lineTo(px, topTierY + topTierH); ctx.stroke();
|
||
}
|
||
ctx.fillStyle = '#0369A1';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
} else if (theme === 'cyber_hud_grid') {
|
||
// Tron Glowing Green/Cyan Holographic Ring Platform
|
||
ctx.save();
|
||
ctx.strokeStyle = '#00FFCC'; ctx.lineWidth = 3.5;
|
||
ctx.shadowColor = '#00FFCC'; ctx.shadowBlur = 18;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + 8, topTierRx * 1.15, topTierRy * 1.15, 0, 0, Math.PI * 2); ctx.stroke();
|
||
ctx.fillStyle = '#022C22';
|
||
ctx.fillRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierH);
|
||
ctx.fillStyle = '#064E3B';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
} else if (theme === 'brutalist_street') {
|
||
// Industrial Diamond Plate Steel Riser with Hazard Warning Face
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(0,0,0,0.95)';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, baseTierY + 30, baseTierRx, baseTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
const steelGrad = ctx.createLinearGradient(stageCx - topTierRx, 0, stageCx + topTierRx, 0);
|
||
steelGrad.addColorStop(0, '#27272A'); steelGrad.addColorStop(0.5, '#52525B'); steelGrad.addColorStop(1, '#18181B');
|
||
ctx.fillStyle = steelGrad;
|
||
ctx.fillRect(stageCx - topTierRx - 20, topTierY, (topTierRx + 20) * 2, topTierH + 20);
|
||
const hazW = 20;
|
||
ctx.fillStyle = '#FACC15';
|
||
for (let hx = stageCx - topTierRx - 20; hx < stageCx + topTierRx + 20; hx += hazW * 2) {
|
||
ctx.fillRect(hx, topTierY + topTierH - 5, hazW, 25);
|
||
}
|
||
ctx.fillStyle = '#3F3F46';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx + 20, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.strokeStyle = '#FACC15'; ctx.lineWidth = 4;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx + 20, topTierRy, 0, 0, Math.PI * 2); ctx.stroke();
|
||
[-topTierRx, topTierRx].forEach(bx => {
|
||
ctx.fillStyle = '#E4E4E7';
|
||
ctx.beginPath(); ctx.arc(stageCx + bx, topTierY, 6, 0, Math.PI * 2); ctx.fill();
|
||
ctx.strokeStyle = '#000000'; ctx.lineWidth = 1.5; ctx.stroke();
|
||
});
|
||
ctx.restore();
|
||
} else if (theme === 'editorial_vogue' || theme === 'nordic_minimal' || theme === 'swiss_modular_grid') {
|
||
// Minimalist Carrara Marble Monolithic Rectangular Block
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(0,0,0,0.85)';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + topTierH + 15, topTierRx * 1.1, 20, 0, 0, Math.PI * 2); ctx.fill();
|
||
const blockW = topTierRx * 1.8;
|
||
const blockH = 45;
|
||
ctx.fillStyle = theme === 'editorial_vogue' || theme === 'swiss_modular_grid' ? '#292524' : '#E2E8F0';
|
||
ctx.fillRect(stageCx - blockW / 2, topTierY, blockW, blockH);
|
||
ctx.fillStyle = theme === 'editorial_vogue' || theme === 'swiss_modular_grid' ? '#44403C' : '#F8FAFC';
|
||
ctx.beginPath();
|
||
ctx.moveTo(stageCx - blockW / 2, topTierY);
|
||
ctx.lineTo(stageCx - blockW / 2 + 30, topTierY - 20);
|
||
ctx.lineTo(stageCx + blockW / 2 + 30, topTierY - 20);
|
||
ctx.lineTo(stageCx + blockW / 2, topTierY);
|
||
ctx.closePath(); ctx.fill();
|
||
ctx.strokeStyle = theme === 'editorial_vogue' || theme === 'swiss_modular_grid' ? '#A8A29E' : '#94A3B8';
|
||
ctx.lineWidth = 1.5;
|
||
ctx.strokeRect(stageCx - blockW / 2, topTierY, blockW, blockH);
|
||
ctx.restore();
|
||
} else if (theme === 'botanical_eco' || theme === 'kraft_artisan' || theme === 'polaroid_film_grid') {
|
||
// Natural Live-Edge Wooden Tree Trunk Slice with Moss
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(0,0,0,0.92)';
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + 25, topTierRx * 1.05, topTierRy * 1.2, 0, 0, Math.PI * 2); ctx.fill();
|
||
const barkGrad = ctx.createLinearGradient(stageCx - topTierRx, 0, stageCx + topTierRx, 0);
|
||
barkGrad.addColorStop(0, '#271206'); barkGrad.addColorStop(0.5, '#451A03'); barkGrad.addColorStop(1, '#1A0B04');
|
||
ctx.fillStyle = barkGrad;
|
||
ctx.fillRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierH);
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + topTierH, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
const woodTop = ctx.createRadialGradient(stageCx, topTierY, 10, stageCx, topTierY, topTierRx);
|
||
woodTop.addColorStop(0, '#B45309'); woodTop.addColorStop(0.6, '#92400E'); woodTop.addColorStop(1, '#78350F');
|
||
ctx.fillStyle = woodTop;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.strokeStyle = 'rgba(253, 230, 138, 0.15)'; ctx.lineWidth = 1.5;
|
||
[0.3, 0.6, 0.85].forEach(scale => {
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx * scale, topTierRy * scale, 0, 0, Math.PI * 2); ctx.stroke();
|
||
});
|
||
ctx.fillStyle = '#10B981';
|
||
for (let mx = -topTierRx * 0.8; mx <= topTierRx * 0.8; mx += 14) {
|
||
ctx.beginPath(); ctx.arc(stageCx + mx, topTierY + Math.sin(mx * 0.2) * 4, 3.5, 0, Math.PI * 2); ctx.fill();
|
||
}
|
||
ctx.restore();
|
||
} else if (theme === 'cyber_neon' || theme === 'tokyo_synthwave' || theme === 'arcade_retro') {
|
||
// 3D Holographic Wireframe Floating Neon Energy Platform
|
||
ctx.save();
|
||
ctx.strokeStyle = currentTheme.goldRim; ctx.lineWidth = 4;
|
||
ctx.shadowColor = currentTheme.goldRim; ctx.shadowBlur = 20;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + 10, topTierRx * 1.15, topTierRy * 1.15, 0, 0, Math.PI * 2); ctx.stroke();
|
||
ctx.fillStyle = currentTheme.pedestalTop;
|
||
ctx.fillRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierH);
|
||
ctx.strokeStyle = currentTheme.goldAccent; ctx.lineWidth = 1.5;
|
||
for (let px = stageCx - topTierRx; px <= stageCx + topTierRx; px += 35) {
|
||
ctx.beginPath(); ctx.moveTo(px, topTierY); ctx.lineTo(px, topTierY + topTierH); ctx.stroke();
|
||
}
|
||
ctx.fillStyle = currentTheme.pedestalMid;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
} else {
|
||
// Luxury Fluted Multi-Tier Cylinder Podium
|
||
const shadowGrad = ctx.createRadialGradient(stageCx, baseTierY + 32, 20, stageCx, baseTierY + 32, baseTierRx * 1.15);
|
||
shadowGrad.addColorStop(0, 'rgba(0,0,0,0.95)'); shadowGrad.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = shadowGrad;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, baseTierY + 32, baseTierRx * 1.15, baseTierRy * 1.5, 0, 0, Math.PI * 2); ctx.fill();
|
||
|
||
const baseCylGrad = ctx.createLinearGradient(stageCx - baseTierRx, 0, stageCx + baseTierRx, 0);
|
||
baseCylGrad.addColorStop(0, currentTheme.pedestalDark); baseCylGrad.addColorStop(0.5, currentTheme.pedestalMid); baseCylGrad.addColorStop(1, currentTheme.pedestalDark);
|
||
ctx.fillStyle = baseCylGrad;
|
||
ctx.fillRect(stageCx - baseTierRx, baseTierY, baseTierRx * 2, baseTierH);
|
||
ctx.beginPath(); ctx.ellipse(stageCx, baseTierY + baseTierH, baseTierRx, baseTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.beginPath(); ctx.ellipse(stageCx, baseTierY, baseTierRx, baseTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
|
||
const topCylGrad = ctx.createLinearGradient(stageCx - topTierRx, 0, stageCx + topTierRx, 0);
|
||
topCylGrad.addColorStop(0, currentTheme.cylStart); topCylGrad.addColorStop(0.2, currentTheme.goldRim);
|
||
topCylGrad.addColorStop(0.5, currentTheme.goldAccent); topCylGrad.addColorStop(0.8, currentTheme.goldRim);
|
||
topCylGrad.addColorStop(1, currentTheme.cylEnd);
|
||
ctx.fillStyle = topCylGrad;
|
||
ctx.fillRect(stageCx - topTierRx, topTierY, topTierRx * 2, topTierH);
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + topTierH, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
|
||
const topCapGrad = ctx.createRadialGradient(stageCx, topTierY, 0, stageCx, topTierY, topTierRx);
|
||
topCapGrad.addColorStop(0, currentTheme.pedestalTop); topCapGrad.addColorStop(0.6, currentTheme.pedestalMid); topCapGrad.addColorStop(1, currentTheme.pedestalDark);
|
||
ctx.fillStyle = topCapGrad;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.fill();
|
||
|
||
ctx.strokeStyle = currentTheme.goldRim; ctx.lineWidth = 3.5;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY, topTierRx, topTierRy, 0, 0, Math.PI * 2); ctx.stroke();
|
||
}
|
||
|
||
// 4. Product Scaling & Grounded 3D Render
|
||
if (productImg) {
|
||
const isBento = theme === 'bento_grid_luxe';
|
||
const isSwiss = theme === 'swiss_modular_grid';
|
||
const pSize = isBento || isSwiss ? (aspect === '9:16' ? 560 : 440) : (aspect === '9:16' ? 680 : 530);
|
||
const pLeft = stageCx - pSize / 2;
|
||
const pTop = topTierY - pSize + (aspect === '9:16' ? 25 : 18);
|
||
|
||
const pCan = document.createElement('canvas');
|
||
pCan.width = productImg.width || 600;
|
||
pCan.height = productImg.height || 600;
|
||
const pCtx = pCan.getContext('2d');
|
||
pCtx.drawImage(productImg, 0, 0, pCan.width, pCan.height);
|
||
|
||
pCtx.globalCompositeOperation = 'destination-in';
|
||
const fadeGrad = pCtx.createRadialGradient(
|
||
pCan.width / 2, pCan.height * 0.48, pCan.width * 0.38,
|
||
pCan.width / 2, pCan.height * 0.48, pCan.width * 0.495
|
||
);
|
||
fadeGrad.addColorStop(0, 'rgba(0,0,0,1)');
|
||
fadeGrad.addColorStop(0.88, 'rgba(0,0,0,1)');
|
||
fadeGrad.addColorStop(1, 'rgba(0,0,0,0)');
|
||
pCtx.fillStyle = fadeGrad;
|
||
pCtx.fillRect(0, 0, pCan.width, pCan.height);
|
||
|
||
ctx.save();
|
||
const contactShadow = ctx.createRadialGradient(stageCx, topTierY + 2, 8, stageCx, topTierY + 2, topTierRx * 0.75);
|
||
contactShadow.addColorStop(0, 'rgba(0,0,0,0.88)');
|
||
contactShadow.addColorStop(0.5, 'rgba(0,0,0,0.45)');
|
||
contactShadow.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = contactShadow;
|
||
ctx.beginPath(); ctx.ellipse(stageCx, topTierY + 2, topTierRx * 0.75, topTierRy * 0.75, 0, 0, Math.PI * 2); ctx.fill();
|
||
ctx.restore();
|
||
|
||
ctx.save();
|
||
ctx.globalCompositeOperation = 'source-over';
|
||
ctx.shadowColor = 'rgba(0,0,0,0.6)';
|
||
ctx.shadowBlur = 22;
|
||
ctx.shadowOffsetY = 10;
|
||
ctx.drawImage(pCan, pLeft, pTop, pSize, pSize);
|
||
ctx.restore();
|
||
}
|
||
|
||
// 5. RADICALLY DISTINCT THEME HEADER ARCHITECTURES
|
||
if (theme === 'bento_grid_luxe') {
|
||
ctx.fillStyle = '#0F131C';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.4)'; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#F8FAFC';
|
||
ctx.font = '900 30px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('🍱 BENTO KEYNOTE SPEC EDITION', w / 2, 50);
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = '700 13px Consolas, monospace';
|
||
ctx.fillText('QUADRANT SPEC SHEET // 100% VERIFIED AUTHENTIC', w / 2, 80);
|
||
} else if (theme === 'swiss_modular_grid') {
|
||
ctx.fillStyle = '#0D0D10';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#FFFFFF'; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = '900 32px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('■ SWISS BAUHAUS MODULAR GRID', w / 2, 50);
|
||
ctx.fillStyle = '#F43F5E';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.fillText('PRECISION ARCHITECTURAL EDITION // 2026', w / 2, 80);
|
||
} else if (theme === 'blueprint_cad_grid') {
|
||
ctx.fillStyle = '#061727';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#38BDF8'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = '900 28px Consolas, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('/// ARCHITECTURAL CAD SCHEMATIC ///', w / 2, 50);
|
||
ctx.fillStyle = '#BAE6FD';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.fillText('ENGINEERING SPEC_SHEET // SCALE 1:1 // PASS', w / 2, 80);
|
||
} else if (theme === 'polaroid_film_grid') {
|
||
ctx.fillStyle = '#100C0A';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#D97706'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#FDE68A';
|
||
ctx.font = '900 28px Georgia, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('🎞️ 35mm FILMSTRIP CONTACT GRID 🎞️', w / 2, 50);
|
||
ctx.fillStyle = '#D97706';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.fillText('KODAK 400TX // PRO GALLERY SELECTION', w / 2, 80);
|
||
} else if (theme === 'cyber_hud_grid') {
|
||
ctx.fillStyle = '#050D1A';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#00FFCC'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#00FFCC';
|
||
ctx.font = '900 28px Consolas, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('[ TRON_HUD // TELEMETRY_GRID_V4 ]', w / 2, 50);
|
||
ctx.fillStyle = '#A7F3D0';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.fillText('ACTIVE SENSOR ARRAY // 100% QUANTUM SECURE', w / 2, 80);
|
||
} else if (theme === 'editorial_vogue') {
|
||
ctx.fillStyle = '#0F0E0D';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#E7E5E4'; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = '900 38px Playfair Display, Georgia, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('V O G U E E D I T I O N', w / 2, 52);
|
||
ctx.fillStyle = '#A8A29E';
|
||
ctx.font = '700 13px Plus Jakarta Sans, sans-serif';
|
||
ctx.letterSpacing = '3px';
|
||
ctx.fillText('VOL. 26 // AUTUMN / WINTER HAUTE COUTURE', w / 2, 82);
|
||
} else if (theme === 'brutalist_street') {
|
||
ctx.fillStyle = '#18181B';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.fillStyle = '#FACC15';
|
||
ctx.fillRect(0, 94, w, 6);
|
||
ctx.fillStyle = '#FACC15';
|
||
ctx.font = '900 30px Impact, Arial Black, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('/// HEAVYWEIGHT TECHNICAL DIVISION ///', w / 2, 50);
|
||
ctx.fillStyle = '#E4E4E7';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.fillText('SPEC_OPS // 100% ORIGINAL // STREETWEAR', w / 2, 78);
|
||
} else if (theme === 'mughal_heritage') {
|
||
ctx.fillStyle = '#180B04';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#F59E0B'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#FDE68A';
|
||
ctx.font = 'bold 32px Hind Siliguri, Playfair Display, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('⚜️ রাজকীয় ঐতিহ্য প্রিমিয়াম কালেকশন ⚜️', w / 2, 50);
|
||
ctx.fillStyle = '#FCD34D';
|
||
ctx.font = '600 15px Hind Siliguri, sans-serif';
|
||
ctx.fillText('হাতে বোনা আভিজাত্য • শতভাগ খাঁটি ও অরিজিনাল', w / 2, 80);
|
||
} else if (theme === 'cyber_neon') {
|
||
ctx.fillStyle = '#070E18';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#06B6D4'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = '900 28px Consolas, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('[ PROTOCOL // CYBER_MATRIX_V3 ]', w / 2, 50);
|
||
ctx.fillStyle = '#22D3EE';
|
||
ctx.font = 'bold 14px Consolas, monospace';
|
||
ctx.fillText('STATUS: ONLINE • AUTHENTIC HARDWARE SECURED', w / 2, 78);
|
||
} else if (theme === 'tokyo_synthwave') {
|
||
ctx.fillStyle = '#100520';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#F43F5E'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#F43F5E';
|
||
ctx.font = '900 32px Impact, Arial Black, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('/// TOKYO NIGHTS 1984 ///', w / 2, 52);
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.fillText('RETRO-WAVE SYNTH // LIMITED EDITION', w / 2, 80);
|
||
} else if (theme === 'vip_blackcard') {
|
||
ctx.fillStyle = '#0A0A0C';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#D4AF37'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#D4AF37';
|
||
ctx.font = 'bold 30px Cinzel, Times New Roman, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('💳 CENTURION BLACK VIP 💳', w / 2, 50);
|
||
ctx.fillStyle = '#F3E5AB';
|
||
ctx.font = '600 14px Plus Jakarta Sans, sans-serif';
|
||
ctx.letterSpacing = '2px';
|
||
ctx.fillText('EXCLUSIVELY FOR PRIVILEGED MEMBERS', w / 2, 80);
|
||
} else if (theme === 'botanical_eco') {
|
||
ctx.fillStyle = '#09140E';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#10B981'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#6EE7B7';
|
||
ctx.font = 'bold 30px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('🌿 100% ORGANIC & BOTANICAL 🌿', w / 2, 50);
|
||
ctx.fillStyle = '#A7F3D0';
|
||
ctx.font = '600 14px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('SUSTAINABLE HARVEST • PURE & NATURAL', w / 2, 80);
|
||
} else if (theme === 'art_deco_gilded') {
|
||
ctx.fillStyle = '#0E0B07';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#EAB308'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#FEF08A';
|
||
ctx.font = 'bold 30px Cinzel, Playfair Display, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('✦ THE GILDED GATSBY COLLECTION ✦', w / 2, 50);
|
||
ctx.fillStyle = '#FDE047';
|
||
ctx.font = '600 13px Plus Jakarta Sans, sans-serif';
|
||
ctx.letterSpacing = '2px';
|
||
ctx.fillText('1920s ART DECO MASTERPIECE', w / 2, 80);
|
||
} else if (theme === 'frost_titanium') {
|
||
ctx.fillStyle = '#0A131F';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#38BDF8'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#E0F2FE';
|
||
ctx.font = 'bold 30px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('❄️ SUB-ZERO ARCTIC TITANIUM ❄️', w / 2, 50);
|
||
ctx.fillStyle = '#BAE6FD';
|
||
ctx.font = '600 14px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('AEROSPACE GRADE METALLURGY', w / 2, 80);
|
||
} else if (theme === 'flash_sale_matrix') {
|
||
ctx.fillStyle = '#140404';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.fillStyle = '#EF4444'; ctx.fillRect(0, 94, w, 6);
|
||
ctx.fillStyle = '#FCA5A5';
|
||
ctx.font = '900 32px Impact, Arial Black, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('⚡ MEGA FLASH SALE // LIMITED STOCK ⚡', w / 2, 50);
|
||
ctx.fillStyle = '#FECACA';
|
||
ctx.font = 'bold 14px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('SPECIAL PROMOTIONAL CAMPAIGN', w / 2, 78);
|
||
} else if (theme === 'holographic_prism') {
|
||
ctx.fillStyle = '#0E0B1A';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#C084FC'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#F0ABFC';
|
||
ctx.font = 'bold 30px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('✦ CHROMATIC PRISM 3D EDITION ✦', w / 2, 50);
|
||
ctx.fillStyle = '#E879F9';
|
||
ctx.font = '600 14px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('IRIDESCENT SPECTRUM REFLECTION', w / 2, 80);
|
||
} else if (theme === 'cosmic_nebula') {
|
||
ctx.fillStyle = '#100624';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#C084FC'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#F3E8FF';
|
||
ctx.font = 'bold 30px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('🌌 DEEP SPACE ORBITAL EDITION 🌌', w / 2, 50);
|
||
ctx.fillStyle = '#D8B4FE';
|
||
ctx.font = '600 14px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('CELESTIAL GRAVITY & STELLAR PRECISION', w / 2, 80);
|
||
} else if (theme === 'kraft_artisan') {
|
||
ctx.fillStyle = '#1A120B';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.strokeStyle = '#D97706'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(w, 100); ctx.stroke();
|
||
ctx.fillStyle = '#FDE68A';
|
||
ctx.font = 'bold 30px Georgia, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('★ HANDCRAFTED ARTISAN QUALITY ★', w / 2, 50);
|
||
ctx.fillStyle = '#FCD34D';
|
||
ctx.font = '600 14px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('GENUINE RECLAIMED WORKSHOP EDITION', w / 2, 80);
|
||
} else if (theme === 'arcade_retro') {
|
||
ctx.fillStyle = '#060B18';
|
||
ctx.fillRect(0, 0, w, 100);
|
||
ctx.fillStyle = '#FACC15'; ctx.fillRect(0, 94, w, 6);
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = '900 28px Consolas, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('🕹️ INSERT COIN // LEVEL UP 🕹️', w / 2, 50);
|
||
ctx.fillStyle = '#FACC15';
|
||
ctx.font = 'bold 13px Consolas, monospace';
|
||
ctx.fillText('PLAYER 1 READY • 100% RETRO WINNER', w / 2, 78);
|
||
} else {
|
||
ctx.fillStyle = '#090D14';
|
||
ctx.fillRect(0, 0, w, 94);
|
||
ctx.strokeStyle = currentTheme.goldRim; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, 94); ctx.lineTo(w, 94); ctx.stroke();
|
||
ctx.fillStyle = currentTheme.goldAccent;
|
||
ctx.font = '900 32px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(brandInfo.headerTitle, w / 2, 48);
|
||
ctx.fillStyle = '#E2E8F0';
|
||
ctx.font = '700 15px Plus Jakarta Sans, sans-serif';
|
||
ctx.letterSpacing = '1.5px';
|
||
ctx.fillText(brandInfo.headerSub, w / 2, 78);
|
||
}
|
||
|
||
// 6. RADICALLY DISTINCT THEME BADGES
|
||
// (Skip standard floating badges for Bento & Blueprint grid as they have built-in grid cards)
|
||
if (theme !== 'bento_grid_luxe' && theme !== 'cyber_hud_grid') {
|
||
function drawBespokeBadge(bx, by, text, isLeft) {
|
||
ctx.save();
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '20px' : '18px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
const textW = ctx.measureText(text).width;
|
||
const padX = aspect === '9:16' ? 24 : 22;
|
||
const badgeH = aspect === '9:16' ? 50 : 46;
|
||
const badgeW = textW + padX * 2;
|
||
const startX = isLeft ? bx : bx - badgeW;
|
||
|
||
if (theme === 'brutalist_street') {
|
||
ctx.fillStyle = '#FACC15';
|
||
ctx.fillRect(startX, by, badgeW, badgeH);
|
||
ctx.strokeStyle = '#000000'; ctx.lineWidth = 2.5;
|
||
ctx.strokeRect(startX, by, badgeW, badgeH);
|
||
ctx.fillStyle = '#000000';
|
||
ctx.font = '900 ' + (aspect === '9:16' ? '19px' : '17px') + ' Impact, Consolas, monospace';
|
||
ctx.fillText(text, startX + padX, by + (aspect === '9:16' ? 32 : 29));
|
||
} else if (theme === 'editorial_vogue' || theme === 'nordic_minimal' || theme === 'swiss_modular_grid') {
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.96)';
|
||
ctx.fillRect(startX, by, badgeW, badgeH);
|
||
ctx.strokeStyle = '#1C1917'; ctx.lineWidth = 1.5;
|
||
ctx.strokeRect(startX, by, badgeW, badgeH);
|
||
ctx.fillStyle = '#1C1917';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '18px' : '16px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(text, startX + padX, by + (aspect === '9:16' ? 31 : 28));
|
||
} else if (theme === 'blueprint_cad_grid') {
|
||
ctx.fillStyle = 'rgba(8, 47, 73, 0.90)';
|
||
ctx.strokeStyle = '#38BDF8'; ctx.lineWidth = 2;
|
||
ctx.strokeRect(startX, by, badgeW, badgeH);
|
||
ctx.fillStyle = '#BAE6FD';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '17px' : '15px') + ' Consolas, monospace';
|
||
ctx.fillText(text, startX + padX, by + (aspect === '9:16' ? 32 : 29));
|
||
} else if (theme === 'cyber_neon' || theme === 'tokyo_synthwave') {
|
||
ctx.fillStyle = 'rgba(8, 47, 73, 0.90)';
|
||
ctx.strokeStyle = theme === 'tokyo_synthwave' ? '#F43F5E' : '#06B6D4'; ctx.lineWidth = 2;
|
||
ctx.shadowColor = theme === 'tokyo_synthwave' ? '#F43F5E' : '#06B6D4'; ctx.shadowBlur = 12;
|
||
ctx.beginPath(); ctx.roundRect(startX, by, badgeW, badgeH, 6); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = theme === 'tokyo_synthwave' ? '#FED7AA' : '#38BDF8';
|
||
ctx.fillText(text, startX + padX, by + (aspect === '9:16' ? 32 : 29));
|
||
} else if (theme === 'botanical_eco') {
|
||
ctx.fillStyle = 'rgba(6, 78, 59, 0.92)';
|
||
ctx.strokeStyle = '#10B981'; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.roundRect(startX, by, badgeW, badgeH, badgeH / 2); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#D1FAE5';
|
||
ctx.fillText(text, startX + padX, by + (aspect === '9:16' ? 32 : 29));
|
||
} else if (theme === 'flash_sale_matrix') {
|
||
ctx.fillStyle = '#EF4444';
|
||
ctx.strokeStyle = '#FACC15'; ctx.lineWidth = 2.5;
|
||
ctx.beginPath(); ctx.roundRect(startX, by, badgeW, badgeH, 8); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillText(text, startX + padX, by + (aspect === '9:16' ? 32 : 29));
|
||
} else {
|
||
ctx.fillStyle = 'rgba(9, 13, 20, 0.92)';
|
||
ctx.strokeStyle = currentTheme.goldRim; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.roundRect(startX, by, badgeW, badgeH, badgeH / 2); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillText(text, startX + padX, by + (aspect === '9:16' ? 32 : 29));
|
||
}
|
||
ctx.restore();
|
||
}
|
||
|
||
const bY1 = aspect === '9:16' ? 240 : 180;
|
||
const bY2 = aspect === '9:16' ? 310 : 245;
|
||
drawBespokeBadge(40, bY1, badgeText, true);
|
||
drawBespokeBadge(40, bY2, brandInfo.badgeL1, true);
|
||
drawBespokeBadge(w - 40, bY1, '⚡ Fast Delivery BD', false);
|
||
drawBespokeBadge(w - 40, bY2, brandInfo.badgeL2, false);
|
||
}
|
||
|
||
// 7. RADICALLY DISTINCT PRODUCT TITLE & PRICE CARDS
|
||
const bannerY = aspect === '9:16' ? 1320 : 770;
|
||
const bannerH = aspect === '9:16' ? 130 : 110;
|
||
const bannerMargin = 40;
|
||
const bannerW = w - bannerMargin * 2;
|
||
const cleanTitle = title.length > 55 ? title.substring(0, 52) + '...' : title;
|
||
|
||
if (theme === 'bento_grid_luxe') {
|
||
ctx.fillStyle = 'rgba(15, 23, 42, 0.92)';
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.45)'; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.roundRect(bannerMargin, bannerY, bannerW, bannerH, 18); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '34px' : '28px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(cleanTitle, w / 2, bannerY + (aspect === '9:16' ? 52 : 44));
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = '700 ' + (aspect === '9:16' ? '24px' : '21px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.fillText(`OFFER PRICE: ${price} • AUTHENTIC VERIFIED SPEC`, w / 2, bannerY + (aspect === '9:16' ? 98 : 85));
|
||
} else if (theme === 'blueprint_cad_grid') {
|
||
ctx.fillStyle = 'rgba(6, 23, 39, 0.96)';
|
||
ctx.strokeStyle = '#38BDF8'; ctx.lineWidth = 2.5;
|
||
ctx.strokeRect(bannerMargin, bannerY, bannerW, bannerH);
|
||
ctx.fillStyle = '#E0F2FE';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '30px' : '26px') + ' Consolas, Hind Siliguri, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(`[SPEC_MODEL]: ${cleanTitle.toUpperCase()}`, w / 2, bannerY + (aspect === '9:16' ? 52 : 44));
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '22px' : '20px') + ' Consolas, monospace';
|
||
ctx.fillText(`UNIT_VAL: ${price} // APPROVED PRODUCTION SPEC`, w / 2, bannerY + (aspect === '9:16' ? 98 : 85));
|
||
} else if (theme === 'brutalist_street') {
|
||
ctx.fillStyle = '#18181B';
|
||
ctx.fillRect(bannerMargin, bannerY, bannerW, bannerH);
|
||
ctx.strokeStyle = '#FACC15'; ctx.lineWidth = 3;
|
||
ctx.strokeRect(bannerMargin, bannerY, bannerW, bannerH);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = '900 ' + (aspect === '9:16' ? '34px' : '28px') + ' Impact, Arial Black, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(cleanTitle.toUpperCase(), w / 2, bannerY + (aspect === '9:16' ? 52 : 44));
|
||
ctx.fillStyle = '#FACC15';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '24px' : '22px') + ' Consolas, Hind Siliguri, monospace';
|
||
ctx.fillText(`PRICE: ${price} /// 100% ORIGINAL STOCK`, w / 2, bannerY + (aspect === '9:16' ? 98 : 85));
|
||
} else if (theme === 'editorial_vogue' || theme === 'nordic_minimal' || theme === 'swiss_modular_grid') {
|
||
ctx.fillStyle = '#1C1917';
|
||
ctx.fillRect(bannerMargin, bannerY, bannerW, bannerH);
|
||
ctx.strokeStyle = '#E7E5E4'; ctx.lineWidth = 1.5;
|
||
ctx.strokeRect(bannerMargin, bannerY, bannerW, bannerH);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '32px' : '28px') + ' Playfair Display, Georgia, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(cleanTitle, w / 2, bannerY + (aspect === '9:16' ? 50 : 42));
|
||
ctx.fillStyle = '#E7E5E4';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '22px' : '20px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.fillText(`${price} • AUTHENTIC COUTURE SELECTION`, w / 2, bannerY + (aspect === '9:16' ? 96 : 84));
|
||
} else if (theme === 'mughal_heritage') {
|
||
ctx.fillStyle = 'rgba(24, 11, 4, 0.96)';
|
||
ctx.strokeStyle = '#F59E0B'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.roundRect(bannerMargin, bannerY, bannerW, bannerH, 16); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#FDE68A';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '34px' : '28px') + ' Hind Siliguri, Playfair Display, serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(cleanTitle, w / 2, bannerY + (aspect === '9:16' ? 52 : 44));
|
||
ctx.fillStyle = '#F59E0B';
|
||
ctx.font = '700 ' + (aspect === '9:16' ? '24px' : '21px') + ' Hind Siliguri, sans-serif';
|
||
ctx.fillText(`${price} • ১০০% খাঁটি গ্যারান্টি • দ্রুত হোম ডেলিভারি`, w / 2, bannerY + (aspect === '9:16' ? 98 : 85));
|
||
} else if (theme === 'cyber_neon' || theme === 'tokyo_synthwave' || theme === 'cyber_hud_grid') {
|
||
ctx.fillStyle = 'rgba(8, 47, 73, 0.94)';
|
||
ctx.strokeStyle = theme === 'cyber_hud_grid' ? '#00FFCC' : (theme === 'tokyo_synthwave' ? '#F43F5E' : '#06B6D4'); ctx.lineWidth = 2.5;
|
||
ctx.shadowColor = theme === 'cyber_hud_grid' ? '#00FFCC' : (theme === 'tokyo_synthwave' ? '#F43F5E' : '#06B6D4'); ctx.shadowBlur = 10;
|
||
ctx.beginPath(); ctx.roundRect(bannerMargin, bannerY, bannerW, bannerH, 8); ctx.fill(); ctx.stroke();
|
||
ctx.shadowBlur = 0;
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '32px' : '28px') + ' Consolas, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(cleanTitle, w / 2, bannerY + (aspect === '9:16' ? 52 : 44));
|
||
ctx.fillStyle = theme === 'cyber_hud_grid' ? '#00FFCC' : (theme === 'tokyo_synthwave' ? '#FED7AA' : '#38BDF8');
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '24px' : '21px') + ' Consolas, sans-serif';
|
||
ctx.fillText(`VAL: ${price} // VERIFIED AUTHENTIC // FAST_EXP`, w / 2, bannerY + (aspect === '9:16' ? 98 : 85));
|
||
} else if (theme === 'botanical_eco') {
|
||
ctx.fillStyle = 'rgba(6, 78, 59, 0.94)';
|
||
ctx.strokeStyle = '#10B981'; ctx.lineWidth = 2.5;
|
||
ctx.beginPath(); ctx.roundRect(bannerMargin, bannerY, bannerW, bannerH, 18); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '34px' : '28px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(cleanTitle, w / 2, bannerY + (aspect === '9:16' ? 52 : 44));
|
||
ctx.fillStyle = '#6EE7B7';
|
||
ctx.font = '700 ' + (aspect === '9:16' ? '22px' : '20px') + ' Hind Siliguri, sans-serif';
|
||
ctx.fillText(`${price} • ১০০% অর্গানিক ও ফ্রেশ • হোম ডেলিভারি`, w / 2, bannerY + (aspect === '9:16' ? 98 : 85));
|
||
} else {
|
||
ctx.fillStyle = 'rgba(9, 13, 20, 0.94)';
|
||
ctx.strokeStyle = currentTheme.goldRim; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.roundRect(bannerMargin, bannerY, bannerW, bannerH, 18); ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '36px' : '30px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(cleanTitle, w / 2, bannerY + (aspect === '9:16' ? 54 : 45));
|
||
ctx.fillStyle = currentTheme.goldAccent;
|
||
ctx.font = '700 ' + (aspect === '9:16' ? '22px' : '20px') + ' Hind Siliguri, sans-serif';
|
||
ctx.fillText(`${price} • ১০০% আসল গ্যারান্টি • দ্রুত হোম ডেলিভারি`, w / 2, bannerY + (aspect === '9:16' ? 98 : 85));
|
||
}
|
||
|
||
// 8. RADICALLY DISTINCT THEME FOOTERS & HOTLINES
|
||
const footerHeight = aspect === '9:16' ? 110 : 100;
|
||
const footerTop = h - footerHeight;
|
||
|
||
if (theme === 'bento_grid_luxe') {
|
||
ctx.fillStyle = '#0B0F17';
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.4)'; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.moveTo(0, footerTop); ctx.lineTo(w, footerTop); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '32px' : '28px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`💬 WhatsApp Order: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '18px' : '16px') + ' Consolas, monospace';
|
||
ctx.fillText(`WEB: ${brandInfo.footerSite} • HOTLINE: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
} else if (theme === 'blueprint_cad_grid') {
|
||
ctx.fillStyle = '#061727';
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
ctx.strokeStyle = '#38BDF8'; ctx.lineWidth = 2.5;
|
||
ctx.beginPath(); ctx.moveTo(0, footerTop); ctx.lineTo(w, footerTop); ctx.stroke();
|
||
ctx.fillStyle = '#38BDF8';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '30px' : '26px') + ' Consolas, monospace';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`/// DISPATCH_HOTLINE: ${brandInfo.footerHotline} ///`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
ctx.fillStyle = '#BAE6FD';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '18px' : '16px') + ' Consolas, monospace';
|
||
ctx.fillText(`SERVER_STORE: ${brandInfo.footerSite} // STATUS: VERIFIED_OK`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
} else if (theme === 'brutalist_street') {
|
||
ctx.fillStyle = '#FACC15';
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
ctx.fillStyle = '#000000';
|
||
ctx.font = '900 ' + (aspect === '9:16' ? '32px' : '30px') + ' Impact, Arial Black, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`/// WHATSAPP ORDER: ${brandInfo.footerHotline} ///`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
ctx.fillStyle = '#18181B';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '18px' : '16px') + ' Consolas, monospace';
|
||
ctx.fillText(`WEB: ${brandInfo.footerSite} // HOTLINE: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
} else if (theme === 'editorial_vogue' || theme === 'nordic_minimal' || theme === 'swiss_modular_grid') {
|
||
ctx.fillStyle = '#0F0E0D';
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
ctx.strokeStyle = '#E7E5E4'; ctx.lineWidth = 2;
|
||
ctx.beginPath(); ctx.moveTo(0, footerTop); ctx.lineTo(w, footerTop); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '30px' : '28px') + ' Playfair Display, Georgia, serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`Private Concierge: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
ctx.fillStyle = '#A8A29E';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '18px' : '16px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(`Official Boutique: ${brandInfo.footerSite} • Direct Hotline: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
} else if (theme === 'mughal_heritage') {
|
||
const footGrad = ctx.createLinearGradient(0, footerTop, w, footerTop);
|
||
footGrad.addColorStop(0, '#78350F'); footGrad.addColorStop(1, '#451A03');
|
||
ctx.fillStyle = footGrad;
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
ctx.strokeStyle = '#F59E0B'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, footerTop); ctx.lineTo(w, footerTop); ctx.stroke();
|
||
ctx.fillStyle = '#FDE68A';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '32px' : '28px') + ' Hind Siliguri, serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`💬 হোয়াটসঅ্যাপ অর্ডার: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
ctx.fillStyle = '#FEF3C7';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '20px' : '17px') + ' Hind Siliguri, sans-serif';
|
||
ctx.fillText(`🌐 ওয়েবসাইট: ${brandInfo.footerSite} • 📞 হটলাইন: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
} else if (theme === 'botanical_eco') {
|
||
const footGrad = ctx.createLinearGradient(0, footerTop, w, footerTop);
|
||
footGrad.addColorStop(0, '#064E3B'); footGrad.addColorStop(1, '#022C22');
|
||
ctx.fillStyle = footGrad;
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
ctx.strokeStyle = '#10B981'; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, footerTop); ctx.lineTo(w, footerTop); ctx.stroke();
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '34px' : '32px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`🌿 Botanical Order: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
ctx.fillStyle = '#A7F3D0';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '21px' : '19px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(`🌐 Eco Store: ${brandInfo.footerSite} • 📞 Hotline: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
} else {
|
||
const footGrad = ctx.createLinearGradient(0, footerTop, w, footerTop);
|
||
footGrad.addColorStop(0, '#10B981'); footGrad.addColorStop(1, '#059669');
|
||
ctx.fillStyle = footGrad;
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '34px' : '32px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`💬 WhatsApp Order: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
ctx.fillStyle = '#DCFCE7';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '21px' : '19px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(`🌐 Website: ${brandInfo.footerSite} • 📞 Hotline: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
}
|
||
|
||
// QR Code Icon on Footer
|
||
const qrS = aspect === '9:16' ? 86 : 80;
|
||
const qrX = w - qrS - 40;
|
||
const qrY = footerTop + (footerHeight - qrS) / 2;
|
||
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillRect(qrX, qrY, qrS, qrS);
|
||
ctx.fillStyle = '#000000';
|
||
ctx.fillRect(qrX + 6, qrY + 6, 24, 24);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillRect(qrX + 10, qrY + 10, 16, 16);
|
||
ctx.fillStyle = '#000000';
|
||
ctx.fillRect(qrX + 13, qrY + 13, 10, 10);
|
||
ctx.fillRect(qrX + qrS - 30, qrY + 6, 24, 24);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillRect(qrX + qrS - 26, qrY + 10, 16, 16);
|
||
ctx.fillStyle = '#000000';
|
||
ctx.fillRect(qrX + qrS - 23, qrY + 13, 10, 10);
|
||
|
||
// Outer Border Rim
|
||
ctx.strokeStyle = currentTheme.goldRim + '99';
|
||
ctx.lineWidth = 6;
|
||
ctx.strokeRect(3, 3, w - 6, h - 6);
|
||
}
|
||
|
||
window.render3DCommercialPoster = render3DCommercialPoster;
|
||
|
||
// =========================================================================
|
||
// 🔲 Multi-Product Grid Commercial Poster Rendering Engine (3-4 Products)
|
||
// =========================================================================
|
||
async function renderMultiProductGridPoster(canvas, products, gridLayout = '2x2_quad', mainHeadline = '✨ 4-IN-1 MEGA COMBO ROUTINE', theme = 'obsidian_gold', aspect = '1:1', brand = 'glamourstouch', customOverrides = null) {
|
||
const ctx = canvas.getContext('2d');
|
||
const w = canvas.width;
|
||
const h = canvas.height;
|
||
|
||
const baseBrand = getBrandProfile(brand);
|
||
const brandInfo = Object.assign({}, baseBrand, customOverrides || {});
|
||
const currentTheme = THEMES[theme] || THEMES.obsidian_gold;
|
||
|
||
// 1. Studio Radial Backdrop
|
||
const stageCy = aspect === '9:16' ? h * 0.45 : h * 0.46;
|
||
const bgGrad = ctx.createRadialGradient(w / 2, stageCy, 40, w / 2, stageCy, w * 0.85);
|
||
bgGrad.addColorStop(0, currentTheme.bgCenter);
|
||
bgGrad.addColorStop(0.5, currentTheme.bgMid);
|
||
bgGrad.addColorStop(1, currentTheme.bgOuter);
|
||
ctx.fillStyle = bgGrad;
|
||
ctx.fillRect(0, 0, w, h);
|
||
|
||
// Background Theme Nuances
|
||
if (theme === 'bento_grid_luxe' || theme === 'swiss_modular_grid') {
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(255, 255, 255, 0.05)';
|
||
for (let dx = 30; dx < w; dx += 30) {
|
||
for (let dy = 110; dy < h - 120; dy += 30) {
|
||
ctx.beginPath(); ctx.arc(dx, dy, 1.2, 0, Math.PI * 2); ctx.fill();
|
||
}
|
||
}
|
||
ctx.restore();
|
||
} else if (theme === 'blueprint_cad_grid') {
|
||
ctx.save();
|
||
ctx.strokeStyle = 'rgba(56, 189, 248, 0.12)';
|
||
ctx.lineWidth = 1;
|
||
for (let bx = 0; bx < w; bx += 30) {
|
||
ctx.beginPath(); ctx.moveTo(bx, 0); ctx.lineTo(bx, h); ctx.stroke();
|
||
}
|
||
for (let by = 0; by < h; by += 30) {
|
||
ctx.beginPath(); ctx.moveTo(0, by); ctx.lineTo(w, by); ctx.stroke();
|
||
}
|
||
ctx.restore();
|
||
}
|
||
|
||
// 2. Multi-Product Top Header Bar
|
||
const headerTop = 24;
|
||
const headerH = aspect === '9:16' ? 140 : 105;
|
||
const isDarkTheme = currentTheme.isNatural && (currentTheme.naturalType === 'warm_cafe' || currentTheme.naturalType === 'velvet_drape');
|
||
|
||
ctx.save();
|
||
if (currentTheme.isNatural) {
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(25, 14, 8, 0.90)' : 'rgba(255, 255, 255, 0.92)';
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.40)' : 'rgba(160, 125, 84, 0.40)';
|
||
} else {
|
||
ctx.fillStyle = 'rgba(15, 23, 42, 0.82)';
|
||
ctx.strokeStyle = currentTheme.goldRim + '77';
|
||
}
|
||
ctx.lineWidth = 1.8;
|
||
roundRect(ctx, 35, headerTop, w - 70, headerH, 16);
|
||
ctx.fill(); ctx.stroke();
|
||
|
||
// Top Store Pill
|
||
const brandTitle = (brandInfo.headerTitle || brandInfo.id || 'OFFICIAL STORE').replace(/[^\w\s\u0980-\u09FF]/gi, '').trim();
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? '#FDE68A' : currentTheme.accentColor) : currentTheme.goldRim;
|
||
ctx.font = 'bold 12px Consolas, monospace';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(`◈ ${brandTitle.toUpperCase()} • MULTI-PRODUCT GRID COLLECTION ◈`, w / 2, headerTop + 28);
|
||
|
||
// Main Headline
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? '#FFFFFF' : '#181109') : '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '36px' : '30px') + ' Playfair Display, Hind Siliguri, sans-serif';
|
||
ctx.fillText(mainHeadline || '✨ MEGA COMBO PACK', w / 2, headerTop + (aspect === '9:16' ? 78 : 66));
|
||
|
||
if (aspect === '9:16') {
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? 'rgba(253, 230, 138, 0.8)' : '#785734') : currentTheme.goldAccent;
|
||
ctx.font = '600 15px Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText('VERIFIED AUTHENTIC BUNDLE // DIRECT STORE DELIVERY', w / 2, headerTop + 112);
|
||
}
|
||
ctx.restore();
|
||
|
||
// 3. Grid Content Geometry
|
||
const footerHeight = aspect === '9:16' ? 150 : 130;
|
||
const footerTop = h - footerHeight;
|
||
const contentTop = headerTop + headerH + 20;
|
||
const contentBottom = footerTop - 20;
|
||
const contentHeight = contentBottom - contentTop;
|
||
const contentLeft = 35;
|
||
const contentRight = w - 35;
|
||
const contentWidth = contentRight - contentLeft;
|
||
|
||
// Helper function to draw an individual product card
|
||
const drawProductGridCard = (pIndex, bx, by, bw, bh, isHero = false) => {
|
||
const prod = products[pIndex] || { title: `Product ${pIndex + 1}`, price: '৳ ১,০৬০', badge: '🛡️ 100% Original', img: null };
|
||
|
||
ctx.save();
|
||
// Glass / Natural Card Background
|
||
if (currentTheme.isNatural) {
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(28, 16, 10, 0.88)' : 'rgba(255, 255, 255, 0.90)';
|
||
ctx.strokeStyle = isHero ? (isDarkTheme ? '#F59E0B' : '#8C6D46') : (isDarkTheme ? 'rgba(245, 158, 11, 0.25)' : 'rgba(160, 125, 84, 0.25)');
|
||
} else {
|
||
const cardGrad = ctx.createLinearGradient(bx, by, bx + bw, by + bh);
|
||
cardGrad.addColorStop(0, 'rgba(30, 41, 59, 0.72)');
|
||
cardGrad.addColorStop(1, 'rgba(15, 23, 42, 0.88)');
|
||
ctx.fillStyle = cardGrad;
|
||
ctx.strokeStyle = isHero ? currentTheme.goldRim : 'rgba(255, 255, 255, 0.20)';
|
||
}
|
||
ctx.lineWidth = isHero ? 2.5 : 1.5;
|
||
roundRect(ctx, bx, by, bw, bh, 16);
|
||
ctx.fill(); ctx.stroke();
|
||
|
||
// Corner index badge [ 01 ]
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? '#FDE68A' : '#8C6D46') : (isHero ? currentTheme.goldRim : 'rgba(255, 255, 255, 0.45)');
|
||
ctx.font = 'bold 11px Consolas, monospace';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`[ 0${pIndex + 1} ]`, bx + 12, by + 22);
|
||
|
||
// Mini Trust Badge Pill at top right
|
||
if (prod.badge) {
|
||
ctx.save();
|
||
ctx.font = 'bold 11px Hind Siliguri, sans-serif';
|
||
const bText = prod.badge.length > 20 ? prod.badge.slice(0, 18) + '..' : prod.badge;
|
||
const bWidth = ctx.measureText(bText).width + 16;
|
||
if (currentTheme.isNatural) {
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.25)' : 'rgba(16, 185, 129, 0.15)';
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.45)' : 'rgba(16, 185, 129, 0.35)';
|
||
} else {
|
||
ctx.fillStyle = isHero ? 'rgba(245, 158, 11, 0.25)' : 'rgba(139, 92, 246, 0.25)';
|
||
ctx.strokeStyle = isHero ? currentTheme.goldRim : 'rgba(192, 132, 252, 0.5)';
|
||
}
|
||
ctx.lineWidth = 1;
|
||
roundRect(ctx, bx + bw - bWidth - 10, by + 10, bWidth, 22, 11);
|
||
ctx.fill(); ctx.stroke();
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? '#FDE68A' : '#065F46') : '#FFFFFF';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText(bText, bx + bw - 10 - bWidth / 2, by + 25);
|
||
ctx.restore();
|
||
}
|
||
|
||
// 3D Mini-Podium or 8K Natural Surface inside the card
|
||
const stageY = by + bh * (isHero ? 0.60 : 0.55);
|
||
const stageX = bx + bw / 2;
|
||
const podiumR = isHero ? bw * 0.36 : bw * 0.32;
|
||
|
||
if (currentTheme.isNatural) {
|
||
if (currentTheme.naturalType === 'scandi_wood' || currentTheme.naturalType === 'warm_cafe') {
|
||
renderNaturalWoodGrain(ctx, bx + 2, stageY - 14, bw - 4, bh - (stageY - 14 - by) - 2, currentTheme.naturalType === 'warm_cafe');
|
||
} else {
|
||
renderTravertineTexture(ctx, stageX, stageY, podiumR * 0.95, podiumR * 0.28, 16);
|
||
}
|
||
renderRealisticContactShadow(ctx, stageX, stageY, podiumR * 0.75, podiumR * 0.28, 45);
|
||
} else {
|
||
// Spotlight glow under product
|
||
const spot = ctx.createRadialGradient(stageX, stageY - 20, 10, stageX, stageY - 20, podiumR * 1.5);
|
||
spot.addColorStop(0, currentTheme.haloCenter || 'rgba(255, 255, 255, 0.3)');
|
||
spot.addColorStop(1, 'transparent');
|
||
ctx.fillStyle = spot;
|
||
ctx.beginPath();
|
||
ctx.arc(stageX, stageY - 20, podiumR * 1.5, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
// 3D Podium Disc
|
||
ctx.save();
|
||
ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
|
||
ctx.beginPath();
|
||
ctx.ellipse(stageX, stageY + 12, podiumR, podiumR * 0.28, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
|
||
ctx.fillStyle = currentTheme.pedestalTop;
|
||
ctx.beginPath();
|
||
ctx.ellipse(stageX, stageY, podiumR, podiumR * 0.26, 0, 0, Math.PI * 2);
|
||
ctx.fill();
|
||
ctx.strokeStyle = currentTheme.goldRim;
|
||
ctx.lineWidth = 1.8;
|
||
ctx.stroke();
|
||
ctx.restore();
|
||
}
|
||
|
||
// Draw the Product Image or 3D Fallback
|
||
const pSize = isHero ? Math.min(bw * 0.70, bh * 0.50) : Math.min(bw * 0.65, bh * 0.45);
|
||
const px = stageX - pSize / 2;
|
||
const py = stageY - pSize * 0.88;
|
||
|
||
if (prod.img && prod.img.complete && prod.img.naturalWidth > 0) {
|
||
ctx.save();
|
||
ctx.shadowColor = 'rgba(0, 0, 0, 0.55)';
|
||
ctx.shadowBlur = 18;
|
||
ctx.shadowOffsetY = 10;
|
||
ctx.drawImage(prod.img, px, py, pSize, pSize);
|
||
ctx.restore();
|
||
} else {
|
||
ctx.save();
|
||
ctx.translate(px, py);
|
||
const scaleF = pSize / 400;
|
||
ctx.scale(scaleF, scaleF);
|
||
if (brandInfo.category === 'panjabi') {
|
||
draw3DPanjabiMannequin(ctx, prod.title);
|
||
} else if (brandInfo.category === 'snehalata') {
|
||
draw3DSareeMannequin(ctx, prod.title);
|
||
} else if (brandInfo.category === 'techvolt') {
|
||
draw3DSmartwatch(ctx, prod.title);
|
||
} else if (brandInfo.category === 'organic') {
|
||
draw3DHoneyJar(ctx, prod.title);
|
||
} else if (brandInfo.category === 'sneakerlab') {
|
||
draw3DSneaker(ctx, prod.title);
|
||
} else if (brandInfo.category === 'royale') {
|
||
draw3DPerfumeBottle(ctx, prod.title);
|
||
} else {
|
||
draw3DCosmeticsSet(ctx, prod.title);
|
||
}
|
||
ctx.restore();
|
||
}
|
||
|
||
// Product Title & Price Card at Bottom of Card
|
||
const infoH = isHero ? 68 : 58;
|
||
const infoY = by + bh - infoH - 10;
|
||
if (currentTheme.isNatural) {
|
||
ctx.fillStyle = isDarkTheme ? 'rgba(20, 10, 5, 0.94)' : 'rgba(255, 255, 255, 0.95)';
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.35)' : 'rgba(160, 125, 84, 0.25)';
|
||
} else {
|
||
ctx.fillStyle = 'rgba(15, 23, 42, 0.92)';
|
||
ctx.strokeStyle = 'rgba(255, 255, 255, 0.12)';
|
||
}
|
||
ctx.lineWidth = 1;
|
||
roundRect(ctx, bx + 10, infoY, bw - 20, infoH, 10);
|
||
ctx.fill(); ctx.stroke();
|
||
|
||
// Product Title
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? '#FFFFFF' : '#1E140A') : '#F8FAFC';
|
||
ctx.font = 'bold ' + (isHero ? '15px' : '13px') + ' Hind Siliguri, Playfair Display, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
const displayTitle = prod.title.length > 28 ? prod.title.slice(0, 26) + '..' : prod.title;
|
||
ctx.fillText(displayTitle, stageX, infoY + (isHero ? 24 : 20));
|
||
|
||
// Price Pill
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? '#FDE68A' : '#047857') : currentTheme.goldRim;
|
||
ctx.font = '900 ' + (isHero ? '17px' : '14.5px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(prod.price || '৳ ১,০৬০', stageX, infoY + (isHero ? 50 : 44));
|
||
|
||
ctx.restore();
|
||
};
|
||
|
||
// 4. Render Grid Geometry based on layout
|
||
const gap = 14;
|
||
|
||
if (gridLayout === '2x2_quad') {
|
||
const cardW = (contentWidth - gap) / 2;
|
||
const cardH = (contentHeight - gap) / 2;
|
||
|
||
drawProductGridCard(0, contentLeft, contentTop, cardW, cardH, false);
|
||
drawProductGridCard(1, contentLeft + cardW + gap, contentTop, cardW, cardH, false);
|
||
drawProductGridCard(2, contentLeft, contentTop + cardH + gap, cardW, cardH, false);
|
||
drawProductGridCard(3, contentLeft + cardW + gap, contentTop + cardH + gap, cardW, cardH, false);
|
||
|
||
} else if (gridLayout === '1_hero_3_bento') {
|
||
const heroW = contentWidth * 0.54;
|
||
const rightW = contentWidth - heroW - gap;
|
||
const itemH = (contentHeight - gap * 2) / 3;
|
||
|
||
drawProductGridCard(0, contentLeft, contentTop, heroW, contentHeight, true);
|
||
|
||
for (let i = 1; i <= 3; i++) {
|
||
const cy = contentTop + (i - 1) * (itemH + gap);
|
||
drawProductGridCard(i, contentLeft + heroW + gap, cy, rightW, itemH, false);
|
||
}
|
||
|
||
} else if (gridLayout === '1_hero_2_trio') {
|
||
if (aspect === '9:16') {
|
||
const heroH = contentHeight * 0.52;
|
||
const subH = contentHeight - heroH - gap;
|
||
const subW = (contentWidth - gap) / 2;
|
||
|
||
drawProductGridCard(0, contentLeft, contentTop, contentWidth, heroH, true);
|
||
drawProductGridCard(1, contentLeft, contentTop + heroH + gap, subW, subH, false);
|
||
drawProductGridCard(2, contentLeft + subW + gap, contentTop + heroH + gap, subW, subH, false);
|
||
} else {
|
||
const heroW = contentWidth * 0.54;
|
||
const rightW = contentWidth - heroW - gap;
|
||
const subH = (contentHeight - gap) / 2;
|
||
|
||
drawProductGridCard(0, contentLeft, contentTop, heroW, contentHeight, true);
|
||
drawProductGridCard(1, contentLeft + heroW + gap, contentTop, rightW, subH, false);
|
||
drawProductGridCard(2, contentLeft + heroW + gap, contentTop + subH + gap, rightW, subH, false);
|
||
}
|
||
|
||
} else if (gridLayout === '3_panel_strip') {
|
||
const colW = (contentWidth - gap * 2) / 3;
|
||
for (let i = 0; i < 3; i++) {
|
||
drawProductGridCard(i, contentLeft + i * (colW + gap), contentTop, colW, contentHeight, i === 0);
|
||
}
|
||
}
|
||
|
||
// 5. Unified Footer with WhatsApp & QR Code
|
||
ctx.save();
|
||
if (currentTheme.isNatural) {
|
||
const footGrad = ctx.createLinearGradient(0, footerTop, 0, h);
|
||
if (isDarkTheme) {
|
||
footGrad.addColorStop(0, 'rgba(15, 8, 4, 0.94)');
|
||
footGrad.addColorStop(1, 'rgba(8, 4, 2, 0.98)');
|
||
} else {
|
||
footGrad.addColorStop(0, 'rgba(255, 255, 255, 0.88)');
|
||
footGrad.addColorStop(1, 'rgba(247, 243, 235, 0.96)');
|
||
}
|
||
ctx.fillStyle = footGrad;
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
|
||
ctx.strokeStyle = isDarkTheme ? 'rgba(245, 158, 11, 0.50)' : 'rgba(160, 125, 84, 0.40)';
|
||
ctx.lineWidth = 1.2;
|
||
ctx.beginPath(); ctx.moveTo(0, footerTop); ctx.lineTo(w, footerTop); ctx.stroke();
|
||
|
||
ctx.fillStyle = isDarkTheme ? '#10B981' : '#047857';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '28px' : '24px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`💬 WhatsApp Order: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
|
||
ctx.fillStyle = isDarkTheme ? '#94A3B8' : '#64748B';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '18px' : '15px') + ' Plus Jakarta Sans, sans-serif';
|
||
ctx.fillText(`🌐 ${brandInfo.footerSite} • 📞 ${brandInfo.footerHotline} • 🚚 Cash on Delivery BD`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
} else {
|
||
const footGrad = ctx.createLinearGradient(0, footerTop, w, footerTop);
|
||
footGrad.addColorStop(0, '#10B981'); footGrad.addColorStop(1, '#059669');
|
||
ctx.fillStyle = footGrad;
|
||
ctx.fillRect(0, footerTop, w, footerHeight);
|
||
|
||
// Divider Line
|
||
ctx.strokeStyle = currentTheme.goldRim; ctx.lineWidth = 3;
|
||
ctx.beginPath(); ctx.moveTo(0, footerTop); ctx.lineTo(w, footerTop); ctx.stroke();
|
||
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.font = 'bold ' + (aspect === '9:16' ? '32px' : '28px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.textAlign = 'left';
|
||
ctx.fillText(`💬 WhatsApp Order: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 48 : 44));
|
||
|
||
ctx.fillStyle = '#DCFCE7';
|
||
ctx.font = '600 ' + (aspect === '9:16' ? '20px' : '17px') + ' Plus Jakarta Sans, Hind Siliguri, sans-serif';
|
||
ctx.fillText(`🌐 Website: ${brandInfo.footerSite} • 📞 Hotline: ${brandInfo.footerHotline}`, 40, footerTop + (aspect === '9:16' ? 86 : 78));
|
||
}
|
||
|
||
if (aspect === '9:16') {
|
||
ctx.fillStyle = currentTheme.isNatural ? (isDarkTheme ? '#FDE68A' : '#785734') : '#FEF08A';
|
||
ctx.font = 'bold 14px Consolas, monospace';
|
||
ctx.fillText(`🚚 FAST HOME DELIVERY ALL OVER BANGLADESH // CASH ON DELIVERY`, 40, footerTop + 120);
|
||
}
|
||
|
||
// Authentic 3-Finder QR Code on Footer
|
||
const qrS = aspect === '9:16' ? 86 : 80;
|
||
const qrX = w - qrS - 40;
|
||
const qrY = footerTop + (footerHeight - qrS) / 2;
|
||
drawQRCodeTile(ctx, qrX, qrY, qrS);
|
||
|
||
// Outer Border Rim
|
||
ctx.strokeStyle = currentTheme.isNatural
|
||
? (isDarkTheme ? 'rgba(245, 158, 11, 0.45)' : 'rgba(160, 125, 84, 0.35)')
|
||
: (currentTheme.goldRim + '99');
|
||
ctx.lineWidth = currentTheme.isNatural ? 3 : 6;
|
||
ctx.strokeRect(2, 2, w - 4, h - 4);
|
||
ctx.restore();
|
||
}
|
||
|
||
window.renderMultiProductGridPoster = renderMultiProductGridPoster;
|
||
|
||
// =========================================================================
|
||
// 8K Natural Lifestyle & 3D CGI Commercial Photography Catalog
|
||
// =========================================================================
|
||
const GT_CGI_PROMPT_CATALOG = [
|
||
// --- 🌿 8K Natural & Lifestyle Commercial Photography (NEW) ---
|
||
{
|
||
id: 'nat_scandi_medicube',
|
||
title: '8K Scandinavian Oak Lifestyle • Medicube Collagen Jelly Cream',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,০৬০',
|
||
recommendedTheme: 'natural_scandi_wood',
|
||
aspect: '1:1',
|
||
summaryBn: 'আসল স্ক্যান্ডিনেভিয়ান ওক কাঠ ও সকালের জানালার মিষ্টি রোদে ৮কে কমার্শিয়াল লাইফস্টাইল শট।',
|
||
prompt: `8k hyper-realistic commercial lifestyle product photography of Medicube Collagen Jelly Cream jar resting naturally on a solid Scandinavian honey oak wooden tabletop with organic wood grain and soft linen cloth draped at the corner. Beautiful 45-degree angle morning window sunlight casting soft diffused rays and realistic ambient occlusion contact shadows. Ultra-clean commercial catalog editorial, f/2.8 depth of field, Hasselblad H6D-100c medium format camera, natural color temperature, zero CGI artifacts, photorealistic masterwork.`
|
||
},
|
||
{
|
||
id: 'nat_botanical_anua',
|
||
title: '8K Botanical Morning & Dew • Anua Heartleaf 77% Toner',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,৪৮০',
|
||
recommendedTheme: 'natural_botanical_sun',
|
||
aspect: '1:1',
|
||
summaryBn: 'প্রাকৃতিক সকালের রোদ, তাজা সবুজ পাতা ও শিশিরবিন্দু সহ ৮কে অর্গানিক স্টুডিও শট।',
|
||
prompt: `8k authentic commercial product photography of Anua Heartleaf 77% Soothing Toner bottle standing on a smooth limestone slab surrounded by fresh green botanical monstera and heartleaf plant shadows dancing on a soft sage wall. Natural morning sunbeams streaming through window blinds, glistening crystal dew droplets on the stone surface, natural glass refraction, realistic soft ground contact shadow, Sony A7R V 90mm macro lens, clean organic skincare aesthetic.`
|
||
},
|
||
{
|
||
id: 'nat_kbeauty_travertine',
|
||
title: '8K K-Beauty Travertine Vanity • COSRX Snail 96 Mucin',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,৩৫০',
|
||
recommendedTheme: 'natural_kbeauty_glow',
|
||
aspect: '1:1',
|
||
summaryBn: 'সানলিট ট্রাভার্টিন মার্বেল পাথর ও ওয়াটার কস্টিকস সহ কোরিয়ান গ্লাস স্কিন এডিটোরিয়াল।',
|
||
prompt: `8k editorial aesthetic commercial photography of COSRX Snail 96 Mucin pump bottle on a beige natural porous travertine stone slab in a bright, sun-drenched minimalist bathroom vanity. Delicate water ripple caustics, soft morning daylight, razor-sharp label typography, authentic soft drop shadow, luxury Korean skincare campaign lookbook, Phase One IQ4 150MP, 85mm lens.`
|
||
},
|
||
{
|
||
id: 'nat_warm_cafe_honey',
|
||
title: '8K Artisan Dark Walnut & Café • Sundarban Raw Khalsi Honey',
|
||
category: 'organic',
|
||
storeName: 'Pranon Organic',
|
||
price: '৳ ১,২৫০',
|
||
recommendedTheme: 'natural_warm_cafe',
|
||
aspect: '1:1',
|
||
summaryBn: 'ডার্ক আমেরিকান ওয়ালনাট কাঠের টেবিল ও কোজি ক্যাফে অ্যাম্বিয়েন্সে ১০০% খাঁটি মধুর শট।',
|
||
prompt: `8k authentic commercial still life photography of Sundarban Pure Raw Khalsi Honey 1kg glass jar on a rustic dark American walnut wood tabletop with rich natural wood grain. Warm golden 3000K ambient café lighting, natural honeycomb slice and wooden honey dipper beside the jar, amber honey glow with internal light refraction, soft realistic contact shadows, Leica SL2 50mm f/1.4 Summilux.`
|
||
},
|
||
|
||
// --- Glamour's Touch K-Beauty & Skincare ---
|
||
{
|
||
id: 'gt_medicube_jelly',
|
||
title: 'Medicube Collagen Jelly Cream + Hydra-Glow Serum',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,০৬০',
|
||
recommendedTheme: 'obsidian_gold',
|
||
aspect: '1:1',
|
||
summaryBn: 'কোরিয়ান হাইড্রা-গ্লো কোলাজেন জেলি ক্রিম ও সিরাম, কাচের মতো উজ্জ্বল গ্লাস স্কিনের জন্য।',
|
||
prompt: `Hollywood commercial product photography of Medicube Collagen Jelly Cream jar and Hydra-Glow Serum bottle standing elegantly on an obsidian slate stone podium with 24K brushed gold trims. Dramatic top-down softbox lighting casting razor-sharp glass reflections, hyper-detailed cosmetic gel texture with micro-moisture droplets, volumetric golden light beams, floating luminous bokeh particles, ultra-photorealistic, 8k resolution, raytraced caustics, Octane render, Hasselblad H6D-100c medium format lens f/4.`
|
||
},
|
||
{
|
||
id: 'gt_anua_heartleaf',
|
||
title: 'Anua Heartleaf 77% Soothing Toner + Calming Ampoule',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,৪৮০',
|
||
recommendedTheme: 'botanical_eco',
|
||
aspect: '1:1',
|
||
summaryBn: '৭৭% হার্টলিফ এক্সট্র্যাক্ট সমৃদ্ধ প্রশান্তিদায়ক কোরিয়ান টোনার ও অ্যাম্পুল।',
|
||
prompt: `Cinematic commercial photography of Anua Heartleaf 77% Soothing Toner transparent bottle and glass dropper ampoule placed on a wet mossy zen river stone podium. Fresh green heartleaf foliage and glistening morning water droplets floating in ambient sunlight, crisp raytraced glass refraction, emerald green and crystal clear liquid physics, softbox diffused rim lighting, 8k studio product render, Unreal Engine 5 aesthetic.`
|
||
},
|
||
{
|
||
id: 'gt_cosrx_snail',
|
||
title: 'COSRX Advanced Snail 96 Mucin Power Essence + Snail 92 Cream',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,৩৫০',
|
||
recommendedTheme: 'nordic_minimal',
|
||
aspect: '1:1',
|
||
summaryBn: '৯৬% স্নেল মিউসিন এসেন্স ও অল-ইন-ওয়ান ক্রিম, ত্বকের রিকভারি ও রিপেয়ারের জন্য।',
|
||
prompt: `Architectural minimalist luxury commercial photography of COSRX Advanced Snail 96 Mucin pump bottle and Snail 92 Cream tub resting on dual-tier brushed titanium and matte concrete pedestals. Minimalist Nordic studio lightbox setup, viscous iridescent mucin droplets suspended mid-air with translucent specular highlights, f/2.8 macro sharpness, clean studio aesthetic, 8k raytraced CGI render.`
|
||
},
|
||
{
|
||
id: 'gt_boj_sun',
|
||
title: 'Beauty of Joseon Relief Sun: Rice + Probiotics SPF50+',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,১৫০',
|
||
recommendedTheme: 'sunset_amber',
|
||
aspect: '1:1',
|
||
summaryBn: 'চাল ও প্রোবায়োটিক সমৃদ্ধ কোরিয়ান বেস্টসেলার সানস্ক্রিন, কোনো সাদা দাগ ফেলে না।',
|
||
prompt: `Golden hour sunset commercial advertising render of Beauty of Joseon Relief Sun Rice + Probiotics sleek white cosmetic tube perched on a warm terracotta and amber glass pedestal. Golden sunflare rays casting soft warm rim light across the matte tube surface, organic rice stalks gracefully framing the background, hyper-detailed creamy lotion texture swatch, 8k photorealistic commercial.`
|
||
},
|
||
{
|
||
id: 'gt_axisy_glow',
|
||
title: 'AXIS-Y Dark Spot Correcting Glow Serum (5% Niacinamide)',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,১৯০',
|
||
recommendedTheme: 'rose_quartz',
|
||
aspect: '1:1',
|
||
summaryBn: '৫% নায়াসিনামাইড সিরাম, ত্বকের পুরোনো দাগ দূর করে প্রাকৃতিক গ্লো ফিরিয়ে আনে।',
|
||
prompt: `Ultra-luxury high fashion beauty commercial render of AXIS-Y Dark Spot Correcting Glow Serum bottle floating above a sculptured rose quartz crystal podium draped in smooth blush pink silk waves. Chromatic prism refractions, dewy water droplets clinging to the glass, soft studio caustics, 8k resolution, Phase One XF IQ4 medium format camera capture.`
|
||
},
|
||
{
|
||
id: 'gt_roundlab_birch',
|
||
title: 'Round Lab Birch Juice Moisturizing Sunscreen SPF50+',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,৩২০',
|
||
recommendedTheme: 'frost_titanium',
|
||
aspect: '1:1',
|
||
summaryBn: 'ইনজে কাঠের রস সমৃদ্ধ আল্ট্রা-হাইড্রেটিং হাইয়ালুরোনিক সানস্ক্রিন।',
|
||
prompt: `Commercial arctic CGI render of Round Lab Birch Juice Moisturizing Sunscreen tube standing proudly on a carved glacial ice block with brushed platinum trim. Cold crisp volumetric blue lighting, microscopic frost crystals and clear melted water condensation beads, crisp reflections, 8k Octane render, award-winning studio lighting.`
|
||
},
|
||
{
|
||
id: 'gt_skin1004_centella',
|
||
title: 'SKIN1004 Madagascar Centella Asiatica 100% Ampoule',
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,৪৫০',
|
||
recommendedTheme: 'botanical_eco',
|
||
aspect: '1:1',
|
||
summaryBn: '১০০% খাঁটি মাদাগাস্কার সেন্টেলা অ্যাম্পুল, ব্রণ ও লালচে ভাব দ্রুত শান্ত করে।',
|
||
prompt: `Luxury commercial product render of SKIN1004 Madagascar Centella golden glass dropper ampoule illuminated on a dark natural slate pedestal surrounded by fresh Centella Asiatica leaves. Pristine amber liquid glow with internal optical dispersion, studio softbox spotlight, 8k hyper-realistic commercial render.`
|
||
},
|
||
{
|
||
id: 'gt_saffron_night_gold',
|
||
title: "Glamour's Touch 24K Pure Gold Saffron Night Brightening Gel",
|
||
category: 'glamourstouch',
|
||
storeName: "Glamour's Touch",
|
||
price: '৳ ১,৬৫০',
|
||
recommendedTheme: 'obsidian_gold',
|
||
aspect: '1:1',
|
||
summaryBn: '২৪ ক্যারেট খাঁটি গোল্ড ফ্লেক্স ও জাফরান যুক্ত ব্রাইটনিং নাইট জেল।',
|
||
prompt: `Bespoke ultra-luxury commercial render of Glamour's Touch 24K Gold Saffron Night Gel in a heavy multifaceted crystal jar with a polished 24K gold lid. Real 24K gold flakes swirling in crystal clear gel, sitting on a black obsidian mirror podium, dramatic overhead spotlight, gold stardust bokeh, 8k cinematic luxury commercial.`
|
||
},
|
||
|
||
// --- Aura Heritage & Royal Panjabi ---
|
||
{
|
||
id: 'panjabi_royal_silk',
|
||
title: 'Aura Royal Platinum Silk Jacquard Panjabi',
|
||
category: 'panjabi',
|
||
storeName: 'Aura Heritage Panjabi',
|
||
price: '৳ ২,৪৫০',
|
||
recommendedTheme: 'mughal_heritage',
|
||
aspect: '1:1',
|
||
summaryBn: 'হাতে বোনা প্লাটিনাম সিল্ক ও জরি কলারের প্রিমিয়াম রয়েল ডিজাইনার পাঞ্জাবি।',
|
||
prompt: `Aristocratic royal commercial photography of Aura Royal Platinum Silk Jacquard Panjabi displayed on a matte black and gold-accented bespoke torso mannequin. Background featuring illuminated Mughal palace archways with intricate gold filigree, micro-texture jacquard weave visible down to the thread count, 24K zari embroidery on mandarin collar and cuffs, dramatic directional cinematic lighting, 8k resolution, Phase One studio quality.`
|
||
},
|
||
{
|
||
id: 'panjabi_kabli_suit',
|
||
title: 'Aura Imperial Navy Blue Two-Piece Kabli Suit',
|
||
category: 'panjabi',
|
||
storeName: 'Aura Heritage Panjabi',
|
||
price: '৳ ২,৮৫০',
|
||
recommendedTheme: 'vip_blackcard',
|
||
aspect: '1:1',
|
||
summaryBn: 'ইম্পেরিয়াল নেভি ব্লু টু-পিস কাবলি সেট, মেটালিক স্ন্যাপ বাটন ও নিখুঁত ফিটিং।',
|
||
prompt: `High-end luxury ethnic fashion render of Aura Imperial Navy Blue Kabli Suit on an executive tailor mannequin. Sleek carbon fiber stage with platinum border inlays, metallic gunmetal snap buttons gleaming under studio spotlights, fine cotton-blend fabric drape with realistic creases, 8k Hasselblad studio render.`
|
||
},
|
||
{
|
||
id: 'panjabi_festive_maroon',
|
||
title: 'Aura Heritage Hand-Embroidered Velvet Maroon Panjabi',
|
||
category: 'panjabi',
|
||
storeName: 'Aura Heritage Panjabi',
|
||
price: '৳ ৩,২০০',
|
||
recommendedTheme: 'velvet_burgundy',
|
||
aspect: '1:1',
|
||
summaryBn: 'উৎসবের স্পেশাল রয়্যাল মেরুন ভেলভেট পাঞ্জাবি, রাজকীয় এমব্রয়ডারি সহ।',
|
||
prompt: `Grand royal festive commercial shoot of Aura Heritage Maroon Velvet Panjabi on a luxury bespoke mannequin standing on a dual-tiered burgundy velvet stage with 24K gold filigree base. Rich plush velvet fabric sheen catching volumetric golden beams, heavy hand-stitched gold threadwork on chest and collar, 8k cinematic studio photography.`
|
||
},
|
||
|
||
// --- Snehalata Saree & Luxury Women Fashion ---
|
||
{
|
||
id: 'saree_muslin_jamdani',
|
||
title: 'Snehalata Pure Handwoven Muslin Jamdani Saree',
|
||
category: 'snehalata',
|
||
storeName: 'Snehalata Aura Fashion',
|
||
price: '৳ ৪,৫০০',
|
||
recommendedTheme: 'editorial_vogue',
|
||
aspect: '1:1',
|
||
summaryBn: '৩০০ কাউন্টের খাঁটি হাতে বোনা মসলিন জামদানি শাড়ি, ঐতিহ্য ও আভিজাত্য।',
|
||
prompt: `Haute couture Vogue editorial commercial photography of Snehalata Handwoven Muslin Jamdani Saree gracefully draped over a minimalist sculpture mannequin. Translucent gossamer muslin fabric floating weightlessly in mid-air, intricate gold and silver floral zari motifs, editorial serif lighting, studio softbox rim highlights, 8k medium-format commercial aesthetic.`
|
||
},
|
||
{
|
||
id: 'saree_royal_katan',
|
||
title: 'Snehalata Royal Mirpur Katan Silk Bridal Saree with Pure Zari',
|
||
category: 'snehalata',
|
||
storeName: 'Snehalata Aura Fashion',
|
||
price: '৳ ৫,৮০০',
|
||
recommendedTheme: 'mughal_heritage',
|
||
aspect: '1:1',
|
||
summaryBn: 'মিরপুর কাতান সিল্ক ব্রাইডাল শাড়ি, খাঁটি জারদৌসি কাজের আঁচল।',
|
||
prompt: `Royal bridal commercial masterwork of Snehalata Royal Katan Silk Saree on an imperial mannequin inside an ornate Mughal palace pavilion with golden arched colonnades. Rich crimson red silk interwoven with pure gold zari pallu catching warm chandeliers and lantern light, extreme micro-weave fabric detail, 8k Octane render.`
|
||
},
|
||
|
||
// --- TechVolt Smart Gadgets & Electronics ---
|
||
{
|
||
id: 'techvolt_smartwatch',
|
||
title: 'TechVolt T900 Ultra 2 AMOLED Series 9 Smartwatch',
|
||
category: 'techvolt',
|
||
storeName: 'TechVolt Gadgets',
|
||
price: '৳ ২,৩৫০',
|
||
recommendedTheme: 'cyber_neon',
|
||
aspect: '1:1',
|
||
summaryBn: '২.২ ইঞ্চি অ্যামোলেড ডিসপ্লে, টাইটানিয়াম কেসিং ও ৭ দিনের ব্যাটারি লাইফ।',
|
||
prompt: `Futuristic cyberpunk 3D commercial render of TechVolt T900 Ultra 2 Smartwatch levitating at a 45-degree angle above an illuminated cyan and magenta hexagonal digital matrix grid. Titanium CNC-machined chassis with orange crown button, vibrant 2.2-inch AMOLED glowing screen showing tricolor fitness rings, neon reflections, raytraced glass glare, 8k resolution.`
|
||
},
|
||
{
|
||
id: 'techvolt_earbuds',
|
||
title: 'TechVolt SonicPulse ANC Pro Wireless Studio Earbuds',
|
||
category: 'techvolt',
|
||
storeName: 'TechVolt Gadgets',
|
||
price: '৳ ১,৯৫০',
|
||
recommendedTheme: 'tokyo_synthwave',
|
||
aspect: '1:1',
|
||
summaryBn: 'অ্যাক্টিভ নয়েজ ক্যান্সেলেশন (ANC) ও স্টুডিও কোয়ালিটি ডিপ বেজ সাউন্ড।',
|
||
prompt: `Neon-lit studio commercial render of TechVolt SonicPulse ANC Pro Earbuds floating out of an open matte black and cyan charging case. Acoustic soundwave rings radiating in neon violet, brushed aluminum accents, raytraced reflection on glossy mirror stage, 8k tech commercial photography.`
|
||
},
|
||
|
||
// --- Pranon 100% Organic & Raw Foods ---
|
||
{
|
||
id: 'organic_sundarban_honey',
|
||
title: 'Pranon 100% Pure Raw Sundarban Wild Flower Honey (1kg)',
|
||
category: 'organic',
|
||
storeName: 'Pranon Organic',
|
||
price: '৳ ১,২০০',
|
||
recommendedTheme: 'sunset_amber',
|
||
aspect: '1:1',
|
||
summaryBn: 'সুন্দরবনের প্রাকৃতিক চাকের ১০০% নির্ভেজাল ও ল্যাব-টেস্টেড কাঁচা মধু।',
|
||
prompt: `Rustic organic commercial render of Pranon Pure Raw Sundarban Honey in a heavy hexagonal faceted glass jar with a carved birch wood lid and jute rope tie. Golden amber honey liquid glowing under warm golden hour sunlight, viscous honey drip swirling down the side, rustic wooden table with wild honeycomb pieces, 8k photorealistic commercial.`
|
||
},
|
||
{
|
||
id: 'organic_mustard_oil',
|
||
title: 'Pranon Cold-Pressed Traditional Wood-Ghani Pure Mustard Oil',
|
||
category: 'organic',
|
||
storeName: 'Pranon Organic',
|
||
price: '৳ ৪৫০',
|
||
recommendedTheme: 'botanical_eco',
|
||
aspect: '1:1',
|
||
summaryBn: 'কাঠের ঘানিতে ভাঙানো ১০০% খাঁটি ঝাঁঝালো সরিষার তেল।',
|
||
prompt: `Artisanal commercial render of Pranon Wood-Ghani Mustard Oil in a traditional amber glass bottle resting on a weathered rustic oak wood podium surrounded by fresh yellow mustard flowers. Golden oil clarity, natural softbox sunlight with lens flare, 8k food photography.`
|
||
},
|
||
|
||
// --- SneakerLab BD Footwear ---
|
||
{
|
||
id: 'sneakerlab_retro_high',
|
||
title: 'SneakerLab StreetFire Retro High OG Leather Kicks',
|
||
category: 'sneakerlab',
|
||
storeName: 'SneakerLab BD',
|
||
price: '৳ ২,৮৫০',
|
||
recommendedTheme: 'brutalist_street',
|
||
aspect: '1:1',
|
||
summaryBn: 'প্রিমিয়াম লেদার ও মেমোরি ফোম কুশন সহ আরবান স্ট্রিটওয়্যার স্নিকার।',
|
||
prompt: `Raw urban brutalist streetwear commercial render of SneakerLab Retro High OG Sneaker floating mid-air above a cracked concrete pedestal with hazard-yellow diagonal stripes. Dramatic industrial studio spotlight, full-grain leather creasing detail, translucent air bubble sole cushion, high-contrast dynamic lighting, 8k commercial photography.`
|
||
},
|
||
{
|
||
id: 'sneakerlab_cow_loafer',
|
||
title: 'SneakerLab Handcrafted Pure Cowhide Leather Loafer',
|
||
category: 'sneakerlab',
|
||
storeName: 'SneakerLab BD',
|
||
price: '৳ ৩,৪৫০',
|
||
recommendedTheme: 'vip_blackcard',
|
||
aspect: '1:1',
|
||
summaryBn: 'হাতে তৈরি ১০০% জেনুইন কাউহাইড লেদার লোফার, অফিস ও পার্টির জন্য।',
|
||
prompt: `Ultra-luxury bespoke menswear commercial render of SneakerLab Pure Leather Loafer positioned on a matte black titanium stage with gold edge trim. High-shine burnished patina calfskin leather, hand-stitched welt precision, rich leather texture, 8k Hasselblad studio render.`
|
||
},
|
||
|
||
// --- Aura Royale Luxury Fragrance & Timepieces ---
|
||
{
|
||
id: 'royale_oud_perfume',
|
||
title: 'Aura Royale 24-Hour Imperial Oud & Saffron Extrait de Parfum',
|
||
category: 'royale',
|
||
storeName: 'Aura Royale Luxury',
|
||
price: '৳ ৩,৮৫০',
|
||
recommendedTheme: 'midnight_sapphire',
|
||
aspect: '1:1',
|
||
summaryBn: '২৪ ঘণ্টারও বেশি লং-লাস্টিং ইম্পেরিয়াল উড ও জাফরান লাক্সারি পারফিউম।',
|
||
prompt: `Moody ultra-luxury perfume commercial photography of Aura Royale Imperial Oud bottle carved from deep sapphire crystal with a 24K heavy gold cap. Fine micro-mist atomizer spray captured in a volumetric sapphire light beam, polished obsidian mirror floor with crystal reflections, 8k luxury cosmetic render.`
|
||
},
|
||
{
|
||
id: 'royale_skeleton_watch',
|
||
title: 'Aura Royale Chronograph Skeleton Automatic Diamond Watch',
|
||
category: 'royale',
|
||
storeName: 'Aura Royale Luxury',
|
||
price: '৳ ৯,৫০০',
|
||
recommendedTheme: 'obsidian_gold',
|
||
aspect: '1:1',
|
||
summaryBn: 'অটোমেটিক মেকানিক্যাল মুভমেন্ট, স্যাফায়ার ক্রিস্টাল গ্লাস ও রয়্যাল ফিনিশ।',
|
||
prompt: `Masterpiece horology commercial advertising render of Aura Royale Skeleton Automatic Watch hovering above a dual-tier gold and carbon fiber pedestal. Intricate moving mechanical tourbillon gears visible through sapphire crystal glass, 24K gold bezel inlay, macro studio lighting, 8k Octane render.`
|
||
}
|
||
];
|
||
|
||
function initCgiLibrary() {
|
||
const container = document.getElementById('cgiPromptCardsContainer');
|
||
const searchInput = document.getElementById('cgiSearchInput');
|
||
const filterChips = document.querySelectorAll('#cgiFilterChips .filter-chip');
|
||
|
||
if (!container) return;
|
||
|
||
let activeCgiCategory = 'all';
|
||
let searchQuery = '';
|
||
|
||
function renderCgiCards() {
|
||
const dict = I18N_DICTIONARY[window.currentLang] || I18N_DICTIONARY.bn;
|
||
let filtered = GT_CGI_PROMPT_CATALOG;
|
||
|
||
if (activeCgiCategory !== 'all') {
|
||
filtered = filtered.filter(item => item.category === activeCgiCategory);
|
||
}
|
||
|
||
if (searchQuery) {
|
||
const q = searchQuery.toLowerCase();
|
||
filtered = filtered.filter(item =>
|
||
item.title.toLowerCase().includes(q) ||
|
||
item.storeName.toLowerCase().includes(q) ||
|
||
item.prompt.toLowerCase().includes(q) ||
|
||
item.summaryBn.toLowerCase().includes(q)
|
||
);
|
||
}
|
||
|
||
if (filtered.length === 0) {
|
||
container.innerHTML = `
|
||
<div class="empty-state" style="grid-column: 1 / -1;">
|
||
<span class="icon-empty">🔍</span>
|
||
<p>${dict.cgi_empty || 'কোনো প্রম্পট পাওয়া যায়নি। অন্য ক্যাটাগরি বা কিওয়ার্ড দিয়ে সার্চ করুন।'}</p>
|
||
</div>`;
|
||
return;
|
||
}
|
||
|
||
container.innerHTML = filtered.map(item => `
|
||
<div class="cgi-card">
|
||
<div class="cgi-card-header">
|
||
<span class="cgi-store-badge">${item.storeName}</span>
|
||
<span class="cgi-theme-badge">🎨 Theme: ${THEMES[item.recommendedTheme]?.name || item.recommendedTheme}</span>
|
||
</div>
|
||
<h3 class="cgi-title">${item.title}</h3>
|
||
<p class="cgi-summary">${item.summaryBn}</p>
|
||
|
||
<div class="cgi-prompt-box">
|
||
<code>${item.prompt}</code>
|
||
</div>
|
||
|
||
<div class="cgi-card-footer">
|
||
<span class="cgi-price-tag">${item.price} • ${item.aspect}</span>
|
||
<div class="cgi-btn-group">
|
||
<button class="btn-cgi-copy" onclick="copyCgiPrompt('${item.id}')" title="Copy 8K CGI Prompt">
|
||
${dict.btn_cgi_copy || '📋 প্রম্পট কপি'}
|
||
</button>
|
||
<button class="btn-cgi-use" onclick="loadCgiIntoPosterLab('${item.id}')" title="Open in 3D Poster Lab">
|
||
${dict.btn_cgi_use || '🎨 ৩ডি ল্যাবে ওপেন'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// Filter chips click
|
||
filterChips.forEach(chip => {
|
||
chip.addEventListener('click', () => {
|
||
filterChips.forEach(c => c.classList.remove('active'));
|
||
chip.classList.add('active');
|
||
activeCgiCategory = chip.getAttribute('data-cat');
|
||
renderCgiCards();
|
||
});
|
||
});
|
||
|
||
// Search input
|
||
if (searchInput) {
|
||
searchInput.addEventListener('input', (e) => {
|
||
searchQuery = e.target.value.trim();
|
||
renderCgiCards();
|
||
});
|
||
}
|
||
|
||
renderCgiCards();
|
||
}
|
||
|
||
// Helper: Copy Prompt to Clipboard
|
||
window.copyCgiPrompt = function(promptId) {
|
||
const item = GT_CGI_PROMPT_CATALOG.find(p => p.id === promptId);
|
||
if (!item) return;
|
||
|
||
navigator.clipboard.writeText(item.prompt).then(() => {
|
||
alert(`✅ 8K Hollywood CGI প্রম্পট কপি হয়েছে!\n\nপ্রোডাক্ট: ${item.title}`);
|
||
}).catch(() => {
|
||
const ta = document.createElement('textarea');
|
||
ta.value = item.prompt;
|
||
document.body.appendChild(ta);
|
||
ta.select();
|
||
document.execCommand('copy');
|
||
document.body.removeChild(ta);
|
||
alert(`✅ 8K Hollywood CGI প্রম্পট কপি হয়েছে!\n\nপ্রোডাক্ট: ${item.title}`);
|
||
});
|
||
};
|
||
|
||
// Helper: Load Prompt & Theme directly into 3D Poster Lab
|
||
window.loadCgiIntoPosterLab = function(promptId) {
|
||
const item = GT_CGI_PROMPT_CATALOG.find(p => p.id === promptId);
|
||
if (!item) return;
|
||
|
||
const productInput = document.getElementById('productInput');
|
||
const productPrice = document.getElementById('productPrice');
|
||
const brandSelect = document.getElementById('brandWatermarkSelect');
|
||
const aspectSelect = document.getElementById('aspectRatioSelect');
|
||
const themeChips = document.querySelectorAll('#themeSelectorGroup .theme-chip');
|
||
|
||
if (productInput) productInput.value = item.title;
|
||
if (productPrice) productPrice.value = item.price;
|
||
if (brandSelect) brandSelect.value = item.category;
|
||
if (aspectSelect) aspectSelect.value = item.aspect;
|
||
|
||
// Set active theme chip
|
||
selectedStageTheme = item.recommendedTheme;
|
||
themeChips.forEach(c => {
|
||
if (c.getAttribute('data-theme') === item.recommendedTheme) {
|
||
c.classList.add('active');
|
||
} else {
|
||
c.classList.remove('active');
|
||
}
|
||
});
|
||
|
||
// Switch to Poster Lab tab
|
||
switchToTab('tabPosterLab');
|
||
|
||
// Trigger Generate Button
|
||
const genBtn = document.getElementById('generatePosterBtn');
|
||
if (genBtn) {
|
||
setTimeout(() => {
|
||
genBtn.click();
|
||
}, 200);
|
||
}
|
||
};
|
||
|
||
async function drawWhatsAppQrOnCanvas(ctx, x, y, size, hotline = '01712-426871') {
|
||
ctx.fillStyle = '#FFFFFF';
|
||
roundRect(ctx, x - 4, y - 4, size + 8, size + 8, 10);
|
||
ctx.fill();
|
||
|
||
const rawPhone = hotline.replace(/\D/g, '');
|
||
const waUrl = `https://wa.me/88${rawPhone.startsWith('88') ? rawPhone.slice(2) : rawPhone.replace(/^0/, '')}`;
|
||
|
||
const qrContainer = document.getElementById('qrcodeHidden');
|
||
if (qrContainer && typeof QRCode !== 'undefined') {
|
||
try {
|
||
qrContainer.innerHTML = '';
|
||
new QRCode(qrContainer, {
|
||
text: waUrl,
|
||
width: size,
|
||
height: size,
|
||
colorDark: '#0B2E13',
|
||
colorLight: '#FFFFFF',
|
||
correctLevel: QRCode.CorrectLevel.M
|
||
});
|
||
|
||
await new Promise(r => setTimeout(r, 60));
|
||
const qrImg = qrContainer.querySelector('img') || qrContainer.querySelector('canvas');
|
||
if (qrImg) {
|
||
ctx.drawImage(qrImg, x, y, size, size);
|
||
return;
|
||
}
|
||
} catch (e) {
|
||
console.warn('QRCode render exception:', e);
|
||
}
|
||
}
|
||
|
||
// Resilient High-Contrast Vector QR Fallback
|
||
ctx.fillStyle = '#0B2E13';
|
||
ctx.fillRect(x + 4, y + 4, size - 8, size - 8);
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.fillRect(x + 10, y + 10, size - 20, size - 20);
|
||
ctx.fillStyle = '#0B2E13';
|
||
ctx.font = 'bold 13px Plus Jakarta Sans, sans-serif';
|
||
ctx.textAlign = 'center';
|
||
ctx.fillText('SCAN', x + size / 2, y + size / 2 - 2);
|
||
ctx.fillText('ORDER', x + size / 2, y + size / 2 + 14);
|
||
}
|
||
|
||
// --- 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';
|
||
|
||
const selectedBrand = document.getElementById('brandWatermarkSelect')?.value || 'glamourstouch';
|
||
const activeBrand = getBrandProfile(selectedBrand);
|
||
const cleanPhone = (activeBrand.footerHotline || '01712-426871').replace(/\D/g, '');
|
||
const dynamicWaLink = `https://wa.me/88${cleanPhone}`;
|
||
|
||
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 {
|
||
const activeContext = storeInfo || `Store: ${activeBrand.headerTitle}, Website: ${activeBrand.footerSite}, Hotline: ${activeBrand.footerHotline}`;
|
||
|
||
if (apiKey) {
|
||
const prompt = `A customer sent this message in e-commerce inbox:
|
||
'${query}'
|
||
Store Info: ${activeContext}
|
||
|
||
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: ${dynamicWaLink} and hotline ${activeBrand.footerHotline})`;
|
||
|
||
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] || `সরাসরি হোয়াটসঅ্যাপে দ্রুত অর্ডার করতে ক্লিক করুন: ${dynamicWaLink}\nহটলাইন: ${activeBrand.footerHotline}`).trim();
|
||
} else {
|
||
reply1.textContent = `আসসালামু আলাইকুম প্রিয় কাস্টমার! 🥰\nআমাদের কাছে ${activeBrand.headerTitle}-এর ১০০% অরিজিনাল অথেনটিক প্রোডাক্ট রয়েছে।\n\n💰 আকর্ষণীয় অফার মূল্য ও সুপারফাস্ট হোম ডেলিভারি সুবিধা!\n🚚 দ্রুত সারা দেশে ক্যাশ অন ডেলিভারি দেওয়া হয়।`;
|
||
reply2.textContent = `অর্ডারটি কনফার্ম করতে অনুগ্রহ করে আপনার:\n১. নাম\n২. সম্পূর্ণ ঠিকানা (জেলা/থানা সহ)\n৩. মোবাইল নম্বর\n\nলিখে পাঠিয়ে দিন। আমরা দ্রুত প্রোডাক্ট পাঠিয়ে দেবো! ধন্যবাদ। 🛍️`;
|
||
reply3.textContent = `সরাসরি হোয়াটসঅ্যাপে ১-ক্লিকে অর্ডার করতে আমাদের ইনবক্স করুন:\n💬 WhatsApp: ${dynamicWaLink}\n📞 হটলাইন: ${activeBrand.footerHotline}\n🌐 ওয়েবসাইট: https://${activeBrand.footerSite}`;
|
||
}
|
||
|
||
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 dict = I18N_DICTIONARY[window.currentLang] || I18N_DICTIONARY.bn;
|
||
const list = JSON.parse(localStorage.getItem('opal_history') || '[]');
|
||
if (list.length === 0) {
|
||
historyContainer.innerHTML = `
|
||
<div class="empty-state">
|
||
<span class="icon-empty">📭</span>
|
||
<p>${dict.history_empty || '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');
|
||
});
|
||
}
|
||
}
|
||
|
||
// --- Universal Multi-Store Catalog & Client URL Sync Engine ---
|
||
window.ALL_STORES = {};
|
||
window.activeStoreId = 'glamourstouch';
|
||
window.GT_CATALOG = [];
|
||
let selectedCatalogBrand = 'all';
|
||
|
||
async function initCatalogBrowser() {
|
||
const catalogModal = document.getElementById('catalogModal');
|
||
const openCatalogModalBtn = document.getElementById('openCatalogModalBtn');
|
||
const catalogSearchInput = document.getElementById('catalogSearchInput');
|
||
const catalogGridContainer = document.getElementById('catalogGridContainer');
|
||
const catalogCountText = document.getElementById('catalogCountText');
|
||
const brandChipsContainer = document.getElementById('catalogBrandFilterChips');
|
||
const storeSwitcherBar = document.getElementById('storeSwitcherBar');
|
||
const toggleSyncPanelBtn = document.getElementById('toggleSyncPanelBtn');
|
||
const storeSyncPanel = document.getElementById('storeSyncPanel');
|
||
const closeSyncPanelBtn = document.getElementById('closeSyncPanelBtn');
|
||
const clientStoreUrlInput = document.getElementById('clientStoreUrlInput');
|
||
const clientStoreNameInput = document.getElementById('clientStoreNameInput');
|
||
const clientStoreCategorySelect = document.getElementById('clientStoreCategorySelect');
|
||
const startStoreSyncBtn = document.getElementById('startStoreSyncBtn');
|
||
const storeSyncStatusMsg = document.getElementById('storeSyncStatusMsg');
|
||
const deleteCurrentStoreBtn = document.getElementById('deleteCurrentStoreBtn');
|
||
const activeStoreIcon = document.getElementById('activeStoreIcon');
|
||
const activeStoreTitle = document.getElementById('activeStoreTitle');
|
||
const activeStoreBadge = document.getElementById('activeStoreBadge');
|
||
const activeStoreUrlLink = document.getElementById('activeStoreUrlLink');
|
||
const productInput = document.getElementById('productInput');
|
||
const autocompleteList = document.getElementById('productAutocompleteList');
|
||
|
||
// 1. Initialize Master Store: Glamour's Touch (563 Products)
|
||
try {
|
||
const res = await fetch('gt_full_catalog.json');
|
||
if (res.ok) {
|
||
window.GT_CATALOG = await res.json();
|
||
window.ALL_STORES['glamourstouch'] = {
|
||
id: 'glamourstouch',
|
||
name: "Glamour's Touch",
|
||
icon: '✨',
|
||
domain: 'glamourstouch.com',
|
||
url: 'https://glamourstouch.com',
|
||
category: 'cosmetics',
|
||
badge: 'KOREAN COSMETICS',
|
||
count: window.GT_CATALOG.length,
|
||
products: window.GT_CATALOG,
|
||
isMaster: true
|
||
};
|
||
}
|
||
} catch (e) {
|
||
console.warn('Could not load gt_full_catalog.json:', e);
|
||
}
|
||
|
||
// 2. Load Synced Stores from backend API
|
||
await loadSyncedStoresFromBackend();
|
||
|
||
async function loadSyncedStoresFromBackend() {
|
||
try {
|
||
const res = await fetch('/api/get-synced-stores');
|
||
if (res.ok) {
|
||
const data = await res.json();
|
||
if (data && Array.isArray(data.stores)) {
|
||
data.stores.forEach(s => {
|
||
let catEmoji = '🛍️';
|
||
let catBadge = 'E-COMMERCE';
|
||
if (s.category === 'fashion') { catEmoji = '👗'; catBadge = 'FASHION & SAREE'; }
|
||
else if (s.category === 'panjabi') { catEmoji = '👑'; catBadge = 'ROYAL PANJABI'; }
|
||
else if (s.category === 'electronics') { catEmoji = '⚡'; catBadge = 'GADGETS & TECH'; }
|
||
else if (s.category === 'organic') { catEmoji = '🍯'; catBadge = 'ORGANIC FOOD'; }
|
||
else if (s.category === 'sneakerlab') { catEmoji = '👟'; catBadge = 'SHOES & WEAR'; }
|
||
else if (s.category === 'cosmetics') { catEmoji = '💄'; catBadge = 'BEAUTY & CARE'; }
|
||
|
||
window.ALL_STORES[s.id] = {
|
||
id: s.id,
|
||
name: s.name,
|
||
icon: catEmoji,
|
||
domain: s.domain,
|
||
url: s.url,
|
||
category: s.category || 'general',
|
||
badge: catBadge,
|
||
count: s.count || (s.products ? s.products.length : 0),
|
||
products: s.products || [],
|
||
isMaster: false
|
||
};
|
||
});
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.warn('Could not load synced stores:', e);
|
||
}
|
||
}
|
||
|
||
// 3. Render Store Switcher Chips Bar
|
||
function renderStoreSwitcher() {
|
||
if (!storeSwitcherBar) return;
|
||
const storeKeys = Object.keys(window.ALL_STORES);
|
||
|
||
let html = '';
|
||
storeKeys.forEach(k => {
|
||
const st = window.ALL_STORES[k];
|
||
const isActive = k === window.activeStoreId;
|
||
html += `
|
||
<button type="button" class="store-chip-btn ${isActive ? 'active' : ''}" data-store-id="${st.id}">
|
||
<span>${st.icon || '🛍️'}</span> ${st.name} (${st.count || st.products.length})
|
||
</button>
|
||
`;
|
||
});
|
||
|
||
html += `
|
||
<button type="button" class="store-chip-btn add-store-btn" id="toggleSyncPanelBtn">
|
||
<span>➕</span> নতুন ক্লায়েন্ট স্টোর সিঙ্ক
|
||
</button>
|
||
`;
|
||
|
||
storeSwitcherBar.innerHTML = html;
|
||
|
||
// Attach click listeners
|
||
storeSwitcherBar.querySelectorAll('.store-chip-btn[data-store-id]').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const targetId = btn.getAttribute('data-store-id');
|
||
switchActiveStore(targetId);
|
||
});
|
||
});
|
||
|
||
const addBtn = document.getElementById('toggleSyncPanelBtn');
|
||
if (addBtn) {
|
||
addBtn.addEventListener('click', () => {
|
||
if (storeSyncPanel) {
|
||
storeSyncPanel.classList.toggle('hidden');
|
||
if (!storeSyncPanel.classList.contains('hidden') && clientStoreUrlInput) {
|
||
clientStoreUrlInput.focus();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// Switch Active Store
|
||
function switchActiveStore(storeId) {
|
||
if (!window.ALL_STORES[storeId]) return;
|
||
window.activeStoreId = storeId;
|
||
selectedCatalogBrand = 'all';
|
||
|
||
if (catalogSearchInput) catalogSearchInput.value = '';
|
||
|
||
renderStoreSwitcher();
|
||
updateStoreBanner();
|
||
renderBrandFilterChips();
|
||
renderCatalogGrid();
|
||
}
|
||
|
||
// Update Store Banner
|
||
function updateStoreBanner() {
|
||
const cur = window.ALL_STORES[window.activeStoreId];
|
||
if (!cur) return;
|
||
|
||
if (activeStoreIcon) activeStoreIcon.textContent = cur.icon || '🛍️';
|
||
if (activeStoreTitle) activeStoreTitle.textContent = `${cur.name} (${cur.domain})`;
|
||
if (activeStoreBadge) activeStoreBadge.textContent = cur.badge || (cur.category ? cur.category.toUpperCase() : 'E-COMMERCE');
|
||
if (activeStoreUrlLink) {
|
||
activeStoreUrlLink.href = cur.url;
|
||
activeStoreUrlLink.textContent = `🔗 ${cur.domain}`;
|
||
}
|
||
|
||
if (deleteCurrentStoreBtn) {
|
||
if (cur.isMaster) {
|
||
deleteCurrentStoreBtn.classList.add('hidden');
|
||
} else {
|
||
deleteCurrentStoreBtn.classList.remove('hidden');
|
||
}
|
||
}
|
||
}
|
||
|
||
// Delete Current Synced Store
|
||
if (deleteCurrentStoreBtn) {
|
||
deleteCurrentStoreBtn.addEventListener('click', async () => {
|
||
const cur = window.ALL_STORES[window.activeStoreId];
|
||
if (!cur || cur.isMaster) return;
|
||
|
||
if (confirm(`আপনি কি "${cur.name}" স্টোর বক্স এবং এর সব প্রডাক্ট মুছে ফেলতে চান?`)) {
|
||
try {
|
||
await fetch('/api/delete-synced-store', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ storeId: cur.id })
|
||
});
|
||
delete window.ALL_STORES[cur.id];
|
||
switchActiveStore('glamourstouch');
|
||
} catch (e) {
|
||
alert('Error deleting store: ' + e.message);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// Toggle / Close Sync Panel
|
||
if (closeSyncPanelBtn && storeSyncPanel) {
|
||
closeSyncPanelBtn.addEventListener('click', () => {
|
||
storeSyncPanel.classList.add('hidden');
|
||
});
|
||
}
|
||
|
||
// 4. Handle Client Store URL Sync Submission
|
||
if (startStoreSyncBtn) {
|
||
startStoreSyncBtn.addEventListener('click', async () => {
|
||
const rawUrl = clientStoreUrlInput ? clientStoreUrlInput.value.trim() : '';
|
||
const customName = clientStoreNameInput ? clientStoreNameInput.value.trim() : '';
|
||
const category = clientStoreCategorySelect ? clientStoreCategorySelect.value : 'general';
|
||
|
||
if (!rawUrl) {
|
||
alert('⚠️ দয়া করে ক্লায়েন্টের ওয়েবসাইট URL দিন (e.g. https://snehalata.com বা যেকোনো শপ লিংক)');
|
||
if (clientStoreUrlInput) clientStoreUrlInput.focus();
|
||
return;
|
||
}
|
||
|
||
storeSyncStatusMsg.classList.remove('hidden');
|
||
storeSyncStatusMsg.style.color = '#38BDF8';
|
||
storeSyncStatusMsg.textContent = '⏳ ওয়েবসাইট ক্রল ও প্রডাক্ট সিঙ্ক হচ্ছে... অনুগ্রহ করে একটু অপেক্ষা করুন...';
|
||
startStoreSyncBtn.disabled = true;
|
||
|
||
try {
|
||
const res = await fetch('/api/sync-store', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
url: rawUrl,
|
||
storeName: customName,
|
||
category: category
|
||
})
|
||
});
|
||
|
||
const data = await res.json();
|
||
if (res.ok && data.success && data.store) {
|
||
const s = data.store;
|
||
let catEmoji = '🛍️';
|
||
let catBadge = 'E-COMMERCE';
|
||
if (s.category === 'fashion') { catEmoji = '👗'; catBadge = 'FASHION & SAREE'; }
|
||
else if (s.category === 'panjabi') { catEmoji = '👑'; catBadge = 'ROYAL PANJABI'; }
|
||
else if (s.category === 'electronics') { catEmoji = '⚡'; catBadge = 'GADGETS & TECH'; }
|
||
else if (s.category === 'organic') { catEmoji = '🍯'; catBadge = 'ORGANIC FOOD'; }
|
||
else if (s.category === 'sneakerlab') { catEmoji = '👟'; catBadge = 'SHOES & WEAR'; }
|
||
else if (s.category === 'cosmetics') { catEmoji = '💄'; catBadge = 'BEAUTY & CARE'; }
|
||
|
||
window.ALL_STORES[s.id] = {
|
||
id: s.id,
|
||
name: s.name,
|
||
icon: catEmoji,
|
||
domain: s.domain,
|
||
url: s.url,
|
||
category: s.category || 'general',
|
||
badge: catBadge,
|
||
count: s.count || s.products.length,
|
||
products: s.products || [],
|
||
isMaster: false
|
||
};
|
||
|
||
storeSyncStatusMsg.style.color = '#10B981';
|
||
storeSyncStatusMsg.textContent = `🎉 "${s.name}"-এর ${s.count}টি প্রোডাক্ট সফলভাবে সিঙ্ক হয়েছে ও আলাদা স্টোর বক্স তৈরি হয়েছে!`;
|
||
|
||
// Clear inputs
|
||
if (clientStoreUrlInput) clientStoreUrlInput.value = '';
|
||
if (clientStoreNameInput) clientStoreNameInput.value = '';
|
||
|
||
setTimeout(() => {
|
||
storeSyncPanel.classList.add('hidden');
|
||
storeSyncStatusMsg.classList.add('hidden');
|
||
switchActiveStore(s.id);
|
||
}, 1200);
|
||
|
||
} else {
|
||
storeSyncStatusMsg.style.color = '#EF4444';
|
||
storeSyncStatusMsg.textContent = `❌ সিঙ্ক এরর: ${data.error || 'ওয়েবসাইট থেকে প্রোডাক্ট পাওয়া যায়নি।'}`;
|
||
}
|
||
} catch (err) {
|
||
storeSyncStatusMsg.style.color = '#EF4444';
|
||
storeSyncStatusMsg.textContent = `❌ কানেকশন এরর: ${err.message}`;
|
||
}
|
||
|
||
startStoreSyncBtn.disabled = false;
|
||
});
|
||
}
|
||
|
||
// 5. Open / Close Modal
|
||
window.openCatalogModal = function() {
|
||
if (catalogModal) {
|
||
catalogModal.classList.remove('hidden');
|
||
renderStoreSwitcher();
|
||
updateStoreBanner();
|
||
renderBrandFilterChips();
|
||
renderCatalogGrid();
|
||
if (catalogSearchInput) {
|
||
catalogSearchInput.value = '';
|
||
}
|
||
}
|
||
};
|
||
|
||
window.closeCatalogModal = function() {
|
||
if (catalogModal) catalogModal.classList.add('hidden');
|
||
};
|
||
|
||
if (openCatalogModalBtn) {
|
||
openCatalogModalBtn.addEventListener('click', window.openCatalogModal);
|
||
}
|
||
|
||
if (catalogModal) {
|
||
catalogModal.addEventListener('click', (e) => {
|
||
if (e.target === catalogModal) {
|
||
window.closeCatalogModal();
|
||
}
|
||
});
|
||
}
|
||
|
||
// 6. Search & Filter
|
||
if (catalogSearchInput) {
|
||
catalogSearchInput.addEventListener('input', () => {
|
||
renderCatalogGrid();
|
||
});
|
||
}
|
||
|
||
// Render Brand Filter Chips dynamically for the active store
|
||
function renderBrandFilterChips() {
|
||
if (!brandChipsContainer) return;
|
||
const cur = window.ALL_STORES[window.activeStoreId];
|
||
if (!cur || !cur.products) {
|
||
brandChipsContainer.innerHTML = '';
|
||
return;
|
||
}
|
||
|
||
const brandCounts = {};
|
||
cur.products.forEach(p => {
|
||
const b = p.brand || cur.name || 'Brand';
|
||
brandCounts[b] = (brandCounts[b] || 0) + 1;
|
||
});
|
||
|
||
const topBrands = Object.keys(brandCounts)
|
||
.sort((a, b) => brandCounts[b] - brandCounts[a])
|
||
.slice(0, 15);
|
||
|
||
let html = `<button class="filter-chip ${selectedCatalogBrand === 'all' ? 'active' : ''}" data-brand="all">🔥 All Brands (${cur.products.length})</button>`;
|
||
|
||
topBrands.forEach(b => {
|
||
html += `<button class="filter-chip ${selectedCatalogBrand.toLowerCase() === b.toLowerCase() ? 'active' : ''}" data-brand="${b}">${b} (${brandCounts[b]})</button>`;
|
||
});
|
||
|
||
brandChipsContainer.innerHTML = html;
|
||
|
||
brandChipsContainer.querySelectorAll('.filter-chip').forEach(chip => {
|
||
chip.addEventListener('click', () => {
|
||
brandChipsContainer.querySelectorAll('.filter-chip').forEach(c => c.classList.remove('active'));
|
||
chip.classList.add('active');
|
||
selectedCatalogBrand = chip.getAttribute('data-brand') || 'all';
|
||
renderCatalogGrid();
|
||
});
|
||
});
|
||
}
|
||
|
||
// Render Product Grid for Active Store
|
||
function renderCatalogGrid() {
|
||
if (!catalogGridContainer) return;
|
||
const cur = window.ALL_STORES[window.activeStoreId];
|
||
if (!cur) return;
|
||
|
||
const dict = I18N_DICTIONARY[window.currentLang] || I18N_DICTIONARY.bn;
|
||
const query = (catalogSearchInput ? catalogSearchInput.value : '').toLowerCase().trim();
|
||
|
||
let filtered = cur.products || [];
|
||
if (selectedCatalogBrand !== 'all') {
|
||
filtered = filtered.filter(p => (p.brand || '').toLowerCase() === selectedCatalogBrand.toLowerCase());
|
||
}
|
||
if (query) {
|
||
filtered = filtered.filter(p =>
|
||
(p.title || '').toLowerCase().includes(query) ||
|
||
(p.brand || '').toLowerCase().includes(query)
|
||
);
|
||
}
|
||
|
||
if (catalogCountText) {
|
||
if (window.currentLang === 'en') {
|
||
catalogCountText.textContent = `${cur.name} — ${filtered.length} authentic products found (Total ${cur.products.length})`;
|
||
} else {
|
||
catalogCountText.textContent = `${cur.name} — ${filtered.length}টি আসল প্রোডাক্ট পাওয়া গেছে (মোট ${cur.products.length}টি)`;
|
||
}
|
||
}
|
||
|
||
if (filtered.length === 0) {
|
||
catalogGridContainer.innerHTML = `
|
||
<div class="empty-state" style="grid-column: 1 / -1;">
|
||
<span class="icon-empty">🔍</span>
|
||
<p>${dict.catalog_empty || 'এই স্টোরে কোনো প্রোডাক্ট পাওয়া যায়নি। অন্য কি-ওয়ার্ড বা ব্র্যান্ড সিলেক্ট করুন অথবা URL দিয়ে সিঙ্ক করুন।'}</p>
|
||
</div>
|
||
`;
|
||
return;
|
||
}
|
||
|
||
const displayList = filtered.slice(0, 150);
|
||
catalogGridContainer.innerHTML = displayList.map(p => `
|
||
<div class="catalog-item-card">
|
||
<img class="catalog-item-img" src="${p.image || '/assets/products/cosmetics_3d_cgi.jpg'}" alt="${p.title}" loading="lazy" onerror="this.src='/assets/products/cosmetics_3d_cgi.jpg'">
|
||
<div style="flex:1;">
|
||
<span style="font-size:10px; font-weight:800; color:#C084FC; text-transform:uppercase; letter-spacing:0.5px;">${p.brand || cur.name}</span>
|
||
<h4 class="catalog-item-title" title="${p.title}">${p.title}</h4>
|
||
<div class="catalog-item-price-row">
|
||
<span class="catalog-item-price">${p.price}</span>
|
||
<span class="catalog-item-reg-price">${p.regularPrice}</span>
|
||
</div>
|
||
</div>
|
||
<div class="catalog-item-actions">
|
||
<button type="button" class="btn-catalog-copy" onclick="window.copyCatalogProductInfo('${p.id}')">
|
||
${dict.btn_catalog_copy || '📋 কপি'}
|
||
</button>
|
||
<button type="button" class="btn-catalog-use" onclick="window.applyCatalogProductToPoster('${p.id}')">
|
||
${dict.btn_catalog_use || '⚡ ৩ডি পোস্টার'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// 7. Global Action Handlers
|
||
window.copyCatalogProductInfo = function(id) {
|
||
let p = null;
|
||
let storeObj = null;
|
||
|
||
for (const sKey of Object.keys(window.ALL_STORES)) {
|
||
const st = window.ALL_STORES[sKey];
|
||
const found = (st.products || []).find(item => item.id === id);
|
||
if (found) {
|
||
p = found;
|
||
storeObj = st;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!p) return;
|
||
const text = `✨ ${p.title}\n🏷️ ব্র্যান্ড / স্টোর: ${p.brand || storeObj.name}\n💰 অফার মূল্য: ${p.price} (রেগুলার ${p.regularPrice})\n🛡️ ১০০% আসল ও প্রিমিয়াম কোয়ালিটি নিশ্চিত\n🔗 লিংক: ${p.link || storeObj.url}\n📸 ইমেজ: ${p.image}`;
|
||
navigator.clipboard.writeText(text).then(() => {
|
||
alert(`✅ "${p.title}"-এর সম্পূর্ণ তথ্য কপি হয়েছে!`);
|
||
}).catch(() => {
|
||
const ta = document.createElement('textarea');
|
||
ta.value = text;
|
||
document.body.appendChild(ta);
|
||
ta.select();
|
||
document.execCommand('copy');
|
||
document.body.removeChild(ta);
|
||
alert(`✅ "${p.title}"-এর সম্পূর্ণ তথ্য কপি হয়েছে!`);
|
||
});
|
||
};
|
||
|
||
window.applyCatalogProductToPoster = function(id) {
|
||
let p = null;
|
||
let storeObj = null;
|
||
|
||
for (const sKey of Object.keys(window.ALL_STORES)) {
|
||
const st = window.ALL_STORES[sKey];
|
||
const found = (st.products || []).find(item => item.id === id);
|
||
if (found) {
|
||
p = found;
|
||
storeObj = st;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!p) return;
|
||
|
||
const pInput = document.getElementById('productInput');
|
||
const pPrice = document.getElementById('productPrice');
|
||
const pBadge = document.getElementById('customBadgeInput');
|
||
const pBrand = document.getElementById('brandWatermarkSelect');
|
||
const photoImg = document.getElementById('attachedPhotoImg');
|
||
const photoBox = document.getElementById('photoPreviewContainer');
|
||
const clearBtn = document.getElementById('clearPhotoBtn');
|
||
|
||
if (pInput) pInput.value = p.title;
|
||
if (pPrice) pPrice.value = `${p.price} (${p.regularPrice}) 20% OFF`;
|
||
if (pBadge) pBadge.value = `🛡️ 100% Authentic ${p.brand || storeObj.name}`;
|
||
|
||
if (pBrand) {
|
||
if (storeObj.id === 'glamourstouch') {
|
||
pBrand.value = 'glamourstouch';
|
||
} else if (storeObj.category && pBrand.querySelector(`option[value="${storeObj.category}"]`)) {
|
||
pBrand.value = storeObj.category;
|
||
} else {
|
||
pBrand.value = 'custom';
|
||
}
|
||
}
|
||
|
||
if (photoImg && photoBox && p.image) {
|
||
photoImg.src = p.image;
|
||
photoBox.classList.remove('hidden');
|
||
if (clearBtn) clearBtn.classList.remove('hidden');
|
||
}
|
||
|
||
window.closeCatalogModal();
|
||
if (autocompleteList) autocompleteList.classList.add('hidden');
|
||
switchToTab('tabPosterLab');
|
||
|
||
setTimeout(() => {
|
||
const genBtn = document.getElementById('generatePosterBtn');
|
||
if (genBtn) genBtn.click();
|
||
}, 250);
|
||
};
|
||
|
||
// 8. Live Autocomplete on #productInput across all active stores
|
||
if (productInput && autocompleteList) {
|
||
productInput.addEventListener('input', (e) => {
|
||
const val = e.target.value.toLowerCase().trim();
|
||
if (val.length < 1) {
|
||
autocompleteList.classList.add('hidden');
|
||
return;
|
||
}
|
||
|
||
let allProducts = [];
|
||
Object.keys(window.ALL_STORES).forEach(k => {
|
||
allProducts = allProducts.concat(window.ALL_STORES[k].products || []);
|
||
});
|
||
|
||
const matches = allProducts
|
||
.filter(p => (p.title || '').toLowerCase().includes(val) || (p.brand || '').toLowerCase().includes(val))
|
||
.slice(0, 10);
|
||
|
||
if (matches.length === 0) {
|
||
autocompleteList.classList.add('hidden');
|
||
return;
|
||
}
|
||
|
||
const dict = I18N_DICTIONARY[window.currentLang] || I18N_DICTIONARY.bn;
|
||
autocompleteList.innerHTML = matches.map(p => `
|
||
<div class="autocomplete-item" onclick="window.applyCatalogProductToPoster('${p.id}')">
|
||
<img class="autocomplete-thumb" src="${p.image || '/assets/products/cosmetics_3d_cgi.jpg'}" alt="${p.title}" onerror="this.src='/assets/products/cosmetics_3d_cgi.jpg'">
|
||
<div class="autocomplete-info">
|
||
<div class="autocomplete-title">${p.title}</div>
|
||
<div class="autocomplete-meta">
|
||
<span class="autocomplete-brand">${p.brand || p.storeName || "Authentic"}</span>
|
||
<span class="autocomplete-price">${p.price}</span>
|
||
</div>
|
||
</div>
|
||
<button type="button" class="autocomplete-copy-btn" onclick="event.stopPropagation(); window.copyCatalogProductInfo('${p.id}');">
|
||
${dict.btn_catalog_copy || '📋 কপি'}
|
||
</button>
|
||
</div>
|
||
`).join('');
|
||
|
||
autocompleteList.classList.remove('hidden');
|
||
});
|
||
|
||
document.addEventListener('click', (e) => {
|
||
if (!productInput.contains(e.target) && !autocompleteList.contains(e.target)) {
|
||
autocompleteList.classList.add('hidden');
|
||
}
|
||
});
|
||
|
||
productInput.addEventListener('focus', () => {
|
||
if (productInput.value.trim().length > 0 && autocompleteList.children.length > 0) {
|
||
autocompleteList.classList.remove('hidden');
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
|
||
|