# What I learned building a tattoo aging simulator with Next.js and image AI

> Source: <https://dev.to/viktria_sti_3fb7d5606cc/what-i-learned-building-a-tattoo-aging-simulator-with-nextjs-and-image-ai-15l4>
> Published: 2026-11-09 12:42:18+00:00

Most people pick a tattoo by looking at a fresh one: crisp lines, saturated colour, perfect skin. But a tattoo spends almost all of its life *not* fresh. Ink slowly spreads in the skin, fine lines get wider, small details merge and light colours fade. I wanted a way to see that before booking, on your own body, so I built [InkAge](https://inkage.app/?lang=en).

You upload a photo of the spot, add a design and set its real size in centimetres. The app draws the tattoo into the photo, then shows it fresh, healed after a year, and after 10, 30 and 50 years. It can also age a tattoo you already have, or preview laser removal after 3, 6 and 10 sessions.

Here are a few things that turned out to matter more than I expected.

The first versions let you drag a design anywhere at any size. The previews looked great and were useless, because the single biggest factor in how a tattoo ages is how big it is relative to its detail. A 3 cm script tattoo and a 10 cm one age completely differently. Asking for the size in centimetres, and placing the design at that scale on the photo, made the aging previews far more honest.

An image of a blurry 50-year-old tattoo invites one question: *why?* So every preview comes with a 0–100 longevity score and the reasons behind it: size, line thickness, colour, placement and sun exposure. The score also offers a sturdier redraw of the same design to compare side by side. People trust a prediction more when they can see what drives it, and they can actually act on it (go bigger, go bolder, pick another spot).

The drawing is done by an image model (Google Gemini, with OpenAI as a fallback). Having a second provider wired in from the start saved me more than once: when one returns an error or refuses a perfectly normal photo, the request quietly retries on the other. Users never see the outage.

The site runs in 35 languages. Every page renders on the server in the language of `?lang=xx`. A small Next.js middleware reads `Accept-Language` and redirects a German browser to `?lang=de`, an English one to `?lang=en`, and so on, while a request with no language preference (most crawlers) gets the default page. Each language version has its own canonical URL and `hreflang` links, so search engines can index all of them.

Most visitors don't arrive wanting a simulator. They arrive asking "how will my tattoo look in 20 years?", "does fine line fade?" or "how many laser sessions will I need?". Answering those questions properly, in articles with sources and illustrations, turned out to be the best way to explain why a preview is worth trying.

The previews are AI estimates of how ink, skin and sun usually behave, not a measurement of anyone's skin, and I say that on every result. I'm working on making the aging steps more consistent between styles.

If you try it, I'd really like to hear what would make the aging previews more convincing to you: [inkage.app](https://inkage.app/?lang=en).
