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,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';