Have you ever wondered what a combination of a capybara and a retro camera would look like in a cozy Ghibli watercolor? Or how a neon-drenched cyberpunk shark mixed with a bubble tea cup would be rendered?
In this post, we'll dive deep under the hood of Pet Fusion Laboratory, a responsive, highly-stylized full-stack application. We'll examine how it turns raw user-provided input strings into pristine, visually descriptive image generator prompts, processes them via Google Gemini, handles fallback states gracefully, and logs everything locally in a biotech-themed React UI.
Application Architecture
Here's how the entire process flows from the user's browser, through our server, out to Google's neural models, and back:
[Client App: React 19]
│
│ 1. POST /api/fuse { animal1, animal2, style }
▼
[Server Engine: Express] ──(Instantiates @google/genai SDK)
│
│ 2. Calls Gemini 3.1-Flash-Lite with Structured JSON Schema
▼
[Google Gemini API] ──(Returns validated JSON object)
│
│ 3. Formulates custom creatureName, imagePrompt, funBio
▼
[Server Engine: Express]
│
│ 4. Sends clean JSON back to client
▼
[Client App: React 19] ──(Logs to LocalStorage & Updates UI state)
│
│ 5. (Optional) POST /api/generate-image { prompt }
▼
[Server Engine: Express] ──(Calls Gemini 3.1-Flash-Lite-Image)
│
│ 6. Generates Base64 PNG image
▼
[Client App: React 19] ──(Visualizes Specimen / Displays fallback Blueprint if limited)
The Backend: Structured JSON Generation with Gemini 3.1-Flash-Lite
To make a reliable AI application, we can't just let the model output arbitrary Markdown text. We need strict, typed JSON data to populate our React state machines. We achieve this by leveraging the schema enforcement parameters of the @google/genai SDK on the backend.
Let's examine how we initialize and run this inside /server.ts:
import { GoogleGenAI, Type } from "@google/genai";
const getGeminiClient = () => {
const apiKey = process.env.GEMINI_API_KEY;
if (!apiKey) {
throw new Error("GEMINI_API_KEY environment variable is missing");
}
return new GoogleGenAI({ apiKey });
};
app.post("/api/fuse", async (req, res) => {
try {
const { animal1, animal2_or_object, style, customStyle } = req.body;
const ai = getGeminiClient();
const systemInstruction = `You are the ultimate "Master Geneticist" of the Pet Fusion Laboratory.
Your job is to take two random animals (or an animal and an object) and blend them into a highly descriptive, visually stunning prompt optimized for AI image generation.
You must design how features are blended, select a background setting, specify lighting/texture, and enforce the chosen art style.`;
const userPrompt = `Fuse these: Subject A: "${animal1}", Subject B: "${animal2_or_object}", Style: "${style}"`;
const response = await ai.models.generateContent({
model: "gemini-3.1-flash-lite", // The most cost-efficient and ultra-low latency model
contents: userPrompt,
config: {
systemInstruction,
responseMimeType: "application/json",
responseSchema: {
type: Type.OBJECT,
properties: {
creatureName: {
type: Type.STRING,
description: "A funny, highly creative hybrid name (e.g. 'The Fluffy Gummy-Shark').",
},
imagePrompt: {
type: Type.STRING,
description: "The complete, detailed, expanded image prompt optimized for text-to-image models.",
},
funBio: {
type: Type.STRING,
description: "A humorous scientific observation or superpower.",
},
},
required: ["creatureName", "imagePrompt", "funBio"],
},
},
});
const data = JSON.parse(response.text);
res.json(data);
} catch (error) {
res.status(500).json({ error: "Splicing matrix error" });
}
});
Using gemini-3.1-flash-lite with responseMimeType: "application/json" guarantees that the returned text matches our exact TypeScript interfaces every time, preventing runtime JSON parsers from throwing errors!
The Image Generation & Fallback Blueprint Engine
One of the highlights of this setup is how we handle image synthesis. We proxy requests to gemini-3.1-flash-lite-image server-side to prevent exposing any client keys.
But what happens if the user's API key hits rate limits, or is missing entirely? Rather than just throwing a crude pop-up alert, the application adapts gracefully by rendering a custom SVG/HTML blueprint schematic blueprint!
// Part of SpecimenDisplay.tsx handling render failures beautifully:
{imageUrl ? (
<div className="relative w-full h-full">
<img src={imageUrl} alt={result.creatureName} className="object-cover w-full h-full" />
</div>
) : renderError ? (
/* Fallback Beautiful Blueprint Schematic Layout */
<div className="absolute inset-0 flex flex-col p-6 overflow-y-auto bg-slate-900 border border-cyan-500/30 relative" style={{
backgroundImage: "radial-gradient(rgba(6, 182, 212, 0.08) 1.5px, transparent 1.5px)",
backgroundSize: "16px 16px",
}}>
<div className="flex flex-col items-center justify-center flex-grow text-center">
<div className="relative mb-4 flex items-center justify-center">
<div className="absolute inset-0 rounded-full bg-cyan-500/5 animate-ping" />
<div className="p-4 rounded-full bg-cyan-950/50 border border-cyan-500/40 text-cyan-400">
<Atom size={32} className="animate-spin" />
</div>
</div>
<h4 className="text-sm font-black font-mono text-cyan-400 uppercase tracking-widest">
GENETIC BLUEPRINT GENERATED
</h4>
<div className="mt-4 w-full p-4 rounded-xl border border-cyan-500/20 bg-slate-950/80 text-left">
{/* Specimen data grid rendering animal1, animal2, style details */}
</div>
<p className="text-xs text-slate-300 mt-4 leading-relaxed max-w-xs">
Your prompt is perfectly compiled. Copy the prompt to witness its true form in Midjourney, DALL-E, or Stable Diffusion!
</p>
</div>
</div>
) : (
/* Prompt to render visualizer */
)}
This ensures that the UX remains engaging, immersive, and fully functional, teaching developers how to build resilient AI user interfaces.
Styling the Biotech Dashboard with Tailwind CSS
We created a dark-room experience with a high-contrast layout. Important design steps we followed:
- Font Pairings: We imported Space Grotesk (display headings) for that high-tech geometric feel, paired with Inter for readable UI content, and JetBrains Mono for technical code outputs.
-
Radial Gradients & Blurs: Utilizing absolute positioned elements with heavy blur values (
blur-[120px]) and low-opacity colors (bg-emerald-500/10) to simulate pulsing biotech laboratory lights behind cards. -
Pulsing Animations: Simple Tailwind animations like
animate-pulse, combined with custom@keyframesto pulse gradient overlays dynamically.
How to Run and Adapt
You can fork this layout and add:
- Collectible Cards: Allow users to download a trading card design with the creature image and attributes.
- Audio synthesis: Add custom web audio synthesizer loops (bubbling liquids, electricity arcing) when the splicing progress bar updates.
- DNA Stats Radar Charts: Render stats like "Cute vs Dangerous", "Toxicity", or "Speed" dynamically using SVG curves or Canvas.
Code & more: https://www.dailybuild.xyz/project/193-pet-fusion-laboratory
Top comments (0)