// model-picker.jsx — model registry + reusable model selector component. // Used by image-tool.jsx and video-tool.jsx, but works for any tool. // // To add a new model: append an entry to MODELS_REGISTRY below. const MODELS_REGISTRY = { image: [ { id: 'flux-pro', name: 'Flux Pro', vendor: 'Black Forest Labs', desc: 'Best photoreal & prompt adherence. Slower, premium quality.', credits: 4, speed: 'slow', quality: 5, tags: ['Photoreal', 'Best quality'], hue: 200, badge: 'PRO', }, { id: 'sdxl-turbo', name: 'SDXL Turbo', vendor: 'Stability AI', desc: 'Fast, balanced quality. Great default for everyday work.', credits: 1, speed: 'fast', quality: 4, tags: ['Fast', 'Default'], hue: 280, badge: null, }, { id: 'midjourney-v6', name: 'MJ v6', vendor: 'Midjourney', desc: 'Cinematic, painterly aesthetic. Strong on mood and lighting.', credits: 3, speed: 'medium', quality: 5, tags: ['Cinematic', 'Artistic'], hue: 30, badge: null, }, { id: 'imagen-3', name: 'Imagen 3', vendor: 'Google', desc: 'Best for typography in image, signage, complex layouts.', credits: 3, speed: 'medium', quality: 5, tags: ['Text-in-image', 'Layout'], hue: 340, badge: null, }, { id: 'dalle-3', name: 'DALL·E 3', vendor: 'OpenAI', desc: 'Best instruction following. Reliable for specific scenes.', credits: 2, speed: 'medium', quality: 4, tags: ['Instruction', 'Reliable'], hue: 160, badge: null, }, { id: 'recraft-v3', name: 'Recraft v3', vendor: 'Recraft', desc: 'Vector & icon style. Editable strokes and brand-ready.', credits: 2, speed: 'fast', quality: 4, tags: ['Vector', 'Icons'], hue: 100, badge: 'NEW', }, ], video: [ { id: 'sora-turbo', name: 'Sora Turbo', vendor: 'OpenAI', desc: 'High coherence, longer clips, best for scenes with motion.', credits: 24, speed: 'slow', quality: 5, tags: ['Best motion', '8s max'], hue: 220, badge: 'PRO', }, { id: 'veo-3', name: 'Veo 3', vendor: 'Google', desc: 'Photoreal & cinematic. Strong on landscapes, characters.', credits: 18, speed: 'slow', quality: 5, tags: ['Photoreal', '4K'], hue: 200, badge: null, }, { id: 'kling-2', name: 'Kling 2.0', vendor: 'Kuaishou', desc: 'Excellent character consistency and physics simulation.', credits: 12, speed: 'medium', quality: 4, tags: ['Character', 'Physics'], hue: 340, badge: null, }, { id: 'runway-gen4', name: 'Runway Gen-4', vendor: 'Runway', desc: 'Fast iteration. Great for image-to-video and stylized clips.', credits: 8, speed: 'fast', quality: 4, tags: ['Fast', 'i2v'], hue: 280, badge: null, }, { id: 'luma-ray', name: 'Luma Ray 2', vendor: 'Luma Labs', desc: 'Smooth camera moves. Best when you need controlled motion.', credits: 10, speed: 'medium', quality: 4, tags: ['Camera', 'Smooth'], hue: 30, badge: null, }, { id: 'pika-2', name: 'Pika 2.0', vendor: 'Pika Labs', desc: 'Playful, stylized. Cheap iteration for quick concepts.', credits: 6, speed: 'fast', quality: 3, tags: ['Stylized', 'Cheap'], hue: 100, badge: null, }, ], }; // ---- ModelCard: a single picker tile ---- const ModelCard = ({ model, selected, onClick, accent }) => { const speedLabel = { fast: '⚡ Fast', medium: '~ Medium', slow: '◐ Slow' }[model.speed]; return ( ); }; // ---- ModelPicker: full inline grid + collapsible "show all" ---- const ModelPicker = ({ kind = 'image', value, onChange, accent = '#22d3ee', compareMode, onCompareToggle, compareModels = [] }) => { const models = MODELS_REGISTRY[kind] || []; const [expanded, setExpanded] = React.useState(false); const visible = expanded ? models : models.slice(0, 4); return (