The hero animation that broke my site on mobile

I built a hero animation I was a little too proud of. A blob of liquid metal that rippled and chased the cursor, rendered live in the browser, the first thing you saw when the page loaded. On my laptop it looked incredible. Then I opened the same page on my phone, watched it stutter for a second, felt the back of the case get warm, and on the next reload it just hung on a white screen until the tab quietly gave up.

So here is the answer I would give any vibe coder whose site feels fast on the laptop and broken on a phone. The fix is almost never optimizing the flashy effect itself. It is measuring what actually costs on the device, then reaching for progressive enhancement: serve a light static version to every phone by default, and only switch the live effect on for hardware that can afford it. Ship the enhancement, not the diagnostic. The thing to rewrite is rarely the animation. It is the quiet assumption that what runs on your machine is what your visitor gets.

why was it fine on my laptop and broken on a phone?

Because the laptop is close to the worst place you can judge a website from. It is plugged in, it has a real graphics chip, it is on fast wifi, and it never has to think about battery or heat. A mid-range phone is the opposite on every axis, and it is where a large share of your visitors actually are. My hero ran a continuous render loop, redrawing the effect every frame for as long as the page was open. The laptop absorbed that without noticing. The phone throttled itself to protect its own temperature, dropped frames, and burned power doing it, all before the visitor had read a single word.

The payload told the same story. The scripts that powered the effect downloaded instantly over my home connection and crawled over cellular. This is the authoring-environment gap, and it is the root of most vibe coded sites that feel great to the person who built them and rough to everyone else. A heavy hero is only the loudest member of a whole cluster of failures that only show up on a real phone. You are not testing the thing your visitor loads. You are testing a privileged version of it on privileged hardware, and the gap between those two is exactly where the mobile failures hide.

should I just optimize the animation?

This is where I almost lost a day. The instinct is to go straight at the scary-looking thing, the shader, the math, the part that feels expensive, and make it faster. I nearly did. What stopped me was the rule that has saved me the most time in this kind of work: diagnose before you fix, measure before you optimize. So instead of rewriting the effect, I opened the performance tools on an actual phone and watched where the time and the power went.

The shader was not the bottleneck. The math inside the effect was cheap. The cost was the payload it took to get there, plus the flat fact of running any live render loop continuously on a device that would rather be asleep. If I had trusted my instinct and spent the day optimizing the shader, I would have made the wrong thing faster and shipped a site that was still broken, just with a more elegant broken part. The honest measurement pointed somewhere I would never have guessed from the desktop. That is the whole value of measuring first: your intuition about what is slow was formed on the machine where nothing is slow.

what does the fix actually look like?

Progressive enhancement, in the old and literal sense. The baseline that every phone gets is a static poster image of the hero. It looks like the effect, it loads in one request, and it asks the device for nothing after that. The live animation is treated as an upgrade, not the default. It only turns on when the browser can prove it can pay for it, gated behind a real capability check rather than a guess: a fine pointer, enough device memory, and a visitor who has not asked for reduced motion. High-end phones and desktops get the full thing. Everything else gets a fast, legible site that never heats up in a pocket.

The move that makes this durable is deciding, in the spec, that mobile is its own path and not a shrunken copy of desktop. When the light version is the thing you build first and the live effect is the thing you add on top, the failure mode inverts. The worst case for a weak device stops being a hung tab and becomes a still image, which is a perfectly good worst case. This is the same spec-first discipline that shows up everywhere else in serious vibe coding: name the property you refuse to break, in this case a phone that never chokes on the homepage, and let that decision drive the build instead of discovering it in the wild.

where this goes wrong

Two failure modes sit on either side of the fix. The first is the one I nearly walked into: assuming the fancy compute is the cost, rewriting it, and burning real hours making a thing faster that was never the problem. The measurement exists precisely to stop you from spending effort where your intuition points instead of where the cost is. A lot of the reasons AI-built sites load slowly live in the payload, not the part that looks hard.

The second failure is subtler and more tempting, because it looks like a win. You leave the heavy effect in place and just defer it until after the page has painted, so your first-load numbers improve and you call it fixed. Sometimes that is genuine. Often it is measurement noise, a better score sitting on top of the same underlying weight, and it brings its own bugs: a scroll wheel that goes dead while the deferred effect initializes, animation that bleeds past where it was pinned, a layout that shifts under the visitor's thumb. Deferring the cost is not the same as removing it. If the device could not afford the effect, the answer is to not send the effect, not to send it half a second later.

If you are scaling personal site work into client builds and want a sparring partner on the production jump, /work-with-us.

questions that keep coming up

Do I have to throw the animation away? No, and that is the point of gating it. The people on hardware that can render it smoothly still get it. You are not deleting the effect, you are refusing to force it onto devices that will choke on it, which is a smaller decision than it feels like when you are attached to the thing you built.

Isn't a static image a worse experience? A static image that loads instantly beats a live effect that stutters, heats the phone, and sometimes hangs the tab. The honest comparison is the version your visitor actually gets, not the version you see on your laptop. For most phones the poster is the better experience by a wide margin, and the ones that can do better are exactly the ones you let do better.

How do I know which effects to gate? Measure on a real mid-range phone, not the simulator and not your laptop. Anything that runs continuously, anything that ships a heavy library to render one visual, and anything that warms the device is a candidate. If the honest on-device number disagrees with your gut, trust the number. It is reading the site your visitor loads. Your gut is reading the one you built.

I still like that liquid metal hero. It is still there, still rippling, for anyone whose device can render it without complaint. The difference is that it stopped being the price of admission. The homepage loads fast and stays cool for everyone else, because the thing I was proudest of is no longer the first thing standing between a visitor and the site.

// part of the ai websites topic

// grab the free starter kit that makes your AI stop forgetting and stop guessing: get it →

// building with AI? the field manual has the structured lessons.

// hitting this on a real build? this is what I fix →