Here's an uncomfortable truth: your GitHub profile README is the most-viewed file you'll ever write, and almost nobody reads it. It's the first thing that loads on your profile — and it's usually a pile of badges, a streak counter, and a "most used languages" card that looks exactly like everyone else's. Wallpaper. You scroll past your own.
I snapped one evening and decided mine would do something. Not look busy — do something. Two weeks later my profile is a mission console orbiting a living planet, and every panel on it is a real instrument wired to my actual data. It rebuilds itself every morning while I'm asleep.
This is the whole teardown — the one weird constraint that makes this genuinely hard, the SVG trick that beats it, the maths behind the rings, and the three bugs that stole my weekend. Steal all of it.
That rule is the entire difference between a toy and a dashboard, and it was brutal. It killed half my ideas on the spot. No glowing lines for vibes. No waveform that's just a pretty sine. Every animated pixel has to be a real number — my commits, my pull requests, my languages, my writing — or it doesn't ship.
GitHub READMEs can't run JavaScript. None. No , no , no WebGL, no click handlers. GitHub strips all of it for security. You get Markdown and images. That's the whole sandbox.
Here's the trick, and it's the most useful thing in this post: an SVG animates itself even when it's just an . GitHub strips scripts, but it keeps declarative animation — plain CSS @keyframes and SMIL baked into the SVG. Drop this in a README:
…reference it as , and that dot breathes. Forever. Inside a file GitHub swore couldn't run code.
That one loophole is the foundation of everything below. Every spinning ring, radar sweep, and flickering readout is just an SVG pretending to be a picture.
The hero is a slowly rotating planet, and the rings around it aren't decoration — they're my contribution calendar bent into orbit.
Seven rings, one per weekday. Each ring is split into 53 segments, one per week. A segment lights up — cyan, then mint, then gold — based on how hard I committed that day. A lazy month shows as thin, dim inner arcs. A sprint lights up a bright band around the equator.
The trick that makes it cheap is a one-line SVG superpower: pathLength. I tell each ring "your circumference is 53 units long," so now one unit = one week, and a dash pattern can paint activity week by week:
One last touch sells the 3D: I clip the rings into a front half and a back half and draw them on either side of the planet, so they pass behind it at the top and in front at the bottom. Without that, it's a sticker. With it, the planet sits inside its own orbit.
The radar is my open-source footprint — the pull requests I've opened in other people's repos, the work that never shows up in your own repo list. Each blip is a real PR. The dish sweeps, the blips ping as it passes.
The spectrum turns my languages into emission lines, like you're reading the light off a star. Fat cyan line? TypeScript. Thin green sliver? Shell. The widths are the real percentages, not a vibe.
The signal is the one I'm proudest of — because I first built it wrong. For about ten minutes it was a gorgeous sine wave… that meant absolutely nothing. It broke the rule, so I ripped it out and plotted what it should have been all along: my reactions per post on dev.to.
Now the tallest spike on the oscilloscope is my most-reacted article. The sweep "intercepts" each post in turn. It reads like a transmission log and it's 100% my real engagement. The second I swapped the fake wave for real numbers, the panel went from screensaver to dashboard. That's the whole thesis in one commit.
The profile looks like a single console, but it's actually ten separate SVGs stacked in the README — hero, link badges, missions, radar, spectrum, signal, footer:
Why split them? One giant SVG is miserable to maintain, and every panel is a different height. The catch: stacked images show hairline seams and the illusion cracks. The fix is shared chrome — every panel draws the same corner brackets, the same bezel, and the same scanline sweeping down it, so ten images read as one continuous screen:
