<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 周磊</title>
    <description>The latest articles on DEV Community by 周磊 (@_feb8725b29fed67712e93e).</description>
    <link>https://dev.to/_feb8725b29fed67712e93e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3754303%2F5c9e85db-a174-4ce5-b228-e360a770b656.png</url>
      <title>DEV Community: 周磊</title>
      <link>https://dev.to/_feb8725b29fed67712e93e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_feb8725b29fed67712e93e"/>
    <language>en</language>
    <item>
      <title>From One Selfie to Four Cartoon Avatars: How I Built an AI Avatar Generator with Next.js</title>
      <dc:creator>周磊</dc:creator>
      <pubDate>Thu, 05 Feb 2026 07:22:18 +0000</pubDate>
      <link>https://dev.to/_feb8725b29fed67712e93e/from-one-selfie-to-four-cartoon-avatars-how-i-built-an-ai-avatar-generator-with-nextjs-36g2</link>
      <guid>https://dev.to/_feb8725b29fed67712e93e/from-one-selfie-to-four-cartoon-avatars-how-i-built-an-ai-avatar-generator-with-nextjs-36g2</guid>
      <description>&lt;p&gt;Live Demo: &lt;a href="https://www.zltest.online/" rel="noopener noreferrer"&gt;https://www.zltest.online/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TL;DR&lt;br&gt;
User Flow: Upload 1 selfie, pick a style pack, and get 4 unique cartoon avatars.&lt;/p&gt;

&lt;p&gt;The Secret Sauce: A two-stage pipeline—Visual Description → Style Generation—to balance character likeness with artistic consistency.&lt;/p&gt;

&lt;p&gt;MVP Architecture: Used JSON-based storage for task and subscription management to enable rapid validation with minimal overhead.&lt;/p&gt;

&lt;p&gt;Background: Why Build This?&lt;br&gt;
I noticed a common pain point among users:&lt;/p&gt;

&lt;p&gt;People want avatars that are recognizable but protect their privacy.&lt;/p&gt;

&lt;p&gt;People want consistent styles, not a "lottery" of random AI outputs.&lt;/p&gt;

&lt;p&gt;Most people don't want to write complex prompts.&lt;/p&gt;

&lt;p&gt;My mission was simple: "One selfie, many styles."&lt;/p&gt;

&lt;p&gt;The user journey is compressed into three steps:&lt;/p&gt;

&lt;p&gt;Upload a selfie.&lt;/p&gt;

&lt;p&gt;Select a Style Pack.&lt;/p&gt;

&lt;p&gt;Generate and download.&lt;/p&gt;

&lt;p&gt;Functional Design: Style-First &amp;amp; "Prompt-less" UI&lt;br&gt;
The core concept is the Style Pack. I bundled Prompts, Negative Prompts, and recommended aspect ratios into single configuration objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2fokrk4sfohg9m89p4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr2fokrk4sfohg9m89p4y.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfvgys9hm9lpp88rf9c7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfvgys9hm9lpp88rf9c7.png" alt=" " width="800" height="452"&gt;&lt;/a&gt;&lt;br&gt;
This keeps the artistic output consistent while providing a "Prompt-less" experience for the user.&lt;/p&gt;

&lt;p&gt;Simplified Configuration:&lt;/p&gt;

&lt;p&gt;TypeScript&lt;br&gt;
const stylePacks = [&lt;br&gt;
  {&lt;br&gt;
    id: "anime-lineart",&lt;br&gt;
    name: "Clean Anime",&lt;br&gt;
    promptTemplate: "clean lineart, soft pastel colors, high-quality digital art",&lt;br&gt;
    negativePrompt: "low quality, text, watermark, blurry, realistic photo",&lt;br&gt;
  },&lt;br&gt;
]&lt;br&gt;
Currently, the app features 10 built-in styles, including Anime, Cel-shaded, Chibi, 3D, Pixel Art, and Claymation.&lt;/p&gt;

&lt;p&gt;The Workflow: Balancing Likeness vs. Artistry&lt;br&gt;
To avoid the instability of direct img2img (which often creates "uncanny valley" results), I implemented a two-stage process:&lt;/p&gt;

&lt;p&gt;Visual Description (VLM): Use a vision model (like Gemini) to extract key features from the selfie (hair style, glasses, facial expression, etc.).&lt;/p&gt;

&lt;p&gt;Stylized Generation: Combine the Style Pack Prompt + Visual Description to generate 4 distinct avatars.&lt;/p&gt;

&lt;p&gt;This ensures the "Style" dominates the aesthetic while the "Visual Description" maintains the user's identity. I also added a slider for Likeness vs. Style priority to give users more control.&lt;/p&gt;

&lt;p&gt;System Architecture: The MVP Stack&lt;br&gt;
My goal was speed-to-market. Here is the stack I chose:&lt;/p&gt;

&lt;p&gt;Next.js App Router: Full-stack integration; API routes handle the task orchestration.&lt;/p&gt;

&lt;p&gt;OpenRouter: A single unified API to call both Gemini (for vision) and various image generation models.&lt;/p&gt;

&lt;p&gt;Supabase Auth: Quick implementation of Google Social Login.&lt;/p&gt;

&lt;p&gt;Creem / PayPal: Handling subscriptions and international payments.&lt;/p&gt;

&lt;p&gt;Tailwind CSS + shadcn/ui: For a clean, responsive UI.&lt;/p&gt;

&lt;p&gt;Lightweight Task Queue&lt;br&gt;
For the MVP, I skipped complex message brokers like RabbitMQ. Instead, I used an in-memory queue backed by JSON storage:&lt;/p&gt;

&lt;p&gt;States: queued → running → succeeded/failed/canceled&lt;/p&gt;

&lt;p&gt;Automatic timeouts and retry logic.&lt;/p&gt;

&lt;p&gt;This setup is more than enough for initial traffic and is incredibly easy to maintain.&lt;/p&gt;

&lt;p&gt;Subscriptions &amp;amp; Rate Limiting&lt;br&gt;
To keep GPU costs under control, I enforced strict rules at the API layer:&lt;/p&gt;

&lt;p&gt;Authorization: Only subscribed users can trigger generation tasks.&lt;/p&gt;

&lt;p&gt;Quota: 1 credit per generation (yielding 4 images).&lt;/p&gt;

&lt;p&gt;Concurrency: Maximum of 1 active task per user.&lt;/p&gt;

&lt;p&gt;Retention: Images are stored for 7 days by default, with an option for users to delete them manually.&lt;/p&gt;

&lt;p&gt;Lessons Learned &amp;amp; Pitfalls&lt;br&gt;
Model Compatibility: Not all models through OpenRouter support image output natively. I had to build a robust configuration handler with mock fallbacks.&lt;/p&gt;

&lt;p&gt;Identity Drift: Pure prompting often loses the person's likeness. Introducing the "Visual Description" stage stabilized the results significantly.&lt;/p&gt;

&lt;p&gt;JSON for Storage: While simple, you must be careful with concurrent writes. I implemented basic file-locking to prevent data corruption during the MVP stage.&lt;/p&gt;

&lt;p&gt;Roadmap&lt;br&gt;
Integrate stronger identity-preserving solutions (like LoRA or DreamBooth).&lt;/p&gt;

&lt;p&gt;Add a dashboard for Style Pack management.&lt;/p&gt;

&lt;p&gt;Migrate to a persistent task queue (e.g., Upstash or BullMQ) and S3-compatible object storage.&lt;/p&gt;

&lt;p&gt;If you're interested in AI-driven UX or want to discuss the technical implementation of avatar generators, let’s connect in the comments!&lt;/p&gt;

&lt;p&gt;A few tips for your dev.to post:&lt;br&gt;
Add Visuals: Since this is a "generator," users will want to see results. Include a "Before &amp;amp; After" image in the post.&lt;/p&gt;

&lt;p&gt;Code Snippets: You mentioned you're a computer teacher—developers on dev.to love seeing how you handled the OpenRouter API call or the JSON file-locking. Feel free to add a bit more code!&lt;/p&gt;

&lt;p&gt;The "Call to Action": Since you are an independent developer, mentioning that you are looking for feedback on the UX is a great way to get comments.&lt;/p&gt;

&lt;p&gt;Would you like me to expand on any specific technical part, such as the JSON file-locking logic or the OpenRouter integration code?&lt;a href="https://dev.tourl"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>nanobanana</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
