AI Image Studio Phase 1

This commit is contained in:
ajaysi
2025-11-20 09:06:00 +05:30
parent e96525347b
commit eede21ad42
58 changed files with 12951 additions and 8 deletions

View File

@@ -0,0 +1,263 @@
import React from 'react';
import {
Box,
Paper,
Stack,
Typography,
Chip,
Button,
Tooltip,
Divider,
} from '@mui/material';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import LaunchIcon from '@mui/icons-material/Launch';
import LockIcon from '@mui/icons-material/Lock';
import { alpha } from '@mui/material/styles';
import { ModuleConfig } from './types';
import { statusStyles } from './constants';
import { ModuleInfoCard } from './ModuleInfoCard';
import {
CreateEffectPreview,
EditEffectPreview,
UpscaleEffectPreview,
TransformEffectPreview,
SocialOptimizerEffectPreview,
ControlEffectPreview,
} from './previews';
interface ModuleCardProps {
module: ModuleConfig;
isHovered: boolean;
onMouseEnter: () => void;
onMouseLeave: () => void;
onNavigate: (route: string) => void;
}
export const ModuleCard: React.FC<ModuleCardProps> = ({
module,
isHovered,
onMouseEnter,
onMouseLeave,
onNavigate,
}) => {
const status = statusStyles[module.status];
const disabled = module.status !== 'live';
const hasPreview =
module.key === 'create' ||
module.key === 'edit' ||
module.key === 'upscale' ||
module.key === 'transform' ||
module.key === 'optimizer' ||
module.key === 'control';
const renderPreview = () => {
switch (module.key) {
case 'create':
return <CreateEffectPreview />;
case 'edit':
return <EditEffectPreview />;
case 'upscale':
return <UpscaleEffectPreview />;
case 'transform':
return <TransformEffectPreview />;
case 'optimizer':
return <SocialOptimizerEffectPreview />;
case 'control':
return <ControlEffectPreview />;
default:
return null;
}
};
return (
<Paper
sx={{
height: '100%',
borderRadius: 4,
p: 3,
border: '1px solid rgba(255,255,255,0.06)',
background: alpha('#111827', 0.8),
display: 'flex',
flexDirection: 'column',
gap: 1.5,
position: 'relative',
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
boxShadow: isHovered
? '0 20px 45px rgba(124,58,237,0.25)'
: '0 10px 25px rgba(15,23,42,0.35)',
transform: isHovered ? 'translateY(-4px)' : 'translateY(0)',
overflow: 'hidden',
'&::after': {
content: '""',
position: 'absolute',
inset: 0,
background:
module.key === 'create'
? 'radial-gradient(circle at top, rgba(124,58,237,0.25), transparent 60%)'
: module.key === 'edit'
? 'linear-gradient(120deg, rgba(8,145,178,0.25), transparent)'
: module.key === 'upscale'
? 'linear-gradient(90deg, rgba(248,113,113,0.25), transparent)'
: 'linear-gradient(120deg, rgba(59,130,246,0.15), transparent)',
opacity: isHovered ? 1 : 0.35,
pointerEvents: 'none',
},
}}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<Stack direction="row" justifyContent="space-between" alignItems="flex-start">
<Stack direction="row" spacing={1} alignItems="center">
<Box
sx={{
width: 44,
height: 44,
borderRadius: 2,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: alpha('#6366f1', 0.2),
color: '#c7d2fe',
fontSize: 22,
}}
>
{module.icon}
</Box>
<Stack spacing={0.5}>
<Typography variant="h6" fontWeight={700}>
{module.title}
</Typography>
<Typography variant="body2" color="text.secondary">
{module.subtitle}
</Typography>
</Stack>
</Stack>
<Chip
label={status.label}
size="small"
sx={{
backgroundColor: alpha(status.color, 0.2),
color: status.color,
fontWeight: 700,
}}
/>
</Stack>
<Stack direction="row" spacing={1} alignItems="center">
<Typography
variant="body2"
sx={{
color: hasPreview
? 'rgba(248,250,252,0.92)'
: 'rgba(148,163,184,0.95)',
}}
>
{module.description}
</Typography>
</Stack>
<Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
{module.highlights.map(item => (
<Chip
key={item}
size="small"
label={item}
sx={{
background: 'linear-gradient(120deg, rgba(99,102,241,0.35), rgba(14,165,233,0.35))',
color: '#f1f5f9',
border: '1px solid rgba(255,255,255,0.3)',
fontWeight: 600,
letterSpacing: 0.2,
}}
/>
))}
</Stack>
{hasPreview && (
<>
{renderPreview()}
<ModuleInfoCard module={module} />
</>
)}
{!hasPreview && (
<Box
sx={{
position: 'absolute',
inset: 16,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.1)',
background: 'rgba(15,23,42,0.92)',
backdropFilter: 'blur(12px)',
display: 'flex',
flexDirection: 'column',
gap: 1,
padding: 2,
opacity: isHovered ? 1 : 0,
pointerEvents: 'none',
transition: 'opacity 0.2s ease',
}}
>
<Typography variant="overline" sx={{ color: '#a5b4fc', letterSpacing: 1 }}>
Pricing & How it works
</Typography>
<Stack spacing={0.5}>
<Typography variant="body2" fontWeight={700}>
{module.pricing.estimate}
</Typography>
<Typography variant="caption" color="text.secondary">
{module.pricing.notes}
</Typography>
</Stack>
<Divider sx={{ borderColor: 'rgba(255,255,255,0.08)' }} />
<Typography variant="subtitle2" fontWeight={700}>
{module.example.title}
</Typography>
<Stack component="ul" spacing={0.5} sx={{ pl: 2, m: 0 }}>
{module.example.steps.map(step => (
<Typography
component="li"
key={step}
variant="body2"
color="text.secondary"
>
{step}
</Typography>
))}
</Stack>
<Typography variant="caption" color="text.secondary">
ETA: {module.example.eta}
</Typography>
</Box>
)}
<Stack direction="row" spacing={1} alignItems="center" mt="auto">
<Tooltip title={module.help}>
<InfoOutlinedIcon sx={{ color: 'rgba(255,255,255,0.6)', fontSize: 20 }} />
</Tooltip>
<Button
variant="contained"
disabled={disabled}
startIcon={disabled ? <LockIcon /> : <LaunchIcon />}
onClick={() => {
if (!disabled && module.route) {
onNavigate(module.route);
}
}}
sx={{
borderRadius: 999,
textTransform: 'none',
fontWeight: 700,
ml: 'auto',
background: disabled
? 'rgba(148,163,184,0.2)'
: 'linear-gradient(90deg,#7c3aed,#2563eb)',
}}
>
{disabled ? 'Coming Soon' : 'Open'}
</Button>
</Stack>
</Paper>
);
};

View File

@@ -0,0 +1,43 @@
import React from 'react';
import { Paper, Stack, Typography, Divider } from '@mui/material';
import { ModuleConfig } from './types';
export const ModuleInfoCard: React.FC<{ module: ModuleConfig }> = ({ module }) => (
<Paper
variant="outlined"
sx={{
mt: 1.5,
borderRadius: 3,
borderColor: 'rgba(255,255,255,0.12)',
backgroundColor: 'rgba(15,23,42,0.65)',
p: 2,
}}
>
<Stack spacing={1}>
<Typography variant="caption" sx={{ color: '#a5b4fc', letterSpacing: 1 }}>
Pricing & Workflow
</Typography>
<Typography variant="body2" fontWeight={600}>
{module.pricing.estimate}
</Typography>
<Typography variant="caption" color="text.secondary">
{module.pricing.notes}
</Typography>
<Divider sx={{ borderColor: 'rgba(255,255,255,0.08)' }} />
<Typography variant="subtitle2" fontWeight={700}>
{module.example.title}
</Typography>
<Stack component="ul" spacing={0.5} sx={{ pl: 2, m: 0 }}>
{module.example.steps.map(step => (
<Typography key={step} component="li" variant="body2" color="text.secondary">
{step}
</Typography>
))}
</Stack>
<Typography variant="caption" color="text.secondary">
ETA: {module.example.eta}
</Typography>
</Stack>
</Paper>
);

View File

@@ -0,0 +1,93 @@
export const createExamples = [
{
id: 'ig-hero',
label: 'Instagram hero',
prompt:
'"Cinematic coffee shop hero shot, golden hour lighting, stylish barista pouring latte art, 4k, depth of field, film grain"',
provider: 'WaveSpeed Ideogram V3 Turbo',
image:
'https://images.unsplash.com/photo-1509042239860-f550ce710b93?auto=format&fit=crop&w=1200&q=80',
description:
'Polished hero visual for carousel slides and blog headers with photorealistic signage.',
price: '$0.18',
eta: '~4s',
},
{
id: 'linkedin-thought',
label: 'LinkedIn thought-leadership',
prompt:
'"Minimalist workspace flat lay, teal gradients, AI workflow diagrams, overhead view, ultra clean, 8k render"',
provider: 'Gemini Imagen',
image:
'https://images.unsplash.com/photo-1487017159836-4e23ece2e4cf?auto=format&fit=crop&w=1200&q=80',
description: 'Clean layout for LinkedIn posts that need professional, text-friendly framing.',
price: '$0.11',
eta: '~3s',
},
{
id: 'tiktok-hook',
label: 'TikTok hook frame',
prompt:
'"Vibrant neon studio, bold typography reading Growth Hacks, 9:16 layout, dynamic lighting, energetic vibe"',
provider: 'WaveSpeed Qwen Image',
image:
'https://images.unsplash.com/photo-1504196606672-aef5c9cefc92?auto=format&fit=crop&w=1200&q=80',
description: 'High-energy vertical frame to start TikTok/Reels with bold colors and legible copy.',
price: '$0.07',
eta: '~2s',
},
];
export const upscaleSamples = {
lowRes: 'https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&w=600&q=30',
hiRes: 'https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&w=1600&q=80',
};
export const transformAssets = {
storyboard: '/images/scene_1_Welcome_to_the_Cloud_Kitchen___ae6436d9.png',
video: '/videos/scene_1_user_33Gz1FPI86V_0a5d0d71.mp4',
script:
"Welcome to the Cloud Kitchen! Meet Ava, your virtual chef companion. Let's explore how she runs three delivery brands from one AI-powered hub.",
};
export const controlAssets = {
inputImage: '/images/scene_1_Welcome_to_the_Cloud_Kitchen___ae6436d9.png',
outputVideo: '/videos/text-video-voiceover.mp4',
prompt:
"A confident woman in her 40s stands on a stage with a microphone. The background shows a large LED screen with abstract visuals. She smiles and begins speaking to the audience: \"Good evening everyone. Tonight, I want to share three powerful lessons about leadership and innovation.\" Her lip movements match her voice, and she uses expressive hand gestures while speaking.",
seed: 2133312826,
resolution: '720p',
duration: 5,
};
export const editBeforeAfter = [
{
before: 'https://images.unsplash.com/photo-1455587734955-081b22074882?auto=format&fit=crop&w=800&q=80',
after: 'https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?auto=format&fit=crop&w=800&q=80',
prompt: 'Inpainted background swap with studio lighting and relit subject',
},
{
before: 'https://images.unsplash.com/photo-1472506200026-38c43d5fbf97?auto=format&fit=crop&w=800&q=80',
after: 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?auto=format&fit=crop&w=800&q=80',
prompt: 'Recolored wardrobe + added morning haze',
},
{
before: 'https://images.unsplash.com/photo-1434389677669-e08b4cac3105?auto=format&fit=crop&w=800&q=80',
after: 'https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=800&q=80',
prompt: 'Reframed hero crop with dramatic sky replacement',
},
];
export const platformPresets = [
{ label: 'IG Feed 1:1', top: '10%', left: '5%', width: '35%', height: '35%' },
{ label: 'TikTok 9:16', top: '5%', right: '5%', width: '25%', height: '60%' },
{ label: 'LinkedIn 1.91:1', bottom: '8%', left: '10%', width: '55%', height: '25%' },
{ label: 'Pinterest 2:3', bottom: '12%', right: '8%', width: '22%', height: '30%' },
];
export const statusStyles = {
live: { label: 'Live', color: '#10b981' },
'coming soon': { label: 'Coming Soon', color: '#f97316' },
planning: { label: 'In Planning', color: '#d1d5db' },
};

View File

@@ -0,0 +1,7 @@
export * from './types';
export * from './constants';
export { ModuleInfoCard } from './ModuleInfoCard';
export { ModuleCard } from './ModuleCard';
export { studioModules } from './modules';
export * from './previews';

View File

@@ -0,0 +1,208 @@
import React from 'react';
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
import BrushIcon from '@mui/icons-material/Brush';
import UpgradeIcon from '@mui/icons-material/Upgrade';
import TransformIcon from '@mui/icons-material/Transform';
import ShareIcon from '@mui/icons-material/Share';
import EditNoteIcon from '@mui/icons-material/EditNote';
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
import { ModuleConfig } from './types';
export const studioModules: ModuleConfig[] = [
{
key: 'create',
title: 'Create Studio',
subtitle: 'Text-to-image generation',
description:
'Generate photorealistic visuals with Stability, WaveSpeed, HuggingFace, and Gemini. Templates, smart providers, and enterprise prompt controls included.',
highlights: ['Smart provider routing', 'Platform templates', 'Cost preview'],
status: 'live',
route: '/image-generator',
icon: <AutoAwesomeIcon />,
help: 'Ideal for blog headers, social posts, ad creatives, and brand assets.',
pricing: {
estimate: '$0.12 - $0.48 / image (credit aware)',
notes: 'Auto-select suggests lowest-cost provider before generation.',
},
example: {
title: 'Instagram carousel hero image',
steps: [
'Choose Instagram template + 4:5 ratio',
'Prompt helper enriches "fall coffee launch" copy',
'Preview cost/time → generate 3 variations',
],
eta: '~4s per variation',
},
},
{
key: 'edit',
title: 'Edit Studio',
subtitle: 'AI-powered editing',
description:
'Remove backgrounds, inpaint, outpaint, recolor, and relight images with Stability AI workflows and Hugging Face conversational edits.',
highlights: ['Object removal', 'Canvas expansion', 'Relight + background swap'],
status: 'live',
route: '/image-editor',
icon: <BrushIcon />,
help: 'Upload existing assets and enhance them with precise AI tools.',
pricing: {
estimate: '$0.08 - $0.30 / edit (based on area + ops)',
notes: 'Bulk edits share the same upload to save credits.',
},
example: {
title: 'Replace dull background for LinkedIn hero',
steps: [
'Upload portrait → auto mask detects subject',
'Use "Replace background" preset → choose corporate loft style',
'Relight + save layered history for future tweaks',
],
eta: '~6s render',
},
},
{
key: 'upscale',
title: 'Upscale Studio',
subtitle: 'Resolution enhancement',
description:
'Fast 4x upscale, conservative 4K, and creative 4K pipelines powered by Stability AI. Perfect for print, campaigns, and hero imagery.',
highlights: ['Fast 4x mode', '4K creative', 'Side-by-side preview'],
status: 'live',
route: '/image-upscale',
icon: <UpgradeIcon />,
help: 'Upscale images to 4K-ready assets with one click.',
pricing: {
estimate: '$0.10 (Fast) · $0.32 (Creative 4K)',
notes: 'Queue batches overnight to reduce credit burn.',
},
example: {
title: 'Print-ready hero panel',
steps: [
'Upload 1024 hero → auto-detect recommends Creative 4K',
'Preview side-by-side → confirm texture preservation',
'Schedule overnight batch with 6 variants',
],
eta: 'Fast = 1s · 4K = 6s',
},
},
{
key: 'transform',
title: 'Transform Studio',
subtitle: 'Image → Video / Avatar / 3D',
description:
'WaveSpeed WAN 2.5 (image-to-video), Hunyuan Avatar, and Stable Fast 3D to convert images into motion, avatars, or 3D assets.',
highlights: ['Image-to-video', 'Talking avatars', '3D export'],
status: 'coming soon',
icon: <TransformIcon />,
help: 'Designed for campaign teasers, explainers, and immersive media.',
pricing: {
estimate: '$0.50 (10s video 480p) · $3.60 (avatar 2 min)',
notes: 'Text-to-speech add-on billed separately per 15s.',
},
example: {
title: 'Product launch teaser video',
steps: [
'Pick motion preset "Medium pan + glow"',
'Upload hero shot + 8s script for TTS',
'Preview storyboard → export 1080p MP4',
],
eta: '~15s generation',
},
},
{
key: 'optimizer',
title: 'Social Optimizer',
subtitle: 'Platform-ready exports',
description:
'Smart resize, safe zones, and engagement tips for Instagram, TikTok, LinkedIn, YouTube, Pinterest, and more in one click.',
highlights: ['Text safe zones', 'Batch export', 'Platform presets'],
status: 'planning',
icon: <ShareIcon />,
help: 'Ship consistent assets across every social surface.',
pricing: {
estimate: '$0.02 - $0.06 / rendition',
notes: 'Unlimited exports on Pro + Enterprise tiers.',
},
example: {
title: 'One hero → 6 platform exports',
steps: [
'Add source image → auto-detect focal subject',
'Select IG, TikTok, LinkedIn, Pinterest presets',
'Review safe zones overlay → export ZIP + schedule',
],
eta: '~2s / platform',
},
},
{
key: 'control',
title: 'Control Studio',
subtitle: 'Sketch, structure & style',
description:
'Sketch-to-image, structure control, and advanced style transfer so creative directors can steer outputs precisely.',
highlights: ['Sketch control', 'Style libraries', 'Strength sliders'],
status: 'planning',
icon: <EditNoteIcon />,
help: 'For art directors who need total control over AI outputs.',
pricing: {
estimate: '$0.20 / render with dual-control',
notes: 'Saved reference boards reuse controls at $0.05.',
},
example: {
title: 'Storyboard consistency pack',
steps: [
'Upload wireframe + art-style JPEG',
'Set control strength 60% structure / 40% style',
'Generate 8 shots → auto-tag to Asset Library',
],
eta: '~8s per shot',
},
},
{
key: 'batch',
title: 'Batch Processor',
subtitle: 'Scale campaigns',
description:
'Queue generators, edits, upscales, and exports for entire campaigns with cost previews, scheduling, and monitoring.',
highlights: ['Bulk prompts', 'Usage tracking', 'Schedule windows'],
status: 'planning',
icon: <LibraryBooksIcon />,
help: 'Turn one brief into dozens of deliverables automatically.',
pricing: {
estimate: 'Dynamic · e.g. 25-image pack ≈ $9',
notes: 'Warns when batch exceeds remaining credits.',
},
example: {
title: 'Evergreen blog refresh',
steps: [
'Upload CSV prompts grouped by persona',
'Assign module per row (Create, Edit, Upscale)',
'Schedule weekend window + email digest',
],
eta: 'Depends on queue size',
},
},
{
key: 'library',
title: 'Asset Library',
subtitle: 'Searchable visual archive',
description:
'AI-tagged collections, favorites, history, and collaboration. Filters by platform, persona, use case, or campaign.',
highlights: ['AI tagging', 'Version history', 'Shareable collections'],
status: 'planning',
icon: <LibraryBooksIcon />,
help: 'Centralize every visual produced inside ALwrity.',
pricing: {
estimate: 'Included in tier · extra storage $5 / 100GB',
notes: 'Enterprise adds S3 export + governance logs.',
},
example: {
title: 'Campaign war-room board',
steps: [
'Filter by persona + platform → pin hero assets',
'Share read-only board with agency partner',
'Track usage + cost per asset inside analytics tab',
],
eta: 'Instant search (<500ms)',
},
},
];

View File

@@ -0,0 +1,122 @@
import React from 'react';
import { Box, Stack, Typography, Chip, Button } from '@mui/material';
import { controlAssets } from '../constants';
export const ControlEffectPreview: React.FC = () => {
const [videoKey, setVideoKey] = React.useState(0);
return (
<Box
sx={{
mt: 2,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.08)',
background: 'rgba(15,23,42,0.5)',
p: { xs: 2, md: 3 },
}}
>
<Stack direction={{ xs: 'column', md: 'row' }} spacing={2} alignItems="stretch">
<Box
sx={{
flex: 1,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.12)',
background: 'linear-gradient(135deg,#8b5cf6,#a855f7)',
color: '#f3e8ff',
p: 2,
display: 'flex',
flexDirection: 'column',
gap: 1.5,
}}
>
<Typography variant="overline" sx={{ letterSpacing: 2, color: '#e9d5ff' }}>
Control Input
</Typography>
<Box
component="img"
src={controlAssets.inputImage}
alt="Control reference"
sx={{ width: '100%', borderRadius: 2, border: '2px solid rgba(255,255,255,0.2)', boxShadow: '0 10px 25px rgba(139,92,246,0.3)' }}
/>
<Stack spacing={1}>
<Typography variant="caption" sx={{ color: '#e9d5ff', fontWeight: 600 }}>
Prompt
</Typography>
<Typography variant="body2" sx={{ fontSize: '0.875rem', lineHeight: 1.5 }}>
{controlAssets.prompt}
</Typography>
<Stack direction="row" spacing={1} flexWrap="wrap">
<Chip
size="small"
label={`Seed ${controlAssets.seed}`}
sx={{ background: 'rgba(255,255,255,0.2)', color: '#0f172a', borderRadius: 999 }}
/>
<Chip
size="small"
label={controlAssets.resolution}
sx={{ background: 'rgba(255,255,255,0.2)', color: '#0f172a', borderRadius: 999 }}
/>
<Chip
size="small"
label={`${controlAssets.duration}s`}
sx={{ background: 'rgba(255,255,255,0.2)', color: '#0f172a', borderRadius: 999 }}
/>
</Stack>
</Stack>
</Box>
<Box
sx={{
flex: 1.5,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.12)',
background: '#020617',
p: { xs: 1, md: 2 },
}}
>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 1 }}>
<Typography variant="overline" sx={{ letterSpacing: 2, color: '#a78bfa' }}>
Generated Output
</Typography>
<Chip
label="WAN 2.5"
size="small"
sx={{ background: 'rgba(167,139,250,0.15)', color: '#a78bfa', borderRadius: 999 }}
/>
<Button size="small" onClick={() => setVideoKey(prev => prev + 1)} sx={{ ml: 'auto', color: '#a78bfa', textTransform: 'none' }}>
Reset preview
</Button>
</Stack>
<Box
sx={{
borderRadius: 2,
overflow: 'hidden',
border: '1px solid rgba(255,255,255,0.08)',
position: 'relative',
}}
>
<video key={videoKey} controls poster={controlAssets.inputImage} style={{ width: '100%', display: 'block' }} src={controlAssets.outputVideo} />
<Box
sx={{
position: 'absolute',
top: 12,
left: 12,
background: 'rgba(15,23,42,0.7)',
borderRadius: 999,
px: 1.5,
py: 0.5,
color: '#f8fafc',
fontSize: 12,
}}
>
Voiceover · {controlAssets.duration}s
</Box>
</Box>
</Box>
</Stack>
<Typography variant="caption" color="text.secondary" sx={{ mt: 1.5 }}>
Alibaba WAN 2.5 converts text or images into videos (480p/720p/1080p) with synced audio, faster and more affordable than Google Veo3.
</Typography>
</Box>
);
};

View File

@@ -0,0 +1,116 @@
import React from 'react';
import { Box, Stack, Typography, Chip } from '@mui/material';
import { createExamples } from '../constants';
export const CreateEffectPreview: React.FC = () => {
const [textHovered, setTextHovered] = React.useState(false);
const [exampleIndex, setExampleIndex] = React.useState(0);
const example = createExamples[exampleIndex];
const imageWidth = textHovered ? '20%' : '70%';
const textWidth = textHovered ? '80%' : '30%';
return (
<Box
sx={{
borderRadius: 3,
border: '3px solid',
borderImage:
'linear-gradient(135deg, rgba(124,58,237,0.8), rgba(14,165,233,0.8), rgba(16,185,129,0.8)) 1',
overflow: 'hidden',
height: { xs: 240, md: 280 },
display: 'flex',
background: '#0f172a',
mt: 1,
}}
>
<Box
sx={{
flex: '0 0 auto',
width: imageWidth,
transition: 'width 0.4s ease, filter 0.4s ease',
backgroundImage: `url(${example.image})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
filter: textHovered ? 'saturate(1.1)' : 'saturate(1)',
position: 'relative',
}}
>
<Stack
direction="row"
spacing={1}
sx={{
position: 'absolute',
bottom: 16,
left: '50%',
transform: 'translateX(-50%)',
background: 'rgba(15,23,42,0.8)',
borderRadius: 999,
px: 1.5,
py: 0.5,
boxShadow: '0 10px 20px rgba(2,6,23,0.45)',
}}
>
{createExamples.map((_, idx) => (
<Box
key={_.id}
onClick={() => setExampleIndex(idx)}
sx={{
width: 32,
height: 10,
borderRadius: 999,
background: idx === exampleIndex ? '#c4b5fd' : 'rgba(255,255,255,0.3)',
cursor: 'pointer',
transition: 'background 0.2s ease',
}}
/>
))}
</Stack>
</Box>
<Box
sx={{
flex: '0 0 auto',
width: textWidth,
background: 'rgba(248,250,252,0.95)',
color: '#0f172a',
p: 3,
display: 'flex',
flexDirection: 'column',
gap: 1,
boxShadow: '-12px 0 24px rgba(15,23,42,0.25)',
transition: 'width 0.4s ease',
}}
onMouseEnter={() => setTextHovered(true)}
onMouseLeave={() => setTextHovered(false)}
>
<Stack spacing={0.5} sx={{ overflowY: textHovered ? 'auto' : 'hidden', pr: 1 }}>
<Typography variant="overline" sx={{ letterSpacing: 1.5, color: '#818cf8' }}>
{example.label}
</Typography>
<Typography variant="subtitle2" fontWeight={700}>
Prompt
</Typography>
<Typography variant="body2">{example.prompt}</Typography>
<Typography variant="body2">{example.description}</Typography>
<Stack direction="row" spacing={1} flexWrap="wrap">
<Chip
size="small"
label={`Price ${example.price}`}
sx={{ background: '#ede9fe', color: '#4c1d95', borderRadius: 999, fontWeight: 600 }}
/>
<Chip
size="small"
label={`Turnaround ${example.eta}`}
sx={{ background: '#cffafe', color: '#0f766e', borderRadius: 999, fontWeight: 600 }}
/>
<Chip
size="small"
label={example.provider}
sx={{ background: '#dcfce7', color: '#166534', borderRadius: 999, fontWeight: 600 }}
/>
</Stack>
</Stack>
</Box>
</Box>
);
};

View File

@@ -0,0 +1,134 @@
import React from 'react';
import { Box, Stack, Typography, Chip, Tooltip } from '@mui/material';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import { editBeforeAfter } from '../constants';
export const EditEffectPreview: React.FC = () => {
const [exampleIndex, setExampleIndex] = React.useState(0);
const pair = editBeforeAfter[exampleIndex];
return (
<Box
sx={{
mt: 2,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.08)',
background: 'rgba(15,23,42,0.5)',
p: 2,
}}
>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 2 }}>
<Typography variant="overline" sx={{ color: '#fcd34d', letterSpacing: 2 }}>
Before After
</Typography>
<Tooltip
title={
<Stack spacing={1}>
<Typography variant="body2">
Hover to reveal the original upload vs. AI-edited output. Perfect for showing background swaps,
inpainting, or relighting.
</Typography>
<Stack direction="row" spacing={1} flexWrap="wrap">
{['Erase objects cleanly', 'Smart relight', 'Replace backgrounds'].map(label => (
<Chip
key={label}
size="small"
label={label}
sx={{ background: 'rgba(236,252,203,0.12)', color: '#fef3c7', borderRadius: 999 }}
/>
))}
</Stack>
</Stack>
}
>
<InfoOutlinedIcon sx={{ fontSize: 18, color: 'rgba(252,211,77,0.85)', cursor: 'pointer' }} />
</Tooltip>
</Stack>
<Box
sx={{
'--gap': '8px',
display: 'grid',
position: 'relative',
width: '100%',
borderRadius: 3,
overflow: 'hidden',
border: '4px solid #22d3ee',
minHeight: { xs: 260, md: 300 },
'& > img': {
'--progress': 'calc(-1 * var(--gap))',
gridArea: '1 / 1',
width: '100%',
height: '100%',
objectFit: 'cover',
transition: 'clip-path 0.4s 0.1s',
},
'& > img:first-of-type': {
clipPath: 'polygon(0 0, calc(100% + var(--progress)) 0, 0 calc(100% + var(--progress)))',
},
'& > img:last-of-type': {
clipPath: 'polygon(100% 100%, 100% calc(0% - var(--progress)), calc(0% - var(--progress)) 100%)',
},
'&:hover > img:last-of-type, &:hover > img:first-of-type:hover': {
'--progress': 'calc(50% - var(--gap))',
},
'&:hover > img:first-of-type, &:hover > img:first-of-type:hover + img': {
'--progress': 'calc(-50% - var(--gap))',
},
}}
>
<Box component="img" src={pair.before} alt="Original asset" />
<Box component="img" src={pair.after} alt="Edited asset" />
<Stack
direction="row"
spacing={1}
sx={{
position: 'absolute',
top: 12,
right: 12,
background: 'rgba(15,23,42,0.8)',
borderRadius: 999,
px: 1,
py: 0.5,
boxShadow: '0 10px 20px rgba(2,6,23,0.5)',
}}
>
{editBeforeAfter.map((_, idx) => (
<Box
key={idx}
onClick={() => setExampleIndex(idx)}
sx={{
width: 10,
height: 10,
borderRadius: '50%',
background: idx === exampleIndex ? '#f472b6' : 'rgba(255,255,255,0.4)',
cursor: 'pointer',
}}
/>
))}
</Stack>
<Stack
direction="row"
spacing={1}
sx={{
position: 'absolute',
bottom: 12,
left: '50%',
transform: 'translateX(-50%)',
background: 'rgba(15,23,42,0.85)',
px: 1.5,
py: 0.75,
borderRadius: 999,
boxShadow: '0 10px 25px rgba(2,6,23,0.6)',
}}
>
<Chip label="Original" size="small" sx={{ background: '#fef3c7', color: '#78350f', fontWeight: 600 }} />
<Chip label="Edited" size="small" sx={{ background: '#a5b4fc', color: '#1e1b4b', fontWeight: 600 }} />
</Stack>
</Box>
<Typography variant="caption" color="text.secondary" sx={{ mt: 1.5 }}>
Prompt used: {pair.prompt}
</Typography>
</Box>
);
};

View File

@@ -0,0 +1,78 @@
import React from 'react';
import { Box, Stack, Typography, Chip } from '@mui/material';
import { transformAssets, platformPresets } from '../constants';
export const SocialOptimizerEffectPreview: React.FC = () => (
<Box
sx={{
mt: 2,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.08)',
background: 'rgba(15,23,42,0.5)',
p: { xs: 2, md: 3 },
}}
>
<Typography variant="overline" sx={{ letterSpacing: 2, color: '#fcd34d' }}>
Platform Auto-Crop
</Typography>
<Typography variant="body2" color="text.secondary">
Smart resize finds the focal point and generates safe-zone aware crops for every surface.
</Typography>
<Box
sx={{
mt: 2,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.1)',
background: '#020617',
p: 2,
position: 'relative',
minHeight: 280,
overflow: 'hidden',
}}
>
<Box
component="img"
src={transformAssets.storyboard}
alt="Source creative"
sx={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 2, filter: 'brightness(0.8)' }}
/>
{platformPresets.map(frame => (
<Box
key={frame.label}
sx={{
position: 'absolute',
border: '2px solid rgba(248,250,252,0.8)',
borderRadius: 2,
boxShadow: '0 10px 20px rgba(2,6,23,0.45)',
transition: 'transform 0.2s ease',
cursor: 'pointer',
'&:hover': { transform: 'scale(1.05)' },
...frame,
}}
>
<Box
sx={{
position: 'absolute',
top: -24,
left: 0,
background: 'rgba(15,23,42,0.85)',
color: '#f8fafc',
px: 1,
py: 0.25,
borderRadius: 999,
fontSize: 11,
}}
>
{frame.label}
</Box>
</Box>
))}
</Box>
<Stack direction="row" spacing={1} flexWrap="wrap" sx={{ mt: 2 }}>
{['Safe zones', 'Focal cropping', 'Batch export'].map(label => (
<Chip key={label} size="small" label={label} sx={{ background: 'rgba(15,118,110,0.2)', color: '#5eead4', borderRadius: 999 }} />
))}
</Stack>
</Box>
);

View File

@@ -0,0 +1,114 @@
import React from 'react';
import { Box, Stack, Typography, Chip, Button } from '@mui/material';
import { transformAssets } from '../constants';
export const TransformEffectPreview: React.FC = () => {
const [videoKey, setVideoKey] = React.useState(0);
return (
<Box
sx={{
mt: 2,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.08)',
background: 'rgba(15,23,42,0.5)',
p: { xs: 2, md: 3 },
}}
>
<Stack direction={{ xs: 'column', md: 'row' }} spacing={2} alignItems="stretch">
<Box
sx={{
flex: 1,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.12)',
background: 'linear-gradient(135deg,#0ea5e9,#6366f1)',
color: '#e0f2fe',
p: 2,
minHeight: 260,
display: 'flex',
flexDirection: 'column',
gap: 1.2,
}}
>
<Typography variant="overline" sx={{ letterSpacing: 2, color: '#cffafe' }}>
Storyboard Prompt
</Typography>
<Typography variant="body2">{transformAssets.script}</Typography>
<Stack direction="row" spacing={1} flexWrap="wrap">
{['Image-to-video', 'WAN 2.5', '10s duration'].map(label => (
<Chip
key={label}
size="small"
label={label}
sx={{ background: 'rgba(255,255,255,0.2)', color: '#0f172a', borderRadius: 999 }}
/>
))}
</Stack>
<Box
sx={{
mt: 'auto',
borderRadius: 2,
overflow: 'hidden',
border: '1px solid rgba(255,255,255,0.25)',
boxShadow: '0 20px 45px rgba(2,6,23,0.45)',
}}
>
<Box component="img" src={transformAssets.storyboard} alt="Storyboard still" sx={{ width: '100%', display: 'block' }} />
</Box>
</Box>
<Box
sx={{
flex: 1.5,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.12)',
background: '#020617',
p: { xs: 1, md: 2 },
}}
>
<Stack direction="row" spacing={1} alignItems="center" sx={{ mb: 1 }}>
<Typography variant="overline" sx={{ letterSpacing: 2, color: '#38bdf8' }}>
Render Preview
</Typography>
<Chip
label="1080p"
size="small"
sx={{ background: 'rgba(56,189,248,0.15)', color: '#38bdf8', borderRadius: 999 }}
/>
<Button size="small" onClick={() => setVideoKey(prev => prev + 1)} sx={{ ml: 'auto', color: '#38bdf8', textTransform: 'none' }}>
Reset preview
</Button>
</Stack>
<Box
sx={{
borderRadius: 2,
overflow: 'hidden',
border: '1px solid rgba(255,255,255,0.08)',
position: 'relative',
}}
>
<video key={videoKey} controls poster={transformAssets.storyboard} style={{ width: '100%', display: 'block' }} src={transformAssets.video} />
<Box
sx={{
position: 'absolute',
top: 12,
left: 12,
background: 'rgba(15,23,42,0.7)',
borderRadius: 999,
px: 1.5,
py: 0.5,
color: '#f8fafc',
fontSize: 12,
}}
>
Scene 1 · Cloud Kitchen
</Box>
</Box>
</Box>
</Stack>
<Typography variant="caption" color="text.secondary" sx={{ mt: 1.5 }}>
Convert hero images into narrated clips with motion presets, subtitles, and audio uploads.
</Typography>
</Box>
);
};

View File

@@ -0,0 +1,107 @@
import React from 'react';
import { Box, Stack, Typography, Chip } from '@mui/material';
import { upscaleSamples } from '../constants';
export const UpscaleEffectPreview: React.FC = () => (
<Box
sx={{
mt: 2,
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.08)',
background: 'rgba(15,23,42,0.5)',
p: { xs: 2, md: 3 },
}}
>
<Stack direction="row" spacing={1} alignItems="center" justifyContent="space-between">
<Box>
<Typography variant="overline" sx={{ letterSpacing: 2, color: '#f9a8d4' }}>
4× Upscale Showcase
</Typography>
<Typography variant="body2" color="text.secondary">
Flip the panels to compare the low-res upload with the 4K-ready output.
</Typography>
</Box>
<Chip
label="Fast vs Creative"
size="small"
sx={{ background: 'rgba(236,72,153,0.15)', color: '#f9a8d4', borderRadius: 999 }}
/>
</Stack>
<Box
sx={{
mt: 2,
display: 'flex',
gap: 2,
justifyContent: 'center',
flexWrap: 'wrap',
'&:hover .flip-left': { transform: 'rotateY(-180deg)' },
'&:hover .flip-right': { transform: 'rotateY(180deg)' },
}}
>
{[
{ key: 'low', label: 'Before 600×400', className: 'flip-left', image: upscaleSamples.lowRes },
{ key: 'high', label: 'After 2400×1600', className: 'flip-right', image: upscaleSamples.hiRes },
].map(card => (
<Box key={card.key} sx={{ perspective: 1000, width: { xs: 140, sm: 180 }, height: { xs: 200, sm: 240 } }}>
<Box
className={card.className}
sx={{ position: 'relative', width: '100%', height: '100%', transition: '0.6s', transformStyle: 'preserve-3d' }}
>
<Box
className="front"
sx={{
position: 'absolute',
inset: 0,
backfaceVisibility: 'hidden',
borderRadius: 3,
border: '1px solid rgba(255,255,255,0.1)',
background:
card.key === 'low'
? 'linear-gradient(135deg,#4c1d95,#9333ea)'
: 'linear-gradient(135deg,#0f766e,#14b8a6)',
display: 'flex',
alignItems: 'center',
justifyContent: card.key === 'low' ? 'flex-end' : 'flex-start',
px: 2,
color: '#fff',
}}
>
<Box
sx={{
width: 80,
height: 80,
borderRadius: '50%',
background: 'rgba(255,255,255,0.2)',
border: '2px solid rgba(255,255,255,0.8)',
}}
/>
<Typography variant="caption" sx={{ ml: card.key === 'low' ? -6 : 2, mr: card.key === 'low' ? 2 : -6 }}>
{card.label}
</Typography>
</Box>
<Box
className="back"
sx={{
position: 'absolute',
inset: 0,
backfaceVisibility: 'hidden',
borderRadius: 3,
transform: 'rotateY(180deg)',
overflow: 'hidden',
border: '1px solid rgba(255,255,255,0.15)',
}}
>
<Box component="img" src={card.image} alt={card.label} sx={{ width: '100%', height: '100%', objectFit: 'cover' }} />
</Box>
</Box>
</Box>
))}
</Box>
<Typography variant="caption" color="text.secondary" sx={{ mt: 1.5 }}>
Try creative upscaling for texture enhancement, or fast mode for previews.
</Typography>
</Box>
);

View File

@@ -0,0 +1,7 @@
export { CreateEffectPreview } from './CreateEffectPreview';
export { EditEffectPreview } from './EditEffectPreview';
export { UpscaleEffectPreview } from './UpscaleEffectPreview';
export { TransformEffectPreview } from './TransformEffectPreview';
export { SocialOptimizerEffectPreview } from './SocialOptimizerEffectPreview';
export { ControlEffectPreview } from './ControlEffectPreview';

View File

@@ -0,0 +1,25 @@
import React from 'react';
export type ModuleStatus = 'live' | 'coming soon' | 'planning';
export type ModuleConfig = {
key: string;
title: string;
subtitle: string;
description: string;
highlights: string[];
status: ModuleStatus;
route?: string;
icon: React.ReactNode;
help: string;
pricing: {
estimate: string;
notes: string;
};
example: {
title: string;
steps: string[];
eta: string;
};
};