← All articles
Minh Pham Portfolio Case Study (Awwwards SOTD)
A Minh Pham portfolio case study — how this designer portfolio website was built with GSAP, Three.js & WebGL and won Awwwards Site of the Day (dev score 7.77).

There's a special kind of pressure in building a designer portfolio website for someone whose entire reputation is the quality of their craft. Minh Pham is a world-class multidisciplinary designer — Design Lead at Fantasy, with work for Ford, UFC, Lincoln, Royal Caribbean and the NFL — and his portfolio had to be a portfolio-grade artifact, not just describe one. This Minh Pham portfolio case study breaks down how I built that site as the developer: the brief, the GSAP motion, the Three.js/WebGL layer, and the engineering that earned it Awwwards Site of the Day with a developer score of 7.77.
Who built it — and the trust behind it
I was the creative developer on this project; Minh owned the design and direction. That split matters here more than usual. When the client is a top-tier designer, the developer isn't there to interpret loosely — you're there to render someone's intent at 100% fidelity, then make it move.
Minh has since called me "a phenomenal front-end developer," which I don't quote to brag — I quote it because it's the whole point of this case study. A designer that demanding only signs off when the build actually matches the vision pixel for pixel. For context on why I take that bar seriously: I've spent 11+ years building award-winning experiences for clients across Norway, Denmark, Sweden, Malta, Germany and Vietnam, I sit on the Awwwards jury, and my work has earned multiple Awwwards Site of the Day awards. On a designer's own portfolio, that track record is the difference between motion that flatters the work and motion that quietly undersells it.
The brief: the portfolio has to be portfolio-quality itself
This is the recursive trap of any designer portfolio website: the site is simultaneously the container and an exhibit. A flat, generic build would contradict everything the work claims. So the bar wasn't "present the projects clearly" — it was "make the site itself good enough to belong in the projects."
Three constraints shaped every decision:
- Fidelity is non-negotiable. Spacing, type scale, easing, timing — every value had to match Minh's design exactly. "Close enough" reads as a downgrade on a designer's own site.
- Motion is the personality. Minh's craft spans 3D, motion and product design. The site had to feel designed-in-motion, not decorated after the fact.
- The work imagery stays pristine. His case studies are visual. No effect could ever soften, compress or distort the source imagery.
The craft: GSAP motion, Three.js and WebGL
The signature pieces came down to three layers working together — a GSAP-driven motion system, considered page and image transitions, and a Three.js/WebGL layer for the moments that needed real GPU work. Here's how each was built.
Pixel-perfect layout that holds across every screen
"Faithful to the design" can't mean pixel-perfect at one breakpoint and broken everywhere else. The reliable way to honor a designer's spacing and type scale on every viewport is fluid tokens derived straight from the design's min/max values, so the rhythm Minh set never collapses between breakpoints:
:root {
/* clamp(min, fluid, max) — fluid type that tracks the design 1:1 */
--step-0: clamp(1rem, 0.93rem + 0.36vw, 1.25rem);
--step-1: clamp(1.5rem, 1.3rem + 1vw, 2.25rem);
--display: clamp(3rem, 1.8rem + 6vw, 9rem);
--gutter: clamp(1.25rem, 0.8rem + 2.2vw, 3rem);
}
This is the unglamorous half of an award site: the layout has to be invisible, so the motion gets all the attention. The deeper version of this discipline is in our guide on how to build an award-winning portfolio site.
A GSAP motion system, not scattered animations
A site this motion-led falls apart if every reveal is hand-tuned in isolation. The fix is one shared motion language — a single set of eases and a consistent duration scale — driven by GSAP and synced to smooth, inertia-based scrolling so the whole page reads as one continuous surface:
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)
// One reveal vocabulary, reused everywhere — consistency = "designed", not "decorated"
gsap.utils.toArray<HTMLElement>('[data-reveal]').forEach((el) => {
gsap.from(el, {
yPercent: 14,
opacity: 0,
ease: 'expo.out',
duration: 1.1,
scrollTrigger: { trigger: el, start: 'top 82%', once: true },
})
})
Using one ease (expo.out) and one timing scale across the entire site is what makes the motion
feel authored. The mechanics behind pinning, scrub and parallax are covered in our
GSAP ScrollTrigger tutorial.
Three.js / WebGL transitions that elevate the imagery
The moments that needed real GPU work — the considered transitions between project visuals — ran on Three.js. The hard rule was never degrade the imagery, so the shader work happens around the image (a displacement-driven reveal between two full-resolution textures) rather than crushing the source. The fragment shader mixes between the outgoing and incoming texture, displacing the UVs by a noise map so the swap feels physical instead of a plain crossfade:
uniform sampler2D uFrom;
uniform sampler2D uTo;
uniform sampler2D uDisp; // displacement / noise map
uniform float uProgress; // 0 → 1, driven by GSAP
varying vec2 vUv;
void main() {
float d = texture2D(uDisp, vUv).r;
vec2 fromUv = vUv + vec2(d * uProgress * 0.12, 0.0);
vec2 toUv = vUv - vec2(d * (1.0 - uProgress) * 0.12, 0.0);
vec4 from = texture2D(uFrom, fromUv);
vec4 to = texture2D(uTo, toUv);
gl_FragColor = mix(from, to, smoothstep(0.0, 1.0, uProgress));
}
GSAP drives uProgress, so the same easing language that governs the DOM also governs the shader —
the WebGL never feels like a separate system bolted on. If you want the full build of this
technique, see our WebGL image displacement hover effect
guide. Two performance habits keep it crisp: textures load at full resolution with anisotropic
filtering, and the renderer caps device pixel ratio at 2 — above that you pay a huge fill-rate cost
for a difference almost no one can see.
import * as THREE from 'three'
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
const tex = new THREE.TextureLoader().load('/work/ford.jpg', (t) => {
t.colorSpace = THREE.SRGBColorSpace
t.anisotropy = renderer.capabilities.getMaxAnisotropy() // stays sharp at angles
})
Keeping it fast under all that motion
An award doesn't survive a janky scroll. The performance discipline was familiar but strict:
animate only transform and opacity so motion stays GPU-composited; lazy-init the WebGL scene and
pause its render loop when it's off-screen; and respect prefers-reduced-motion via
gsap.matchMedia() so the site stays accessible without forking the codebase.
The result: Awwwards Site of the Day
| Recognition | Body | Detail |
|---|---|---|
| Site of the Day | Awwwards | Developer score 7.77 |
| SOTD score | Awwwards | 7.37 |
Awwwards judges design, usability, creativity and content — a Site of the Day on a designer's own portfolio means the build read as craft, not decoration. The developer score of 7.77 is the one I care about most here: it's the jury recognising the engineering specifically — the fidelity, the motion system, and the WebGL holding up under scrutiny. You can see it live at minhpham.design.
What this case study is really about
The lesson generalises past one portfolio: when the client is a designer, the developer's job is fidelity plus life — render the vision exactly, then make it move at 60fps without ever degrading the work. That's the same playbook behind every award winner in the projects archive, from experiential brand sites to kinetic-type portfolios. If you're a designer or studio that needs someone to realise an Awwwards-level concept faithfully, that's exactly what I do.
FAQ
What is the Minh Pham portfolio built with?
A GSAP-driven motion system on the front end with Three.js/WebGL for the heavier image transitions, fluid design tokens for pixel-perfect layout, and inertia-based smooth scrolling — a stack chosen to render a designer's vision at full fidelity and keep it fast.
Who built the Minh Pham website?
Minh Pham owned the design and creative direction; Hon Tran (hontran.dev) was the creative developer responsible for the front-end build, GSAP motion and Three.js/WebGL engineering.
What did the Minh Pham portfolio win?
Awwwards Site of the Day, with a developer score of 7.77 and an SOTD score of 7.37.
How do you make a designer's portfolio feel "designed" rather than decorated?
Build one shared motion system — a single ease and timing scale across the whole site — derive layout from fluid tokens so spacing matches the design at every breakpoint, and drive both the DOM and the WebGL from the same GSAP timeline so nothing feels bolted on.
Let's build something award-worthy
If you're a designer, brand, or agency that needs an Awwwards-level portfolio or product site built with the fidelity and motion the work deserves — that's exactly what I do as a creative developer.
- See how I work and the engagement tiers on the hire page.
- Browse more shipped, awarded work in the projects archive.
- Ready to talk? Let's talk →
Written by Hon Tran — creative developer, founder of hontran.dev, and Awwwards jury member. 11+ years building award-winning, performance-first web experiences (GSAP, Three.js / WebGL, Next.js) for clients worldwide. The first Vietnamese developer to win an international web award. hontran.dev · Behance.