Welcome Elvis to this blog!

Over the last few days, I’ve been working on putting Elvis, our Dachshund, onto this blog’s banner. The goal was to create a smooth animation where Elvis appears by rising from the bottom of the banner, then leans his paws over the border—adding some personality to the site while exploring modern web animation techniques.
Creating a cartoon version of Elvis

I wasn’t able to find a dog that was similar enough to Elvis on Bitmoji (where my own avatar was created), but this one on the right looked like a good starting point.
(Apparently, Bitmoji switched its character engine to a more 3D-ish look, which I like less than the old cartoon look. That’s why the picture shows a different look for my avatar than the dog.)
Could ChatGPT help me out here? Its image generator (GPT-4o) uses an interesting, autoregressive architecture which is much different from other, diffusion-based models. This makes image generation more steerable, so I wanted to put this to the test.
I gave ChatGPT my previous (sans Elvis) blog header, as well as my Bitmoji-generated avatar image (to show it the style I wanted), plus a photo of Elvis and the Bitmoji dog above. My prompt was quite descriptive:
Hi, here’s a Bitmoji image of myself. I’m using it in my blog’s header, which I also attached. I would like to add a picture of my dog Elvis, Bitmoji-style, to my blog header, similarly to how the dog looks in the the 3rd picture. However, my dog Elvis is a black and tan Dachshund, you can see a picture of him in the last image.
Now, please generate a Bitmoji-style image of my dog Elvis, in the same pose as the Bitmoji-dog I showed you, so I can add it to my banner, next to my own thinking-pose avatar.
That worked quite well!
I really liked the slightly overhanging paws which gave me the idea of Elvis appearing into the animated banner by raising up, then leaning itself onto the bottom border of the banner.
To make that work, I needed the picture to have more body. So I brought up Acorn, my favourite image editor, and used my crude artistic skills to add a slightly longer belly. I also made the brown tone in his eyes slightly lighter.
Here’s the final result of Elvis, the dachshund, cartoon-style:
Adding some simple animation
The animation was a bit tricky to do and taught me several things about SVG animation:
SVG Clipping Challenges
To make Elvis raise from the bottom, then let his paws overlap, I used SVG’s <clipPath>
element with two rectangles:
- One inside the banner area to make Elvis visible at all times
- One below that makes him invisible from the bottom border down while he’s moving up, then revealing just the left bottom part of him as he leans down onto the border, but not the right belly part
<clipPath id="elvisClip">
<rect id="elvis-clip-upper-rect"
x="{{ ELVIS_X }}"
y="{{ BANNER_HEIGHT - ELVIS_HEIGHT }}"
width="{{ ELVIS_WIDTH }}"
height="{{ ELVIS_HEIGHT }}" />
<rect id="elvis-clip-lower-rect"
x="{{ ELVIS_X }}"
y="{{ BANNER_HEIGHT }}"
width="0"
height="{{ ELVIS_PAWS_HEIGHT }}" />
</clipPath>
Coordinate System Gotchas
However, now that Elvis’ paws are hanging over the bottom of the banner, the whole SVG dimensions needed to be adjusted to fit the banner plus paws. That in turn led to some bottom parts of my avatar and the sine curves bleeding over the bottom edge where they shouldn’t, so I added a clipping rectangle to the non-Elvis parts of the banner as well.
Animation Mathematics
The animation curve is based on a sine function with some calculations to let him stop at just the right moment to make the image align well:
function setupElvis(config) {
// ... setup code ...
// The key calculation: determine the sine end point
const elvisPawsPercent = config.elvisPawsHeight / config.elvisHeight;
animState.elvis.sinEnd =
animState.elvis.sinPeak + Math.asin(elvisPawsPercent);
}
function animateElvis(elapsedPercent) {
// ... timing logic ...
if (elapsedPercent < stop) {
const elvisPercent = (elapsedPercent - start) / (stop - start);
const sinPos =
(animState.elvis.sinEnd - animState.elvis.sinStart) * elvisPercent;
elvisY =
animState.elvis.startY - animState.elvis.height * Math.sin(sinPos);
elvisClipX = sinPos < Math.PI / 2 ? 0 : animState.elvis.pawsClipTargetX;
}
animState.elvis.image.setAttribute("y", elvisY);
animState.elvis.pawsClip.setAttribute("width", elvisClipX);
}
This is also a nice example to show my daughter when she asks “why would anyone ever use Math beyond school?” - here’s trigonometry being used to make a cute dog animation on the internet!
Key Learnings
There was quite a lot of fiddling with exact position and size values to make it happen. However, thanks to SVG’s coordinate system and some pixel counting on the Acorn side, I was able to compute the right values rather than guessing.
The debugging lesson: While I was fiddling with the animation system anyway, I also cleaned up some of the constants which introduced some bugs. Interestingly, Claude wasn’t able to find the bug right away: The root cause was that I had added the paw height to the full SVG dimensions, then used those dimensions to infer the banner height from the JavaScript part, which incorrectly included the paws part and that mispositioned Elvis at the end of the animation. It took me some good old measurement addition and comparison work to figure that out. This highlights that LLMs struggle with spatial reasoning when they can’t see the visual result—I only found the root cause after doing the positioning math manually and noticing the double-counting of the paws overhang.
What I learned:
- Using
<clipPath>
in SVG for complex reveal animations - Coordinate system management when mixing absolute positioning with clipping
- Sine-based animation curves for natural movement
- How to add interactive behavior to SVG elements
I also added clicking behaviour to the banner: On the home page, it restarts the animation, on any other page, it links to the home page.
You can see the final result, with animation on the main home page.
Note: You might want to clear your local web cache (Cmd-Shift-R on a Mac) and reload the main page to see the new animation since the old JavaScript code might still be in the cache.
It’s not quite Disney-class, but I like it, and spending a few hours creating and animating a simple movement animation with clipping rectangles and some sine-based math was a fun learning experience. I hope you like it!