How to Build a Creative Portfolio with React JS and WebGL
The behind the scenes of the making of Robin Noguier’s portfolio
In this article I’m going to explain the making of the Robin Noguier’s portfolio by answering the questions of group of international developers.
I’ll show you the process, the tools and my personal approach to a website full of interactions and animations.
This website is built in React JS, using Next.js as a framework in order to delegate effectively the routing and the static-generation.
Contents are managed by Prismic — I put a lot of effort into creating custom modules in order to simplify the contents integration and give to Robin a wide range of customisations — some of them include the possibility to manage the number of columns on the grids, enable/disable parallax effects, add borders and change the background color on certain sections.
HTML and WebGL feel like 2 different worlds from a development perspective. How did you integrate the WebGL part?
That’s tricky to implement, and creativity is needed from the developer side — just think of WebGL as a layer that can stand in front or behind HTML elements.
Since it’s a multi-page website, with transitions between them, the canvas element is shared between pages and always present — based on the events, such as routing changes, I move the WebGL elements according to the design requests.
When I build website using Next.js, like that one, I import Three.js using the React renderer R3F.
The scroll in homepage feels really good. How did you achieve that?
My intention was to give a natural feedback and a smooth experience to the user.
Handling the wheel event, and using the delta value to snap between items, has always been tough to implement: I can’t hide that I struggled to find the right balance.
My ace in the hole is Lethargy, a tool that I used to distinguish intention from inertia — being able to recognise when the intentional scroll ends, lets me know when I have to start the transition to the next item.
When the transition between pages starts, the curtain hides all the thumbnail except the current one. How did you achieve that?
Using React with R3F lets me treat every WebGL element as a single component that reacts to state changes.
This means versatility in writing code, and brings all the advantages of React into Three.js: independence, reusability and isolation.
Being able to pass props to a WebGL element, such as isCurrent, lets me easily exclude it from transitions, or do something else.
How did you manage the transitions between pages?
Performance wise, I decided to have one single animation that orchestrates the transition from one page to another, dispatching the progress to the whole application — in that way I’ve been able to keep all the changes perfectly synchronised, from the HTML elements to the WebGL ones.
Can you name the tools you used to manage the animations?
The animation library I have chosen for this project is React-Spring, a library made for the React ecosystem that interpolates values using spring physics.
For the page-change animation I used the useTransition hook API as it allows to replace one component to another with a transition.
In some particular cases I used easing curves instead of spring physics, because React-Spring, by its nature, doesn’t allow to set the duration — in those cases I used Bezier-Easing with the help of Easing.co.
How did you make the light effect visible when hovering over the images in homepage?
All the images in homepage, along with the video preview and the background, are draw by Three.js using the React renderer R3F.
Using WebGL allowed me to write shaders to handle all those effects on the images, like bind the light effect to the mouse movement.
How did you keep all the animations perfectly synchronised in Next.js? Did you use a global store that dispatches the progress between components?
I put a lot of effort into finding the way to share one single animation between components.
I excluded the store from the beginning, for the simple reason that it isn’t made for continuous updates, just like an animation.
The solution I opted for was using a global context and dispatching the React-Spring interpolation object over the application, so that every component could attach to it and create its own transition.
Inspecting the code I noticed you used Web Workers. What do you use them for? What made you realise that you had to opt for using Web Workers?
I used Web Workers in the homepage — the project cases scroll needs a lot of CPU effort, and on less powerful computers this compromised performance.
In detail, I have one Web Worker to project the images 3D position to screen coordinates, so that I can mask the titles with clip-path.
A second Web Worker is used to observe the wheel input and snap to the right project case.
What performance hurdle / bottleneck is Web Workers solving on your site?
When the transition from one page to another starts, a lot of things happen and performance suffers.
Web Workers come to help by running scripts in background threads, without interfering with the user interface — in this way I still managed to mask the titles preserving good performance, even though I’m moving many elements at the same time.
What did you use to integrate the page scrolling with the transition animations?
I didn’t use any specific library, but I decided to use a custom scroll made by me in order to have total control of what happens — that’s crucial performance wise.
Basically a custom scroll works by listening for the wheel event, and using the delta value to move elements.
Since the case-study pages are rich in content, I chose to move only the blocks that enter in the viewport and share the progress within it through a React Context — in this way I’ve been able to bind any kind of transition to the scroll.
Animations on this site all felt purposeful — How do you decide where to add animations in your design?
This is the designer’s job 😁 A strong collaboration between developers and designers is fundamental to find the right path — designers have creativity on their side, but we, as developers, are in charged to give them cues and solutions.
What is your process when starting from scratch on a new project like this? Since you’re creating a site for someone else, do the designers have always a clear idea of what they want?
No they don’t — but developers should always predict which direction the project will take, and this awareness is acquired only with a right amount of experience.
Besides this, in my view, there are rules to follow to make the work easier.
My first advice is to always start from frameworks / libraries with a strong community behind them, because that means documentation, videos, articles and many developers ready to help.
The second advice is to ask a lot of questions at the beginning to get a precise idea of the designer’s thinking — if there’re doubts, this is the moment to find solutions.
Last but not least, developers should always write code as it was open source: maintainable and easy to read — this allows for easier changes which results in faster changes and a lot less risk.
How do you manage to use Memoji as an icon / profile picture?
First of all you need to own an Apple device — just create a new note from iPhone and insert the Memoji, then open it with Notes app on Mac and from there you can download it as an image or video.
How do you access the animated version of your Memoji on browsers?
When you download an animated Memoji, Apple gives you a .mov file — at that point you just need to convert it to WebM, a media file format designed for the web that supports the alpha transparency.
Unfortunately Safari doesn’t support it yet, so I switched to an animated GIF.
I hope you found the reading helpful and please, use the comments below if you have questions.