aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
734 lines (731 loc) • 29.1 kB
JavaScript
'use client';
import { jsxs, jsx } from 'react/jsx-runtime';
import { useReducedMotion } from '../../hooks/useReducedMotion.js';
import { motion } from 'framer-motion';
import { forwardRef, useState, useRef, useCallback, useEffect } from 'react';
import { useMotionPreference } from '../../hooks/useMotionPreference.js';
import '../../primitives/GlassCore.js';
import '../../primitives/glass/GlassAdvanced.js';
import { OptimizedGlassCore } from '../../primitives/OptimizedGlassCore.js';
import '../../primitives/glass/OptimizedGlassAdvanced.js';
import '../../primitives/MotionNative.js';
import '../../primitives/motion/MotionFramer.js';
import { useA11yId } from '../../utils/a11y.js';
import { createGlassStyle } from '../../utils/createGlassStyle.js';
import { useGlassSound } from '../../utils/soundDesign.js';
const defaultModels = [{
id: "stylegan2-faces",
name: "StyleGAN2 Faces",
description: "High-quality human face generation",
type: "stylegan",
category: "faces",
resolution: 1024,
latentDim: 512,
trained: true
}, {
id: "dcgan-art",
name: "DCGAN Art",
description: "Abstract art generation",
type: "dcgan",
category: "art",
resolution: 256,
latentDim: 100,
trained: true
}, {
id: "biggan-objects",
name: "BigGAN Objects",
description: "Conditional object generation",
type: "biggan",
category: "objects",
resolution: 512,
latentDim: 128,
trained: true
}, {
id: "cyclegan-style",
name: "CycleGAN Style Transfer",
description: "Unpaired image-to-image translation",
type: "cyclegan",
category: "style_transfer",
resolution: 256,
latentDim: 256,
trained: true
}, {
id: "progressive-landscapes",
name: "Progressive Landscapes",
description: "Landscape scene generation",
type: "progressive",
category: "landscapes",
resolution: 512,
latentDim: 256,
trained: true
}, {
id: "stylegan3-general",
name: "StyleGAN3 General",
description: "General purpose image generation",
type: "stylegan",
category: "general",
resolution: 512,
latentDim: 512,
trained: false
}];
const defaultGenerationParams = {
seed: 42,
truncation: 0.7,
styleStrength: 1.0,
noiseStrength: 0.5,
batchSize: 4,
interpolationSteps: 10
};
const defaultTrainingConfig = {
epochs: 100,
batchSize: 32,
learningRate: 0.0002,
beta1: 0.5,
beta2: 0.999,
discriminatorSteps: 1,
generatorSteps: 1
};
const GlassGANGenerator = /*#__PURE__*/forwardRef(({
availableModels = defaultModels,
selectedModel = "stylegan2-faces",
generationParams = {},
trainingConfig = {},
showModelSelector = true,
showGenerationControls = true,
showTrainingControls = true,
showLatentSpace = true,
showProgress = true,
enableInterpolation = true,
enableRealTime = false,
maxGenerations = 16,
canvasWidth = 256,
canvasHeight = 256,
onModelSelect,
onGenerate,
onTrainingProgress,
className = "",
...props
}, ref) => {
const prefersReducedMotion = useReducedMotion();
const [isGenerating, setIsGenerating] = useState(false);
const [isTraining, setIsTraining] = useState(false);
const [currentModel, setCurrentModel] = useState(selectedModel);
const [generatedImages, setGeneratedImages] = useState([]);
const [latentVectors, setLatentVectors] = useState([]);
const [trainingProgress, setTrainingProgress] = useState({
epoch: 0,
generatorLoss: 0,
discriminatorLoss: 0
});
const [interpolationImages, setInterpolationImages] = useState([]);
const [generationProgress, setGenerationProgress] = useState(0);
const [params, setParams] = useState({
...defaultGenerationParams,
...generationParams
});
const [training, setTraining] = useState({
...defaultTrainingConfig,
...trainingConfig
});
useRef([]);
const latentSpaceCanvasRef = useRef(null);
useRef(null);
useA11yId("glass-gan-generator");
const {
shouldAnimate
} = useMotionPreference();
const {
play
} = useGlassSound();
// Get selected model
const model = availableModels.find(m => m.id === currentModel) || availableModels[0];
// Generate random latent vector
const generateLatentVector = useCallback(dim => {
return Array.from({
length: dim
}, () => (Math.random() - 0.5) * 2);
}, []);
// Simulate GAN generation
const generateGANImage = useCallback((latentVector, model, seed) => {
const canvas = document.createElement("canvas");
canvas.width = model.resolution;
canvas.height = model.resolution;
const ctx = canvas.getContext("2d");
if (!ctx) return "";
// Create different patterns based on GAN type
const imageData = ctx.createImageData(canvas.width, canvas.height);
const data = imageData.data;
switch (model.type) {
case "stylegan":
// StyleGAN-like high quality patterns
for (let y = 0; y < canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const i = (y * canvas.width + x) * 4;
// Use latent vector to influence generation
const latentInfluence = latentVector.slice(0, 8).reduce((sum, val) => sum + val, 0) / 8;
const nx = (x / canvas.width - 0.5) * 2;
const ny = (y / canvas.height - 0.5) * 2;
if (model.category === "faces") {
// Face-like patterns
const faceShape = Math.exp(-(nx * nx + ny * ny * 0.8) * 2);
const detail = Math.sin(nx * 10) * Math.cos(ny * 10) * 0.1;
data[i] = Math.floor((0.8 + latentInfluence * 0.2 + detail) * faceShape * 255);
data[i + 1] = Math.floor((0.7 + latentInfluence * 0.3 + detail) * faceShape * 255);
data[i + 2] = Math.floor((0.6 + latentInfluence * 0.4 + detail) * faceShape * 255);
data[i + 3] = 255;
} else {
// General patterns
const pattern = Math.sin(nx * 5 + latentInfluence) * Math.cos(ny * 5 + latentInfluence);
data[i] = Math.floor((pattern + 1) * 128);
data[i + 1] = Math.floor((Math.sin(pattern * 2) + 1) * 128);
data[i + 2] = Math.floor((Math.cos(pattern * 3) + 1) * 128);
data[i + 3] = 255;
}
}
}
break;
case "dcgan":
// DCGAN-like artistic patterns
for (let y = 0; y < canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const i = (y * canvas.width + x) * 4;
const latentSum = latentVector.slice(0, 5).reduce((sum, val) => sum + val, 0);
const freq = 0.02 * (1 + latentSum * 0.1);
const r = Math.sin(x * freq) * Math.cos(y * freq);
const g = Math.sin((x + y) * freq * 0.8);
const b = Math.cos((x - y) * freq * 1.2);
data[i] = Math.floor((r + 1) * 128);
data[i + 1] = Math.floor((g + 1) * 128);
data[i + 2] = Math.floor((b + 1) * 128);
data[i + 3] = 255;
}
}
break;
case "biggan":
// BigGAN-like class-conditional patterns
for (let y = 0; y < canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const i = (y * canvas.width + x) * 4;
const classVector = latentVector.slice(-10);
const dominantClass = Math.floor(Math.abs(classVector[0]) * 10);
const colors = [[255, 100, 100], [100, 255, 100], [100, 100, 255], [255, 255, 100], [255, 100, 255], [100, 255, 255], [200, 150, 100], [150, 100, 200], [100, 200, 150], [180, 180, 180]];
const color = colors[dominantClass] || [128, 128, 128];
const noise = (Math.random() - 0.5) * 50;
data[i] = Math.max(0, Math.min(255, color[0] + noise));
data[i + 1] = Math.max(0, Math.min(255, color[1] + noise));
data[i + 2] = Math.max(0, Math.min(255, color[2] + noise));
data[i + 3] = 255;
}
}
break;
default:
// Default pattern
for (let y = 0; y < canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const i = (y * canvas.width + x) * 4;
const pattern = latentVector.slice(0, 3).reduce((sum, val, idx) => {
return sum + val * Math.sin((x + y) * 0.01 * (idx + 1));
}, 0);
data[i] = Math.floor((Math.sin(pattern) + 1) * 128);
data[i + 1] = Math.floor((Math.cos(pattern * 1.1) + 1) * 128);
data[i + 2] = Math.floor((Math.sin(pattern * 0.9) + 1) * 128);
data[i + 3] = 255;
}
}
}
ctx.putImageData(imageData, 0, 0);
return canvas.toDataURL();
}, []);
// Generate batch of images
const generateImages = useCallback(async () => {
if (!model.trained) {
play("error");
return;
}
setIsGenerating(true);
setGenerationProgress(0);
play("processing");
const newImages = [];
const newLatentVectors = [];
for (let i = 0; i < params.batchSize; i++) {
setGenerationProgress(i / params.batchSize * 100);
// Generate latent vector
const latentVector = generateLatentVector(model.latentDim);
// Apply truncation trick
const truncatedVector = latentVector.map(val => val * params.truncation);
// Generate image
const imageUrl = generateGANImage(truncatedVector, model, params.seed + i);
newImages.push(imageUrl);
newLatentVectors.push(truncatedVector);
// Add delay for realistic generation time
await new Promise(resolve => setTimeout(resolve, 200));
}
setGeneratedImages(prev => [...newImages, ...prev].slice(0, maxGenerations));
setLatentVectors(prev => [...newLatentVectors, ...prev].slice(0, maxGenerations));
setGenerationProgress(100);
onGenerate?.(newImages, params);
setIsGenerating(false);
play("success");
}, [model, params, generateLatentVector, generateGANImage, maxGenerations, onGenerate, play]);
// Generate interpolation between two latent vectors
const generateInterpolation = useCallback(async () => {
if (latentVectors.length < 2) return;
const vec1 = latentVectors[0];
const vec2 = latentVectors[1];
const steps = params.interpolationSteps;
const interpolatedImages = [];
for (let i = 0; i <= steps; i++) {
const t = i / steps;
const interpolatedVector = vec1.map((val, idx) => val * (1 - t) + vec2[idx] * t);
const imageUrl = generateGANImage(interpolatedVector, model, params.seed);
interpolatedImages.push(imageUrl);
}
setInterpolationImages(interpolatedImages);
}, [latentVectors, params.interpolationSteps, params.seed, generateGANImage, model]);
// Simulate model training
const trainModel = useCallback(async () => {
if (!model) return;
setIsTraining(true);
play("processing");
for (let epoch = 0; epoch < training.epochs; epoch++) {
// Simulate training step
const generatorLoss = 1.0 + Math.random() * 0.5 - epoch * 0.01;
const discriminatorLoss = 0.8 + Math.random() * 0.3 - epoch * 0.005;
setTrainingProgress({
epoch: epoch + 1,
generatorLoss: Math.max(0.1, generatorLoss),
discriminatorLoss: Math.max(0.1, discriminatorLoss)
});
onTrainingProgress?.(epoch + 1, {
generator: generatorLoss,
discriminator: discriminatorLoss
});
await new Promise(resolve => setTimeout(resolve, 100));
}
// Mark model as trained
const modelIndex = availableModels.findIndex(m => m.id === currentModel);
if (modelIndex !== -1) {
availableModels[modelIndex].trained = true;
}
setIsTraining(false);
play("success");
}, [model, training.epochs, currentModel, availableModels, onTrainingProgress, play]);
// Visualize latent space
const visualizeLatentSpace = useCallback(() => {
const canvas = latentSpaceCanvasRef.current;
if (!canvas || latentVectors.length === 0) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw latent vectors as points in 2D projection
latentVectors.slice(0, 10).forEach((vector, idx) => {
// Project high-dimensional vector to 2D using first two dimensions
const x = (vector[0] + 2) / 4 * canvas.width;
const y = (vector[1] + 2) / 4 * canvas.height;
ctx.fillStyle = `hsl(${idx * 36}, 70%, 60%)`;
ctx.beginPath();
ctx.arc(x, y, 5, 0, Math.PI * 2);
ctx.fill();
// Draw connections between nearby points
latentVectors.slice(idx + 1, 10).forEach((otherVector, otherIdx) => {
const distance = Math.sqrt(Math.pow(vector[0] - otherVector[0], 2) + Math.pow(vector[1] - otherVector[1], 2));
if (distance < 1.0) {
const ox = (otherVector[0] + 2) / 4 * canvas.width;
const oy = (otherVector[1] + 2) / 4 * canvas.height;
ctx.strokeStyle = `rgba(255, 255, 255, ${0.3 * (1 - distance)})`;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(ox, oy);
ctx.stroke();
}
});
});
}, [latentVectors]);
// Handle model selection
const handleModelSelect = useCallback(modelId => {
setCurrentModel(modelId);
onModelSelect?.(modelId);
play("select");
}, [onModelSelect, play]);
// Real-time generation
useEffect(() => {
if (enableRealTime && model.trained) {
const interval = setInterval(() => {
if (!isGenerating) {
generateImages();
}
}, 5000);
return () => clearInterval(interval);
}
}, [enableRealTime, model.trained, isGenerating, generateImages]);
// Update latent space visualization
useEffect(() => {
visualizeLatentSpace();
}, [latentVectors, visualizeLatentSpace]);
const ModelSelector = () => jsxs("div", {
className: 'space-y-4',
children: [jsx("h4", {
className: 'glass-text-sm font-medium text-primary/80',
children: "GAN Models"
}), jsx("div", {
className: 'glass-grid glass-grid-cols-1 md:grid-cols-2 glass-gap-3',
children: availableModels.map(ganModel => jsx(motion.div, {
className: `
p-3 rounded-lg border cursor-pointer transition-all duration-200
${currentModel === ganModel.id ? "border-blue-400 bg-blue-400/20" : "border-white/20 hover:border-white/40 bg-white/5"}
`,
whileHover: shouldAnimate ? {
scale: 1.01
} : {},
whileTap: shouldAnimate ? {
scale: 0.99
} : {},
onClick: () => handleModelSelect(ganModel.id),
children: jsxs("div", {
className: "glass-flex glass-items-start glass-justify-between",
children: [jsxs("div", {
className: "glass-flex-1",
children: [jsxs("div", {
className: 'glass-flex glass-items-center space-x-2 mb-1',
children: [jsx("h5", {
className: 'glass-text-sm font-medium text-primary/90',
children: ganModel.name
}), ganModel.trained ? jsx("span", {
className: 'glass-px-2 glass-py-0.5 glass-surface-green/20 glass-text-secondary glass-radius glass-text-xs font-medium',
children: "Trained"
}) : jsx("span", {
className: 'glass-px-2 glass-py-0.5 glass-surface-primary/20 glass-text-secondary glass-radius glass-text-xs font-medium',
children: "Untrained"
})]
}), jsx("p", {
className: 'glass-text-xs text-primary/60 mb-2',
children: ganModel.description
}), jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between",
children: [jsxs("div", {
className: 'glass-flex glass-items-center space-x-4 glass-text-xs text-primary/50',
children: [jsxs("span", {
children: [ganModel.resolution, "px"]
}), jsxs("span", {
children: ["Z:", ganModel.latentDim]
})]
}), jsx("span", {
className: `
px-2 py-0.5 rounded text-xs font-medium
${ganModel.type === "stylegan" ? "bg-purple-500/20 text-purple-300" : ganModel.type === "dcgan" ? "bg-blue-500/20 text-blue-300" : ganModel.type === "biggan" ? "bg-green-500/20 text-green-300" : ganModel.type === "cyclegan" ? "bg-red-500/20 text-red-300" : "bg-gray-500/20 text-gray-300"}
`,
children: ganModel.type.toUpperCase()
})]
})]
}), currentModel === ganModel.id && jsx("div", {
className: 'text-primary ml-2',
children: "\u2713"
})]
})
}, ganModel.id))
})]
});
const GenerationControls = () => jsxs("div", {
className: 'space-y-4',
children: [jsx("h4", {
className: 'glass-text-sm font-medium text-primary/80',
children: "Generation Parameters"
}), jsxs("div", {
className: 'glass-grid glass-grid-cols-1 md:grid-cols-2 glass-gap-4',
children: [jsxs("div", {
children: [jsxs("label", {
className: 'block glass-text-xs text-primary/70 mb-1',
children: ["Seed: ", params.seed]
}), jsx("input", {
type: "range",
min: "0",
max: "1000",
value: params.seed,
onChange: e => setParams(prev => ({
...prev,
seed: parseInt(e.target.value)
})),
className: 'glass-w-full h-2 glass-surface-subtle/20 glass-radius-lg appearance-none cursor-pointer'
})]
}), jsxs("div", {
children: [jsxs("label", {
className: 'block glass-text-xs text-primary/70 mb-1',
children: ["Truncation: ", params.truncation.toFixed(2)]
}), jsx("input", {
type: "range",
min: "0.1",
max: "2.0",
step: "0.1",
value: params.truncation,
onChange: e => setParams(prev => ({
...prev,
truncation: parseFloat(e.target.value)
})),
className: 'glass-w-full h-2 glass-surface-subtle/20 glass-radius-lg appearance-none cursor-pointer'
})]
}), jsxs("div", {
children: [jsxs("label", {
className: 'block glass-text-xs text-primary/70 mb-1',
children: ["Style Strength: ", params.styleStrength.toFixed(2)]
}), jsx("input", {
type: "range",
min: "0.0",
max: "2.0",
step: "0.1",
value: params.styleStrength,
onChange: e => setParams(prev => ({
...prev,
styleStrength: parseFloat(e.target.value)
})),
className: 'glass-w-full h-2 glass-surface-subtle/20 glass-radius-lg appearance-none cursor-pointer'
})]
}), jsxs("div", {
children: [jsxs("label", {
className: 'block glass-text-xs text-primary/70 mb-1',
children: ["Batch Size: ", params.batchSize]
}), jsx("input", {
type: "range",
min: "1",
max: "8",
value: params.batchSize,
onChange: e => setParams(prev => ({
...prev,
batchSize: parseInt(e.target.value)
})),
className: 'glass-w-full h-2 glass-surface-subtle/20 glass-radius-lg appearance-none cursor-pointer'
})]
})]
})]
});
return jsxs(OptimizedGlassCore, {
ref: ref,
variant: "frosted",
className: `p-6 space-y-6 ${className}`,
...props,
children: [jsxs("div", {
className: "glass-flex glass-items-center glass-justify-between",
children: [jsxs("div", {
children: [jsx("h3", {
className: 'glass-text-xl font-semibold text-primary/90',
children: "GAN Generator"
}), jsx("p", {
className: 'glass-text-sm text-primary/60',
children: "Generative Adversarial Networks for image synthesis"
})]
}), jsxs("div", {
className: 'glass-flex glass-items-center space-x-2',
children: [enableRealTime && model.trained && jsxs("div", {
className: 'glass-flex glass-items-center space-x-1 text-primary',
children: [jsx("div", {
className: 'w-2 h-2 glass-surface-green glass-radius-full animate-pulse'
}), jsx("span", {
className: "glass-text-xs",
children: "Auto-gen"
})]
}), isGenerating && jsxs("div", {
className: 'glass-flex glass-items-center space-x-1 text-primary',
children: [jsx("div", {
className: 'w-4 h-4 glass-border-2 glass-border-blue glass-border-t-transparent glass-radius-full animate-spin'
}), jsx("span", {
className: "glass-text-xs",
children: "Generating..."
})]
}), isTraining && jsxs("div", {
className: 'glass-flex glass-items-center space-x-1 text-primary',
children: [jsx("div", {
className: 'w-4 h-4 glass-border-2 glass-border-orange-400 glass-border-t-transparent glass-radius-full animate-spin'
}), jsx("span", {
className: "glass-text-xs",
children: "Training..."
})]
})]
})]
}), generatedImages.length > 0 && jsxs("div", {
className: 'space-y-4',
children: [jsx("h4", {
className: 'glass-text-sm font-medium text-primary/80',
children: "Generated Images"
}), jsx("div", {
className: 'glass-grid glass-grid-cols-2 md:grid-cols-4 lg:grid-cols-6 glass-gap-3',
children: generatedImages.slice(0, maxGenerations).map((imageUrl, index) => jsxs(motion.div, {
className: 'relative aspect-square glass-radius-lg overflow-hidden glass-surface-subtle/10 group cursor-pointer',
whileHover: shouldAnimate ? {
scale: 1.05
} : {},
initial: {
opacity: 0,
scale: 0.8
},
animate: prefersReducedMotion ? {} : {
opacity: 1,
scale: 1
},
transition: prefersReducedMotion ? {
duration: 0
} : {
duration: 0.3
},
children: [jsx("img", {
src: imageUrl,
alt: `Generated ${index + 1}`,
className: 'glass-w-full glass-h-full object-cover'
}), jsx("div", {
className: 'absolute inset-0 glass-surface-dark/50 opacity-0 group-hover:opacity-100 transition-opacity glass-flex glass-items-center glass-justify-center',
children: jsx("button", {
className: 'glass-p-2 glass-surface-subtle/20 glass-radius-lg text-primary hover:glass-surface-subtle/30 transition-colors',
children: jsx("svg", {
className: 'w-4 h-4',
fill: "none",
stroke: "currentColor",
viewBox: "0 0 24 24",
children: jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
strokeWidth: 2,
d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
})
})
})
})]
}, index))
})]
}), isGenerating && showProgress && jsxs("div", {
className: `
p-3 rounded-lg border border-blue-400/30
${createGlassStyle({
blur: "sm",
opacity: 0.8
}).background}
`,
children: [jsxs("div", {
className: 'glass-flex glass-items-center glass-justify-between mb-2',
children: [jsx("span", {
className: 'glass-text-sm text-primary/80',
children: "Generating batch..."
}), jsxs("span", {
className: 'glass-text-sm font-medium text-primary',
children: [Math.round(generationProgress), "%"]
})]
}), jsx("div", {
className: 'glass-w-full glass-surface-subtle/20 glass-radius-full h-2',
children: jsx(motion.div, {
className: 'glass-surface-blue h-2 glass-radius-full',
animate: {
width: `${generationProgress}%`
},
transition: prefersReducedMotion ? {
duration: 0
} : {
duration: 0.3
}
})
})]
}), jsxs("div", {
className: 'glass-grid glass-grid-cols-1 lg:grid-cols-2 glass-gap-6',
children: [showModelSelector && jsx(ModelSelector, {}), showGenerationControls && jsx(GenerationControls, {})]
}), showLatentSpace && latentVectors.length > 0 && jsxs("div", {
className: 'space-y-4',
children: [jsx("h4", {
className: 'glass-text-sm font-medium text-primary/80',
children: "Latent Space (2D Projection)"
}), jsx("canvas", {
ref: latentSpaceCanvasRef,
width: 400,
height: 300,
className: 'glass-w-full max-w-md glass-border glass-border-white/20 glass-radius-lg glass-surface-dark/20'
})]
}), enableInterpolation && interpolationImages.length > 0 && jsxs("div", {
className: 'space-y-4',
children: [jsx("h4", {
className: 'glass-text-sm font-medium text-primary/80',
children: "Latent Interpolation"
}), jsx("div", {
className: 'glass-flex space-x-2 overflow-x-auto pb-2',
children: interpolationImages.map((imageUrl, index) => jsx("div", {
className: 'glass-flex-shrink-0 w-16 h-16 glass-radius glass-border glass-border-white/20 overflow-hidden',
children: jsx("img", {
src: imageUrl,
alt: `Interpolation ${index}`,
className: 'glass-w-full glass-h-full object-cover'
})
}, index))
})]
}), isTraining && showTrainingControls && jsxs("div", {
className: `
p-3 rounded-lg border border-orange-400/30
${createGlassStyle({
blur: "sm",
opacity: 0.8
}).background}
`,
children: [jsxs("div", {
className: 'glass-flex glass-items-center glass-justify-between mb-2',
children: [jsx("span", {
className: 'glass-text-sm text-primary/80',
children: "Training Model..."
}), jsxs("span", {
className: 'glass-text-sm font-medium text-primary',
children: ["Epoch ", trainingProgress.epoch]
})]
}), jsxs("div", {
className: 'glass-grid glass-grid-cols-2 glass-gap-4 glass-text-xs text-primary/60',
children: [jsxs("div", {
children: ["Generator Loss: ", trainingProgress.generatorLoss.toFixed(3)]
}), jsxs("div", {
children: ["Discriminator Loss:", " ", trainingProgress.discriminatorLoss.toFixed(3)]
})]
})]
}), jsxs("div", {
className: 'glass-flex glass-items-center glass-justify-between pt-4 glass-border-t glass-border-white/10',
children: [jsxs("div", {
className: 'glass-flex glass-items-center space-x-4',
children: [jsx(motion.button, {
className: 'glass-px-4 glass-py-2 glass-surface-blue hover:glass-surface-blue text-primary glass-radius-lg glass-text-sm font-medium transition-colors disabled:opacity-50',
whileHover: shouldAnimate ? {
scale: 1.02
} : {},
whileTap: shouldAnimate ? {
scale: 0.98
} : {},
onClick: generateImages,
disabled: isGenerating || !model.trained,
children: isGenerating ? "Generating..." : "Generate Images"
}), enableInterpolation && latentVectors.length >= 2 && jsx(motion.button, {
className: 'glass-px-4 glass-py-2 glass-border glass-border-white/30 hover:border-white/50 text-primary/80 glass-radius-lg glass-text-sm transition-colors',
whileHover: shouldAnimate ? {
scale: 1.02
} : {},
whileTap: shouldAnimate ? {
scale: 0.98
} : {},
onClick: generateInterpolation,
children: "Interpolate"
}), showTrainingControls && !model.trained && jsx(motion.button, {
className: 'glass-px-4 glass-py-2 glass-surface-primary hover:glass-surface-primary text-primary glass-radius-lg glass-text-sm font-medium transition-colors disabled:opacity-50',
whileHover: shouldAnimate ? {
scale: 1.02
} : {},
whileTap: shouldAnimate ? {
scale: 0.98
} : {},
onClick: trainModel,
disabled: isTraining,
children: isTraining ? "Training..." : "Train Model"
})]
}), jsxs("div", {
className: 'glass-flex glass-items-center space-x-2 glass-text-xs text-primary/60',
children: [jsxs("span", {
children: ["Generated: ", generatedImages.length]
}), jsx("span", {
children: "\u2022"
}), jsxs("span", {
children: ["Model: ", model.name]
})]
})]
})]
});
});
GlassGANGenerator.displayName = "GlassGANGenerator";
export { GlassGANGenerator };
//# sourceMappingURL=GlassGANGenerator.js.map