secco.tech
...
Ygor Secco in a dark blazer beside the title 'From Animated Resume to a Home on the Web' on a purple secco.tech banner

From Animated Resume to a Home on the Web

5 min readYgor Secco
Building in PublicNext.jsFrontend

For years, my résumé was a PDF. One page, a tasteful serif, a bulleted list of things I supposedly know how to do. And every time I sent it, the same small irony nagged at me: I spend my days building interfaces — motion, state, the feel of a thing — and I was describing that work in the most static format imaginable. A list that says "good at frontend" proves nothing. I wanted the résumé to be the proof.

So I built one. Not a document about the work — a small piece of work itself: an animated résumé, over-engineered on purpose, whose only job was to show rather than tell. What I didn't plan for was that it wouldn't stay a résumé. This is the story of how it grew, and the decisions behind each room I added.

From here on it reads more like a build log.

Chapter 1 — The résumé as a demo

The first decision was to make it data-driven, not hand-coded. All the content lives in a single resume.json, typed and validated against a schema at build time. The point wasn't tidiness for its own sake — it meant the layout could be the craft while the content stayed portable, and it meant I physically can't ship a malformed résumé: an invalid field fails the build before anything reaches the web.

The second decision was GSAP over CSS transitions or a React motion library. I wanted timeline control and scroll-driven choreography — an intentional, slightly indulgent entrance sequence I think of as the "dopamine" pass, because on a showcase résumé the motion is the message. But indulgent isn't the same as inconsiderate: every animation is gated on prefers-reduced-motion, and the reduced path simply snaps to the final state. Delight for people who want it, calm for people who don't.

Underneath both is one small design system — dark-first, a single purple accent, built on Tailwind's CSS-first config with no JavaScript config file at all. Constraints I chose on purpose, because a coherent surface reads as craft.

The result was a résumé that demonstrates the skill instead of asserting it.

Chapter 2 — Two readers, two documents

Then reality intruded: a recruiter skimming two hundred applications does not want my GSAP timeline. They want to scan, and they want to print. The animated version optimizes for delight; a hiring screen optimizes for speed. Those are different products.

Rather than compromise one into the other, I built both. I added a classic /cv — a print-optimized, recruiter-friendly layout with real @media print rules and a one-click PDF export. The export uses a full PDF renderer, but it's lazy-loaded on click via a dynamic import, so that heavy dependency never touches the initial bundle. The interactive site stays light; the PDF is generated in the browser only when someone actually asks for it.

Two front doors meant the site needed a lobby. So the homepage became a hub — a landing page that lets you choose how to explore — and the résumé moved to /resume. The project had a center for the first time.

Chapter 3 — A place to actually write

I wanted somewhere to think out loud — like this. But bolting a blog onto a portfolio usually means dragging in a CMS or a database, and I didn't want that weight.

The constraint made the decision for me. The whole site is a static export served from a CDN — there is no server at request time. That's a feature: every route is just a file at the edge. But it means "a blog" can't mean "query posts from a database on each request."

So everything resolves at build time. Posts are Markdown files in the repo, compiled to HTML during the build inside React Server Components using marked for parsing and Shiki for syntax highlighting. The consequence I care about most: the browser downloads a finished document, not a program that assembles one — zero Markdown-parser or highlighter JavaScript ships to the client. (You're reading a page that quietly proves its own point.)

Storing the posts was its own decision. Not a JSON blob, not a database — one Markdown file per post with frontmatter, so git is the CMS: posts are versioned, diffable, and reviewable in a pull request, and publishing is just a commit. A schema check and a few integrity rules run at build, so a broken post fails the build instead of production.

I also refused to skip the unglamorous parts. A sitemap, a robots file, and an RSS feed are generated at build, and every post gets a branded social card rendered from its title and tags. The one thing static genuinely can't do — view counts, comments — I left out on purpose. When I want them, they'll be a thin serverless function over the static core, not a reason to rewrite it.

Chapter 4 — Where it's going

Somewhere in there the site stopped being a résumé and became a platform — a small, fast, hand-built home on the web I can keep adding rooms to. A portfolio of shipped work is next (it's a "coming soon" sign today), more writing after that, and eventually those dynamic touches, added only where they earn their keep.

The funny part is that what started as a small thing meant to show what I can build turned into the most honest artifact of how I actually work: opinionated, over-built where the craft should show, restrained where it counts. If you're reading this, you're standing in the newest room. There will be more.

Related Projects

Related Posts