Portfolio 2020

Technologies Used
Craft CMS

Project Overview

This project was a great opportunity to apply the skills I had gained while working at Studio Treble to my own portfolio. I designed the site myself using Adobe XD and built it using Craft CMS, React, Gatsby, GraphQL, ThreeJS, WebGL, GSAP, Lottie-Web, Tailwind, Digital Ocean and Netlify.

Backend and CMS

For the back end of this site I first set up a Digital Ocean Ubuntu droplet. I disabled password logins and used SSH to access the terminal. I manually installed and configured NGINX, PHP, MYSQL, Composer and set up the firewall and PHP extensions needed for Craft using the Linux terminal. I then transferred my local version of the Craft install using SFTP and imported my local database using the MYSQL command line. Once Craft CMS was working on the Digital Ocean server I created a private GraphQL schema in Craft with a password and exposed the required fields to that schema. I then removed all the fields from the public schema. This ensures only only a user with the correct API key can access the data from graphQL.

Animations and Scroll Trigger

The majority of the animations on this site a created using GSAP 3. The scroll animations are created using GSAP and the new scrollTrigger plugin. This allowed me to create animations that could either be triggered on scroll or animated to match the amount the user had scrolled up or down. The text in the homepage hero animation is controlled in this manner. The text and buttons are put into an animation timeline controlled by Scroll Trigger. This allows the text and elements to break away from each other when scrolled down and then return to their original positions when scrolled back up.

Other elements on the homepage such as the Lottie animations are controlled in a similar way and will move towards the center of the screen when scrolled down and away from the center when scrolled up.

WebGl and ThreeJS

The 3D globe is created using Three.js, WebGL and React-Three-Fiber. The geometry of the sphere is controlled by a custom GLSL vertex shader. To create this effect first the vertices of the sphere are collected during the Three.js setup. The positions are then modulated based upon a number that is recalculated every frame. The new number is then passed down to the vertex shader and the new positions for that frame are rendered. The number used to modulate the vertices in the shader is wrapped in a sin function which ensures the modulations loop smoothly. The sphere is rotated in the x, y and z axes by an amount that is updated each frame.

I used React hooks to change the strength of the sphere modulation based on the component state. If the user hovers over the sphere the component state is changed and the modulation amount is increased, amplifying the explosion effect. The the automatic rotation is also stopped, when the user hovers away from the sphere the modulation goes back to the original amount. The zoom buttons use React hooks to change the component state and pass down a different scale amount to the Three.js sphere.

The User can drag and rotate the sphere using the Three.js Orbital controls but the zoom is controlled from the React state updated via the zoom buttons in the bottom right corner.

The colours of the sphere are controlled using a custom GLSL fragment shader. Every frame the current time is passed down to the shader as a uniform. The original coordinates of the current vertex are also passed from the vertex shader down to the fragment shader. These 2 values are then combined to create a colour value for the current fragment shader that will change every frame. A sin wave is again used to create a smooth cycling effect between the colours over time.

Page Transitions

The page transitions are implemented using Gatsby Plugin Transition Link and GSAP. The initial homepage reveal animation is also created using GSAP. In both cases a series of elements are animated in and out of the viewport.

Letters Intro animation

To create the letter animations I needed to wrap the text in a series of span tags in order for them to be accessible to GSAP. In the React component I loop through the text in order to wrap each line, word and letter in a separate span tag. This allows me to control the animation independently for each line of text, each word and each letter. The initial homepage text animation on page load is created by selecting every letter with GSAP and setting them to a random, value for x, y, skew and rotation. I then animate them into their default positions.

Lottie Animatons

The Lottie animations are added using the Lottie React Web package which allows me to control the Lottie animation objects using React state. The animation files are sourced from lottiefiles.com and are CMS driven, The animation URL is added in the CMS entry and this is pulled in at build time. To make the process smoother I use the Gatsby node file to programmatically download the animation json file at build time and pass it down as page context. This means the animation json files are available straight away and do not need to be pulled in with client runtime data fetching.

I use the GSAP Scroll Trigger to control the play and pause state of these animations. Each Lottie animation is created in a paused state. When the animation is scrolled into view I use React hooks to change the component state, this state update starts the Lottie animation that is currently visible on screen. Once the animation is scrolled off screen the component state is updated again and once the animation is paused. This stops the DOM playing multiple animations continuously while not in view.

Global State

The global state for the site was created using the React Context API. This allowed me to pass state to any component without prop drilling down multiple levels. One use of this global state is to control the colour of the burger nav in the site head. When scrolled to certain points an action is dispatched using a dispatch function to update the global state, which then changes the burger nav colour. The global state context was also initially used to control a dark mode toggle for the entire site. This worked well but I later removed it as the dark mode didn't work well enough with the sites design style.