Why Single-Model "Cartoonify" Prompts Fail in Production (And How I Fixed It with a 2-Stage Pipeline) A developer building an AI Cartoonify image-to-image feature found that single-model prompt passes failed on real user uploads, losing micro-details like wire-rimmed glasses and beards when style exaggeration was allowed. The fix was a two-stage pipeline that decouples semantic understanding from spatial rendering: ChatGPT Image 2.5 extracts identity anchors such as eyewear, facial hair and hand pose, which are injected as tokens into a Nano Banana 2.1 conditioning payload with a 0.70 composition lock and anti-uncanny guardrails. The developer reports this forces the renderer to redraw fragile details cleanly rather than blurring them. If you have ever built an image-to-image I2I consumer feature, you already know the dirty secret of prompt engineering: what works in a Cherry-Picked Twitter thread rarely survives contact with real user uploads. A few weeks ago, I started building an AI Cartoonify effect. The goal seemed straightforward—let users upload a selfie or pet photo and transform it into a stylized 3D/2D cartoon while keeping the person recognizable. At first, I tried throwing the reference image and a carefully crafted style prompt into a single generation pass. It was a disaster. Take a typical torture-test upload: a guy with a thick beard, wearing thin wire-rimmed glasses, standing under harsh side-lighting, holding up a peace sign. When I ran this through a standard single-model I2I workflow, I kept hitting a brick wall: The root cause? A single pass forces the model to figure out what is in the image and how to deform it artistically at the exact same time. To ship this to production, I had to decouple semantic understanding from spatial rendering . Here is how I rebuilt the pipeline by pairing ChatGPT Image 2.5 with Nano Banana 2.1 . Instead of asking a single model to guess which pixels matter, I split the workload between two engines based on what they actually do best: Rather than relying on static prompt templates, the backend builds a custom conditioning payload for every single upload. Here is a simplified look at the TypeScript structure driving the orchestration: interface CartoonifyJob { sourceImageUrl: string; targetAesthetic: '3d-animation' | 'cel-shaded' | 'flat-illustration'; } interface ConditioningPayload { spatialReference: { imageUrl: string; edgeFidelity: 'strict' | 'balanced' | 'loose'; compositionLock: number; // 0.0 to 1.0 }; semanticTokens: { identityLocks: string ; // Extracted via ChatGPT Image 2.5 lightingCues: string ; // Preserves mood without keeping raw photo noise styleModifiers: string ; // Drives the Nano Banana 2.1 shader guardrails: string ; // Anti-uncanny-valley negative tokens }; } async function buildCartoonPipeline job: CartoonifyJob : Promise