← All articles

[ Blog ]

June 27, 2026

8 min read

Mathijs Hanenkamp: Photography Portfolio Case Study

A photography portfolio website case study — how the Mathijs Hanenkamp site fused WordPress, GSAP & WebGL into an award-winning, image-led experience (Awwwards Honorable Mention).

Case StudyAwwwardsWordPressGSAPThree.jsWebGLPhotography
Mathijs Hanenkamp: Photography Portfolio Case Study

When the entire product is a photographer's eye, the website has one job: get out of the way and make the work feel inevitable. This Mathijs Hanenkamp case study breaks down how I built a photography portfolio website that does exactly that — an image-led experience woven from WordPress, GSAP and WebGL that earned an Awwwards Honorable Mention. Mathijs is a portrait and documentary photographer based in Nijmegen, the Netherlands, and the brief was deceptively simple: build something that elevates the photography without ever competing with it. Here's the craft behind it, written by the developer who shipped it.

Who built it — and why the developer credit matters

The Mathijs Hanenkamp site was a collaboration between designer Huy Phan — an Awwwards jury member — and Hon Tran as the creative developer. That's me.

I lead with that for a concrete reason. A photography portfolio is the hardest kind of site to add motion to, because every effect risks doing harm: a heavy transition that softens an image, a scroll animation that distracts from a composition, a clever hover that pulls the eye away from the face in frame. The win condition isn't "more animation" — it's motion that makes the photographs feel more present. I've spent 11+ years building award-winning web experiences for clients across Norway, Denmark, Sweden, Malta, Germany and Vietnam; I've been named Awwwards "Independent of the Year" twice and I sit on the Awwwards jury. On a portfolio like this, that experience is the line between motion that serves the work and motion that buries it.

The brief: the photography leads, the site elevates

Portrait and documentary work lives or dies on presence — the moment, the expression, the light. The mandate from the design was a restrained, near-white canvas (the palette is essentially pure #ffffff) where the images are the only color in the room. Three constraints shaped every engineering decision:

  • Never degrade the image. Crispness was non-negotiable. No effect could soften, compress, or crop a photograph in a way the photographer wouldn't sign off on.
  • Motion as choreography, not decoration. Loading transitions, gallery reveals, and menu hover states all had to feel intentional — a single directed sequence, not a pile of one-off tricks.
  • Fast under heavy imagery. A photography site is, by definition, a megabyte-heavy site. It still had to load quickly and scroll at 60fps on a mid-range laptop and a phone.

The craft: building award-level motion on a WordPress stack

Here's the part most people get wrong about this project when they see it: it runs on WordPress. There's a persistent myth that award-level motion requires a fully custom JavaScript framework and that a CMS like WordPress caps you at template-grade output. It doesn't. The trick is treating WordPress as a content layer and building the experience as a proper front-end motion system on top of it — GSAP for the timeline choreography and Three.js / WebGL for the image rendering. The result is a site the photographer can update himself that still competes on Awwwards.

Image-led page and loading transitions

The first impression is a loading-to-content transition, and on a portfolio it has to do double duty: cover the asset load and introduce the first image as a hero moment. The principle is to treat the whole sequence as one GSAP timeline — the loader, the cover wipe, and the first image reveal are choreographed together so the eye never hits a dead frame.

import gsap from 'gsap'

function introTimeline(onReady: () => void) {
  const tl = gsap.timeline({ defaults: { ease: 'expo.inOut', duration: 1 } })

  tl.to('[data-loader-bar]', { scaleX: 1, transformOrigin: 'left' })
    .add(onReady)                                          // content mounted behind the cover
    .to('[data-loader]', { yPercent: -100 }, '+=0.05')    // lift the cover
    .from('[data-hero-image]', { scale: 1.08, autoAlpha: 0 }, '<0.15') // settle the first photo
    .from('[data-hero] [data-stagger]', { yPercent: 110, stagger: 0.05 }, '<0.2')

  return tl
}

The position parameters ('<0.15', '<0.2') overlap the hero image reveal with the cover lift, so the first photograph is already settling into place before the loader clears. That overlap is the whole difference between "a page loaded" and "an experience began."

WebGL that elevates the image instead of crushing it

Three.js handles the heavier image treatments — including the fluid, distortion-driven transitions between gallery shots. The hard rule from the brief (never degrade the image) dictates a specific approach: load textures at full resolution and do the shader work around the photo — a fluid displacement on transition, a subtle settle — rather than permanently altering the source pixels. On a WebGL plane that means respecting device pixel ratio, color space, and anisotropy so nothing softens at angles:

import * as THREE from 'three'

const loader = new THREE.TextureLoader()
loader.load('/uploads/portrait.jpg', (texture) => {
  texture.colorSpace = THREE.SRGBColorSpace
  texture.anisotropy = renderer.capabilities.getMaxAnisotropy() // crisp at any angle
  texture.minFilter = THREE.LinearMipmapLinearFilter
  texture.generateMipmaps = true
})

// Cap DPR: above 2 you pay a huge fill-rate cost for a difference almost nobody can see.
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

The fluid transition itself is a fragment shader that mixes between the outgoing and incoming texture using a displacement value driven by progress — the image appears to flow into the next rather than hard-cut. If you want the mechanics behind this class of effect, I wrote a full guide on the WebGL image displacement hover effect that uses the same GLSL technique.

Immersive scroll and the menu microinteractions

Away from the WebGL planes, the rest of the site runs on GSAP and ScrollTrigger: gallery items rise and settle as they enter the viewport, and the menu hover states — which the Awwwards community called out specifically — animate on transform and opacity only so they stay buttery. The rule that keeps a motion-dense, image-heavy page fast is boring but absolute:

import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)

gsap.utils.toArray<HTMLElement>('[data-photo]').forEach((el) => {
  gsap.from(el, {
    yPercent: 12,
    autoAlpha: 0,
    ease: 'expo.out',
    duration: 1,
    scrollTrigger: { trigger: el, start: 'top 88%', once: true },
  })
})

A photography site is the worst-case scenario for performance: large images everywhere. The discipline that kept it quick:

  • Animate only transform and opacity. They're GPU-composited and skip layout/paint, so the main thread stays free for scrolling through dozens of photos.
  • Lazy-init the WebGL. The Three.js scene spins up only when a gallery section nears the viewport, and pauses its render loop when scrolled off-screen — no GPU cycles burned on what you can't see.
  • Responsive, mip-mapped textures. Serve appropriately sized images per breakpoint and let mipmaps handle the downscale, so a portrait never ships a 4000px file to a phone.
  • Respect the visitor. gsap.matchMedia() strips the heavy motion under prefers-reduced-motion, keeping the site accessible without forking the code.

The result: an Awwwards Honorable Mention

The site earned an Awwwards Honorable Mention, with a community rating averaging around 8.5, and was tagged for its interaction and microinteraction design. You can see it live at mathijshanenkamp.com and the award listing on Awwwards.

What that recognition signals for a buyer is the point of this whole case study: the jury rewarded a site where the photography is unmistakably the star, and the motion is what makes it feel cinematic. For a portrait and documentary photographer, that's the brief executed exactly — the work leads, the experience elevates.

What this case study is really about

The generalisable lesson: award-level motion is a front-end engineering decision, not a stack decision. WordPress didn't hold this site back — a disciplined GSAP + WebGL layer on top of it delivered an experience that competes with fully custom builds, while leaving the photographer able to manage his own galleries. The same playbook — content-managed CMS, a real motion system, and ruthless performance discipline — is what carries any image-heavy brand or portfolio site. You can see it applied differently in the Mat Voyce kinetic typography case study and the Iventions award-winning events site, and if you're building your own, the guide on how to build an award-winning portfolio site walks through the fundamentals.

FAQ

What is the Mathijs Hanenkamp website built with?

WordPress as the content layer, with GSAP driving the motion system and Three.js / WebGL handling the image transitions and fluid rendering — a stack chosen so the photographer can manage his own galleries while the front end still delivers award-level motion.

Can you build an Awwwards-level site on WordPress?

Yes. WordPress is a content layer; the experience is built as a custom front-end motion system (GSAP + WebGL) on top of it. This site is the proof — it earned an Awwwards Honorable Mention while running on WordPress.

Who designed and developed the Mathijs Hanenkamp site?

It was a collaboration between designer Huy Phan (an Awwwards jury member) and Hon Tran as the creative developer responsible for the front-end, GSAP motion and WebGL engineering.

How do you add motion to a photography site without hurting the images?

Load textures at full resolution and do shader work around the photo rather than altering the source, cap device pixel ratio at 2, use anisotropy and mipmaps for crispness, animate only transform/opacity, and lazy-init WebGL so heavy galleries stay fast.

Let's build something award-worthy

If you're a photographer, brand, or agency that needs an image-led portfolio or WebGL photography site that elevates the work instead of competing with it — that's exactly what I do as a creative developer.


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, WordPress) for clients worldwide. The first Vietnamese developer to win an international web award. hontran.dev · Behance.