diff --git a/src/components/CinemaStudio.js b/src/components/CinemaStudio.js
index 62559f6..1c46fc2 100644
--- a/src/components/CinemaStudio.js
+++ b/src/components/CinemaStudio.js
@@ -1,7 +1,7 @@
import { muapi } from '../lib/muapi.js';
import { CameraControls } from './CameraControls.js';
-import { buildNanoBananaPrompt, CAMERA_MAP, LENS_MAP } from '../lib/promptUtils.js';
+import { buildNanoBananaPrompt, CAMERA_MAP, LENS_MAP, FOCAL_PERSPECTIVE, APERTURE_EFFECT } from '../lib/promptUtils.js';
import { AuthModal } from './AuthModal.js';
export function CinemaStudio() {
@@ -17,6 +17,9 @@ export function CinemaStudio() {
focal: 35,
aperture: "f/1.4"
};
+
+ // Camera builder panel state
+ let showCameraBuilder = false;
// ==========================================
// 1. HERO SECTION (Empty State)
@@ -180,6 +183,13 @@ export function CinemaStudio() {
createDropdown(['1K', '2K', '4K'], resBtn.dataset.value, (val) => { updateResBtn(val); }, resBtn);
};
settingsToolbar.appendChild(resBtn);
+
+ // Camera Builder Toggle Button
+ const cameraBuilderBtn = document.createElement('button');
+ cameraBuilderBtn.className = 'flex items-center gap-1.5 px-3 py-1.5 text-[10px] font-bold text-white/50 hover:text-white transition-colors bg-white/5 hover:bg-white/10 rounded-lg border border-white/5';
+ cameraBuilderBtn.setAttribute('data-tooltip', 'Quick camera builder');
+ cameraBuilderBtn.innerHTML = ` Builder`;
+ settingsToolbar.appendChild(cameraBuilderBtn);
leftColumn.appendChild(settingsToolbar);
promptBar.appendChild(leftColumn);
@@ -193,6 +203,7 @@ export function CinemaStudio() {
const summaryCard = document.createElement('button');
// Removed 'hidden' class, added 'flex' and refined width constraints for mobile
summaryCard.className = 'flex flex-col items-start justify-center px-4 py-2 bg-[#2a2a2a] rounded-xl border border-white/5 hover:border-white/20 transition-colors text-left flex-1 min-w-[100px] md:min-w-[140px] max-w-[240px] h-[56px] relative group overflow-hidden';
+ summaryCard.setAttribute('data-tooltip', 'Open camera settings');
// Dot indicator
const dot = document.createElement('div');
@@ -224,6 +235,7 @@ export function CinemaStudio() {
// Generate Button
const generateBtn = document.createElement('button');
generateBtn.className = 'h-[56px] px-8 bg-[#d9ff00] text-black rounded-xl font-black text-xs uppercase hover:bg-white transition-colors shadow-lg disabled:opacity-50 disabled:cursor-not-allowed';
+ generateBtn.setAttribute('data-tooltip', 'Generate cinema shot');
generateBtn.innerHTML = `GENERATE ✨`;
rightGroup.appendChild(summaryCard);
@@ -233,6 +245,114 @@ export function CinemaStudio() {
promptBarWrapper.appendChild(promptBar);
container.appendChild(promptBarWrapper);
+ // ==========================================
+ // 3B. CAMERA BUILDER PANEL (Collapsible)
+ // ==========================================
+ const cameraBuilderPanel = document.createElement('div');
+ cameraBuilderPanel.className = 'absolute bottom-8 left-4 right-4 md:left-1/2 md:-translate-x-1/2 md:w-full md:max-w-4xl z-20';
+ cameraBuilderPanel.style.display = 'none'; // Hidden by default
+
+ const builderCard = document.createElement('div');
+ builderCard.className = 'bg-[#1a1a1a] border border-white/10 rounded-2xl p-4 shadow-3xl';
+
+ builderCard.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ cameraBuilderPanel.appendChild(builderCard);
+ container.appendChild(cameraBuilderPanel);
+
+ // Camera Builder toggle logic
+ cameraBuilderBtn.onclick = () => {
+ showCameraBuilder = !showCameraBuilder;
+ cameraBuilderPanel.style.display = showCameraBuilder ? 'block' : 'none';
+ if (showCameraBuilder) updateBuilderPreview();
+ };
+
+ const closeBuilderBtn = cameraBuilderPanel.querySelector('#close-builder-btn');
+ if (closeBuilderBtn) closeBuilderBtn.onclick = () => {
+ showCameraBuilder = false;
+ cameraBuilderPanel.style.display = 'none';
+ };
+
+ // Update builder preview
+ const updateBuilderPreview = () => {
+ const camera = builderCard.querySelector('#builder-camera')?.value || currentSettings.camera;
+ const lens = builderCard.querySelector('#builder-lens')?.value || currentSettings.lens;
+ const focal = parseInt(builderCard.querySelector('#builder-focal')?.value || currentSettings.focal);
+ const aperture = builderCard.querySelector('#builder-aperture')?.value || currentSettings.aperture;
+
+ const preview = buildNanoBananaPrompt('', camera, lens, focal, aperture);
+ const previewEl = builderCard.querySelector('#builder-preview');
+ if (previewEl) {
+ previewEl.textContent = preview || 'Select camera settings to see preview...';
+ }
+ };
+
+ // Builder event listeners
+ const builderCamera = builderCard.querySelector('#builder-camera');
+ const builderLens = builderCard.querySelector('#builder-lens');
+ const builderFocal = builderCard.querySelector('#builder-focal');
+ const builderAperture = builderCard.querySelector('#builder-aperture');
+
+ if (builderCamera) builderCamera.onchange = updateBuilderPreview;
+ if (builderLens) builderLens.onchange = updateBuilderPreview;
+ if (builderFocal) builderFocal.onchange = updateBuilderPreview;
+ if (builderAperture) builderAperture.onchange = updateBuilderPreview;
+
+ const applyBuilderBtn = builderCard.querySelector('#apply-builder-btn');
+ if (applyBuilderBtn) {
+ applyBuilderBtn.onclick = () => {
+ currentSettings.camera = builderCamera?.value || currentSettings.camera;
+ currentSettings.lens = builderLens?.value || currentSettings.lens;
+ currentSettings.focal = parseInt(builderFocal?.value || currentSettings.focal);
+ currentSettings.aperture = builderAperture?.value || currentSettings.aperture;
+ updateSummaryCard();
+ showCameraBuilder = false;
+ cameraBuilderPanel.style.display = 'none';
+ };
+ }
+
// ==========================================
// 3. HISTORY SIDEBAR
diff --git a/src/components/ImageStudio.js b/src/components/ImageStudio.js
index ef7c7dd..c66deec 100644
--- a/src/components/ImageStudio.js
+++ b/src/components/ImageStudio.js
@@ -4,6 +4,7 @@ import {
i2iModels, getAspectRatiosForI2IModel, getResolutionsForI2IModel, getQualityFieldForI2IModel,
getMaxImagesForI2IModel
} from '../lib/models.js';
+import { ENHANCE_TAGS, QUICK_PROMPTS } from '../lib/promptUtils.js';
import { AuthModal } from './AuthModal.js';
import { createUploadPicker } from './UploadPicker.js';
import { savePendingJob, removePendingJob, getPendingJobs } from '../lib/pendingJobs.js';
@@ -21,6 +22,25 @@ export function ImageStudio() {
let uploadedImageUrls = []; // array of uploaded image URLs (multi-image support)
let imageMode = false; // false = t2i models, true = i2i models
+ // Advanced parameters state
+ let negativePrompt = '';
+ let guidanceScale = 7.5;
+ let steps = 25;
+ let seed = -1;
+ let showAdvanced = false;
+ let selectedStyle = 'None';
+ let batchCount = 1;
+
+ // New advanced controls
+ let customWidth = 0; // 0 means use default (aspect ratio based)
+ let customHeight = 0;
+ let referenceStrength = 50; // 0-100, for style reference models
+ let selectedLora = ''; // LoRA model ID from Civitai
+ let loraWeight = 1.0;
+
+ // Quick tools panel state
+ let showToolsPanel = false;
+
const getCurrentModels = () => imageMode ? i2iModels : t2iModels;
const getCurrentAspectRatios = (id) => imageMode ? getAspectRatiosForI2IModel(id) : getAspectRatiosForModel(id);
const getCurrentResolutions = (id) => imageMode ? getResolutionsForI2IModel(id) : getResolutionsForModel(id);
@@ -127,10 +147,11 @@ export function ImageStudio() {
const controlsLeft = document.createElement('div');
controlsLeft.className = 'flex items-center gap-1.5 md:gap-2.5 relative overflow-x-auto no-scrollbar pb-1 md:pb-0';
- const createControlBtn = (icon, label, id) => {
+ const createControlBtn = (icon, label, id, tooltip) => {
const btn = document.createElement('button');
btn.id = id;
btn.className = 'flex items-center gap-1.5 md:gap-2.5 px-3 md:px-4 py-2 md:py-2.5 bg-white/5 hover:bg-white/10 rounded-xl md:rounded-2xl transition-all border border-white/5 group whitespace-nowrap';
+ if (tooltip) btn.setAttribute('data-tooltip', tooltip);
btn.innerHTML = `
${icon}
${label}
@@ -143,26 +164,42 @@ export function ImageStudio() {
G
- `, selectedModelName, 'model-btn');
+ `, selectedModelName, 'model-btn', 'Select AI generation model');
const arBtn = createControlBtn(`
- `, selectedAr, 'ar-btn');
+ `, selectedAr, 'ar-btn', 'Change aspect ratio');
const qualityBtn = createControlBtn(`
- `, '720p', 'quality-btn');
+ `, '720p', 'quality-btn', 'Set output quality');
controlsLeft.appendChild(modelBtn);
controlsLeft.appendChild(arBtn);
controlsLeft.appendChild(qualityBtn);
+
+ // Advanced options toggle button
+ const advancedBtn = createControlBtn(`
+
+ `, 'Advanced', 'advanced-btn', 'Show advanced options');
+ controlsLeft.appendChild(advancedBtn);
+
+ // Quick Tools toggle button
+ const toolsBtn = createControlBtn(`
+
+ `, 'Tools', 'tools-btn', 'Quick starters & prompt enhancer');
+ controlsLeft.appendChild(toolsBtn);
// Show quality button if the default model has quality/resolution options
const _initResolutions = getResolutionsForModel(defaultModel.id);
qualityBtn.style.display = _initResolutions.length > 0 ? 'flex' : 'none';
- if (_initResolutions.length > 0) document.getElementById('quality-btn-label').textContent = _initResolutions[0];
+ if (_initResolutions.length > 0) {
+ const qlabel = qualityBtn.querySelector('#quality-btn-label');
+ if (qlabel) qlabel.textContent = _initResolutions[0];
+ }
const generateBtn = document.createElement('button');
generateBtn.className = 'bg-primary text-black px-6 md:px-8 py-3 md:py-3.5 rounded-xl md:rounded-[1.5rem] font-black text-sm md:text-base hover:shadow-glow hover:scale-105 active:scale-95 transition-all flex items-center justify-center gap-2.5 w-full sm:w-auto shadow-lg';
+ generateBtn.setAttribute('data-tooltip', 'Generate AI image from prompt');
generateBtn.innerHTML = `Generate ✨`;
bottomRow.appendChild(controlsLeft);
@@ -171,6 +208,419 @@ export function ImageStudio() {
promptWrapper.appendChild(bar);
container.appendChild(promptWrapper);
+ const inlineInstructions = createInlineInstructions('image');
+ inlineInstructions.classList.add('max-w-4xl', 'mt-8');
+ container.appendChild(inlineInstructions);
+
+ // ==========================================
+ // 3. QUICK TOOLS PANEL (Prompt Enhancer + Quick Starters)
+ // ==========================================
+ const toolsPanel = document.createElement('div');
+ toolsPanel.className = 'w-full max-w-4xl mt-6 animate-fade-in-up hidden';
+ toolsPanel.id = 'tools-panel';
+
+ // Build tools panel HTML
+ toolsPanel.innerHTML = `
+
+
+
+
+
+
+
Quick Starters
+
+ ${QUICK_PROMPTS.map(q => `
+
+ `).join('')}
+
+
+
+
+
+
Prompt Enhancer
+
+
+
+
+
+
+ ${Object.entries(ENHANCE_TAGS).map(([category, tags]) =>
+ tags.map(tag => ``).join('')
+ ).join('')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ container.appendChild(toolsPanel);
+
+ // ==========================================
+ // 4. ADVANCED OPTIONS PANEL
+ // ==========================================
+ const STYLE_PRESETS = ['None', 'Photorealistic', 'Anime', 'Cinematic', 'Oil Painting', 'Watercolor', 'Digital Art', 'Concept Art', 'Cyberpunk'];
+
+ const advancedPanel = document.createElement('div');
+ advancedPanel.className = 'w-full max-w-4xl mt-6 animate-fade-in-up hidden';
+ advancedPanel.id = 'advanced-panel';
+ advancedPanel.innerHTML = `
+
+
+
Advanced Options
+
+
+
+
+
+
+
+ ${STYLE_PRESETS.map(s => ``).join('')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 7.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+ 50%
+
+
+
How much to preserve the reference image characteristics
+
+
+
+
+
+
+
+
+
+
+
Enter a LoRA model ID from Civitai (format: civitai:id@version)
+
+
+ `;
+ container.appendChild(advancedPanel);
+
+ // Advanced panel toggle logic
+ const toggleAdvanced = () => {
+ showAdvanced = !showAdvanced;
+ advancedPanel.classList.toggle('hidden', !showAdvanced);
+ document.getElementById('advanced-btn-label').textContent = showAdvanced ? 'Less' : 'Advanced';
+ };
+
+ // Add tools panel and advanced panel to container first before accessing their elements
+ container.appendChild(toolsPanel);
+ container.appendChild(advancedPanel);
+
+ // Now set up event handlers after elements are in DOM
+ advancedBtn.onclick = toggleAdvanced;
+ const closeAdvBtn = advancedPanel.querySelector('#close-adv-btn');
+ if (closeAdvBtn) closeAdvBtn.onclick = toggleAdvanced;
+
+ // Quick Tools Panel toggle
+ const toggleTools = () => {
+ showToolsPanel = !showToolsPanel;
+ toolsPanel.classList.toggle('hidden', !showToolsPanel);
+ if (showToolsPanel) {
+ // Close advanced panel when opening tools
+ if (!showAdvanced) {
+ showAdvanced = true;
+ advancedPanel.classList.remove('hidden');
+ }
+ }
+ document.getElementById('tools-btn-label').textContent = showToolsPanel ? 'Tools' : 'Tools';
+ };
+
+ toolsBtn.onclick = toggleTools;
+ const closeToolsBtn = toolsPanel.querySelector('#close-tools-btn');
+ if (closeToolsBtn) closeToolsBtn.onclick = toggleTools;
+
+ // Quick Starter buttons
+ const quickStarterBtns = toolsPanel.querySelectorAll('.quick-starter-btn');
+ quickStarterBtns.forEach(btn => {
+ btn.onclick = () => {
+ const prompt = btn.dataset.prompt;
+ textarea.value = prompt;
+ textarea.style.height = 'auto';
+ const maxHeight = window.innerWidth < 768 ? 150 : 250;
+ textarea.style.height = Math.min(textarea.scrollHeight, maxHeight) + 'px';
+ // Close tools panel after selection
+ showToolsPanel = false;
+ toolsPanel.classList.add('hidden');
+ };
+ });
+
+ // Prompt Enhancer - selected tags state
+ const enhanceSelectedTags = new Set();
+ const basePromptInput = toolsPanel.querySelector('#base-prompt-input');
+ const enhancedPromptDisplay = toolsPanel.querySelector('#enhanced-prompt-display');
+
+ // Update enhanced prompt display
+ const updateEnhancedPrompt = () => {
+ const base = basePromptInput?.value?.trim() || '';
+ const tags = Array.from(enhanceSelectedTags).join(', ');
+ const enhanced = [base, tags].filter(p => p).join(', ');
+ if (enhancedPromptDisplay) {
+ enhancedPromptDisplay.textContent = enhanced || 'Your enhanced prompt will appear here...';
+ enhancedPromptDisplay.classList.toggle('text-muted', !enhanced);
+ }
+ };
+
+ // Base prompt input handler
+ if (basePromptInput) {
+ basePromptInput.oninput = updateEnhancedPrompt;
+ }
+
+ // Enhance tag buttons
+ const enhanceTagBtns = toolsPanel.querySelectorAll('.enhance-tag-btn');
+ enhanceTagBtns.forEach(btn => {
+ btn.onclick = () => {
+ const tag = btn.dataset.tag;
+ if (enhanceSelectedTags.has(tag)) {
+ enhanceSelectedTags.delete(tag);
+ btn.classList.remove('bg-primary', 'text-black');
+ btn.classList.add('bg-white/5', 'text-secondary');
+ } else {
+ enhanceSelectedTags.add(tag);
+ btn.classList.remove('bg-white/5', 'text-secondary');
+ btn.classList.add('bg-primary', 'text-black');
+ }
+ updateEnhancedPrompt();
+ };
+ });
+
+ // Copy enhanced button
+ const copyEnhancedBtn = toolsPanel.querySelector('#copy-enhanced-btn');
+ if (copyEnhancedBtn) {
+ copyEnhancedBtn.onclick = () => {
+ const text = enhancedPromptDisplay?.textContent || '';
+ if (text && text !== 'Your enhanced prompt will appear here...') {
+ navigator.clipboard.writeText(text);
+ copyEnhancedBtn.textContent = 'Copied!';
+ setTimeout(() => { copyEnhancedBtn.textContent = 'Copy'; }, 1500);
+ }
+ };
+ }
+
+ // Use enhanced button
+ const useEnhancedBtn = toolsPanel.querySelector('#use-enhanced-btn');
+ if (useEnhancedBtn) {
+ useEnhancedBtn.onclick = () => {
+ const text = enhancedPromptDisplay?.textContent || '';
+ if (text && text !== 'Your enhanced prompt will appear here...') {
+ textarea.value = text;
+ textarea.style.height = 'auto';
+ const maxHeight = window.innerWidth < 768 ? 150 : 250;
+ textarea.style.height = Math.min(textarea.scrollHeight, maxHeight) + 'px';
+ // Close tools panel after use
+ showToolsPanel = false;
+ toolsPanel.classList.add('hidden');
+ }
+ };
+ }
+
+ // Negative prompt
+ const negPromptInput = advancedPanel.querySelector('#negative-prompt-input');
+ if (negPromptInput) negPromptInput.oninput = (e) => { negativePrompt = e.target.value; };
+
+ // Guidance scale slider
+ const guidanceSlider = advancedPanel.querySelector('#guidance-slider');
+ const guidanceValue = advancedPanel.querySelector('#guidance-value');
+ if (guidanceSlider && guidanceValue) {
+ guidanceSlider.oninput = (e) => {
+ guidanceScale = parseFloat(e.target.value);
+ guidanceValue.textContent = guidanceScale;
+ };
+ }
+
+ // Steps slider
+ const stepsSlider = advancedPanel.querySelector('#steps-slider');
+ const stepsValue = advancedPanel.querySelector('#steps-value');
+ if (stepsSlider && stepsValue) {
+ stepsSlider.oninput = (e) => {
+ steps = parseInt(e.target.value);
+ stepsValue.textContent = steps;
+ };
+ }
+
+ // Seed input
+ const seedInput = advancedPanel.querySelector('#seed-input');
+ if (seedInput) seedInput.oninput = (e) => { seed = parseInt(e.target.value) || -1; };
+
+ // Randomize seed button
+ const randSeedBtn = advancedPanel.querySelector('#randomize-seed-btn');
+ if (randSeedBtn) {
+ randSeedBtn.onclick = () => {
+ seed = Math.floor(Math.random() * 999999999);
+ if (seedInput) seedInput.value = seed;
+ };
+ }
+
+ // Batch count slider
+ const batchSlider = advancedPanel.querySelector('#batch-slider');
+ const batchValueEl = advancedPanel.querySelector('#batch-value');
+ if (batchSlider && batchValueEl) {
+ batchSlider.oninput = (e) => {
+ batchCount = parseInt(e.target.value);
+ batchValueEl.textContent = batchCount;
+ };
+ }
+
+ // Width input
+ const widthInput = advancedPanel.querySelector('#width-input');
+ if (widthInput) {
+ widthInput.oninput = (e) => {
+ customWidth = parseInt(e.target.value) || 0;
+ };
+ }
+
+ // Height input
+ const heightInput = advancedPanel.querySelector('#height-input');
+ if (heightInput) {
+ heightInput.oninput = (e) => {
+ customHeight = parseInt(e.target.value) || 0;
+ };
+ }
+
+ // Reference strength slider
+ const refStrengthSlider = advancedPanel.querySelector('#reference-strength-slider');
+ const refStrengthValue = advancedPanel.querySelector('#reference-strength-value');
+ if (refStrengthSlider && refStrengthValue) {
+ refStrengthSlider.oninput = (e) => {
+ referenceStrength = parseInt(e.target.value);
+ refStrengthValue.textContent = referenceStrength + '%';
+ };
+ }
+
+ // LoRA input
+ const loraInput = advancedPanel.querySelector('#lora-input');
+ if (loraInput) {
+ loraInput.oninput = (e) => {
+ selectedLora = e.target.value.trim();
+ };
+ }
+
+ // LoRA weight input
+ const loraWeightInput = advancedPanel.querySelector('#lora-weight-input');
+ if (loraWeightInput) {
+ loraWeightInput.oninput = (e) => {
+ loraWeight = parseFloat(e.target.value) || 1.0;
+ };
+ }
+
+ // Style preset handlers
+ advancedPanel.querySelectorAll('.style-preset-btn').forEach(btn => {
+ btn.onclick = () => {
+ selectedStyle = btn.dataset.style;
+ advancedPanel.querySelectorAll('.style-preset-btn').forEach(b => {
+ b.classList.remove('bg-primary/20', 'text-primary', 'border-primary/30');
+ b.classList.add('bg-white/5', 'text-secondary');
+ });
+ btn.classList.add('bg-primary/20', 'text-primary', 'border-primary/30');
+ btn.classList.remove('bg-white/5', 'text-secondary');
+ };
+ });
// ==========================================
// 3. DROPDOWNS (Professional implementation)
// ==========================================
diff --git a/src/components/VideoStudio.js b/src/components/VideoStudio.js
index afc298e..2c4e632 100644
--- a/src/components/VideoStudio.js
+++ b/src/components/VideoStudio.js
@@ -252,10 +252,11 @@ export function VideoStudio() {
const controlsLeft = document.createElement('div');
controlsLeft.className = 'flex items-center gap-1.5 md:gap-2.5 relative overflow-x-auto no-scrollbar pb-1 md:pb-0';
- const createControlBtn = (icon, label, id) => {
+ const createControlBtn = (icon, label, id, tooltip) => {
const btn = document.createElement('button');
btn.id = id;
btn.className = 'flex items-center gap-1.5 md:gap-2.5 px-3 md:px-4 py-2 md:py-2.5 bg-white/5 hover:bg-white/10 rounded-xl md:rounded-2xl transition-all border border-white/5 group whitespace-nowrap';
+ if (tooltip) btn.setAttribute('data-tooltip', tooltip);
btn.innerHTML = `
${icon}
${label}
@@ -268,23 +269,23 @@ export function VideoStudio() {
V
- `, selectedModelName, 'v-model-btn');
+ `, selectedModelName, 'v-model-btn', 'Select AI video model');
const arBtn = createControlBtn(`
- `, selectedAr, 'v-ar-btn');
+ `, selectedAr, 'v-ar-btn', 'Change aspect ratio');
const durationBtn = createControlBtn(`
- `, `${selectedDuration}s`, 'v-duration-btn');
+ `, `${selectedDuration}s`, 'v-duration-btn', 'Set video duration');
const resolutionBtn = createControlBtn(`
- `, selectedResolution || '720p', 'v-resolution-btn');
+ `, selectedResolution || '720p', 'v-resolution-btn', 'Set output resolution');
const qualityBtn = createControlBtn(`
- `, selectedQuality || 'basic', 'v-quality-btn');
+ `, selectedQuality || 'basic', 'v-quality-btn', 'Set output quality');
const modeBtn = createControlBtn(`
@@ -295,7 +296,12 @@ export function VideoStudio() {
controlsLeft.appendChild(durationBtn);
controlsLeft.appendChild(resolutionBtn);
controlsLeft.appendChild(qualityBtn);
- controlsLeft.appendChild(modeBtn);
+
+ // Advanced options toggle button
+ const advancedBtn = createControlBtn(`
+
+ `, 'Advanced', 'v-advanced-btn', 'Show advanced options');
+ controlsLeft.appendChild(advancedBtn);
// Initial visibility (t2v mode)
const initDurations = getDurationsForModel(defaultModel.id);
@@ -307,6 +313,7 @@ export function VideoStudio() {
const generateBtn = document.createElement('button');
generateBtn.className = 'bg-primary text-black px-6 md:px-8 py-3 md:py-3.5 rounded-xl md:rounded-[1.5rem] font-black text-sm md:text-base hover:shadow-glow hover:scale-105 active:scale-95 transition-all flex items-center justify-center gap-2.5 w-full sm:w-auto shadow-lg';
+ generateBtn.setAttribute('data-tooltip', 'Generate AI video from prompt');
generateBtn.innerHTML = `Generate ✨`;
bottomRow.appendChild(controlsLeft);
diff --git a/src/lib/promptUtils.js b/src/lib/promptUtils.js
index 6c657c9..fbb32bb 100644
--- a/src/lib/promptUtils.js
+++ b/src/lib/promptUtils.js
@@ -1,3 +1,21 @@
+export const ENHANCE_TAGS = {
+ quality: ['professional photography', 'ultra-detailed', '8K resolution', 'high dynamic range', 'award-winning'],
+ lighting: ['cinematic lighting', 'golden hour', 'dramatic studio lighting', 'soft diffused light', 'neon glow', 'volumetric rays'],
+ mood: ['moody atmosphere', 'serene and peaceful', 'epic and dramatic', 'warm and cozy', 'dark and mysterious'],
+ style: ['photorealistic', 'oil painting style', 'watercolor', 'digital art', 'concept art', 'anime style', 'cyberpunk aesthetic'],
+};
+
+export const QUICK_PROMPTS = [
+ { label: 'Portrait', prompt: 'Professional portrait photograph, shallow depth of field, soft studio lighting, 85mm lens' },
+ { label: 'Landscape', prompt: 'Breathtaking landscape photograph, golden hour, wide angle, dramatic clouds, 4K' },
+ { label: 'Product', prompt: 'Commercial product photography, clean white background, studio lighting, professional' },
+ { label: 'Fantasy', prompt: 'Epic fantasy scene, magical atmosphere, volumetric lighting, highly detailed, concept art' },
+ { label: 'Sci-Fi', prompt: 'Futuristic sci-fi environment, neon lights, cyberpunk city, rain reflections, cinematic' },
+ { label: 'Food', prompt: 'Professional food photography, appetizing, warm lighting, shallow depth of field, editorial' },
+ { label: 'Architecture', prompt: 'Architectural photography, dramatic angles, clean lines, modern design, professional' },
+ { label: 'Fashion', prompt: 'High fashion editorial, avant-garde styling, studio lighting, Vogue aesthetic, professional' },
+];
+
export const CAMERA_MAP = {
"Modular 8K Digital": "modular 8K digital cinema camera",
"Full-Frame Cine Digital": "full-frame digital cinema camera",
diff --git a/src/styles/global.css b/src/styles/global.css
index f0b334d..970d6ba 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -72,4 +72,181 @@
.animate-fade-in-up {
animation: fade-in-up 0.6s cubic-bezier(0.23, 1, 0.32, 1) forwards;
+}
+
+/* Thumbnail cards */
+.thumb-hero {
+ position: relative;
+ overflow: hidden;
+}
+
+.thumb-hero img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ object-position: top center;
+ transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.thumb-hero::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 60%;
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.75), transparent);
+ pointer-events: none;
+}
+
+.thumb-hero:hover img,
+.group:hover .thumb-hero img {
+ transform: scale(1.05);
+}
+
+.thumb-skeleton {
+ background: rgba(255, 255, 255, 0.03);
+ animation: skeleton-pulse 1.5s ease-in-out infinite;
+}
+
+@keyframes skeleton-pulse {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.4; }
+}
+
+.thumb-fallback .thumb-hero {
+ display: none;
+}
+
+.hero-banner img {
+ transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1);
+}
+
+.hero-banner:hover img {
+ transform: scale(1.03);
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .animate-fade-in-up {
+ animation: none;
+ opacity: 1;
+ }
+
+ .thumb-hero img {
+ transition: none;
+ }
+
+ .thumb-skeleton {
+ animation: none;
+ }
+}
+
+/* ========================
+ TOOLTIP SYSTEM
+ ======================== */
+
+/* Base tooltip container */
+[data-tooltip] {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
+/* Tooltip arrow */
+[data-tooltip]::before {
+ content: '';
+ position: absolute;
+ bottom: 100%;
+ left: 50%;
+ transform: translateX(-50%) translateY(8px);
+ border: 6px solid transparent;
+ border-top-color: #1a1a1a;
+ opacity: 0;
+ pointer-events: none;
+ transition: all 0.2s ease;
+ z-index: 9999;
+}
+
+/* Tooltip body */
+[data-tooltip]::after {
+ content: attr(data-tooltip);
+ position: absolute;
+ bottom: 100%;
+ left: 50%;
+ transform: translateX(-50%) translateY(12px);
+ padding: 8px 14px;
+ background: #1a1a1a;
+ border: 1px solid rgba(255,255,255,0.1);
+ border-radius: 10px;
+ font-size: 12px;
+ font-weight: 600;
+ color: #fff;
+ white-space: nowrap;
+ opacity: 0;
+ pointer-events: none;
+ transition: all 0.2s ease;
+ z-index: 9999;
+ box-shadow: 0 10px 30px -10px rgba(0,0,0,0.5);
+}
+
+/* Show tooltip on hover */
+[data-tooltip]:hover::before,
+[data-tooltip]:hover::after {
+ opacity: 1;
+ transform: translateX(-50%) translateY(-6px);
+}
+
+/* Tooltip positioning variants */
+[data-tooltip-bottom]::before {
+ bottom: auto;
+ top: 100%;
+ border-top-color: transparent;
+ border-bottom-color: #1a1a1a;
+ transform: translateX(-50%) translateY(-8px);
+}
+
+[data-tooltip-bottom]::after {
+ bottom: auto;
+ top: 100%;
+ transform: translateX(-50%) translateY(-12px);
+}
+
+[data-tooltip-bottom]:hover::before,
+[data-tooltip-bottom]:hover::after {
+ transform: translateX(-50%) translateY(6px);
+}
+
+/* Tooltip for left-aligned elements */
+[data-tooltip-left]::before {
+ left: 0;
+ transform: translateX(-100%) translateY(-50%);
+}
+
+[data-tooltip-left]::after {
+ left: 0;
+ transform: translateX(calc(-100% - 10px)) translateY(-50%);
+}
+
+[data-tooltip-left]:hover::before,
+[data-tooltip-left]:hover::after {
+ transform: translateX(calc(-100% - 6px)) translateY(-50%);
+}
+
+/* Tooltip for right-aligned elements */
+[data-tooltip-right]::before {
+ left: auto;
+ right: 0;
+ transform: translateX(100%) translateY(-50%);
+}
+
+[data-tooltip-right]::after {
+ left: auto;
+ right: 0;
+ transform: translateX(calc(100% + 10px)) translateY(-50%);
+}
+
+[data-tooltip-right]:hover::before,
+[data-tooltip-right]:hover::after {
+ transform: translateX(calc(100% + 6px)) translateY(-50%);
}
\ No newline at end of file