
Why Create a Private Portfolio?
Contemplating I’m already the co-founder of Overpx studio, this can be a query many would possibly ask. The explanations are primarily two:
1. The necessity for a private house: from 2008 to 2014 I had a weblog, fedeweb.internet, the place I used to write down articles about WordPress, JavaScript, Gimp (does it nonetheless exist?), and extra. After closing it, I’ve missed having an area of my very own to share concepts and tasks.
2. A private problem: I wished to problem myself by dealing with on my own each step of the method, from idea to execution. I took care of every stage: ideation, moodboard, design and improvement, with out counting on anybody else.
Earlier than beginning the design course of, I took the Obys course on Awwwards, which I extremely suggest. It offered helpful insights and helped me refine my design strategy.
Inspiration
I’ve all the time been drawn in direction of geometry, particularly circles, precision, and cleanliness in design. Whereas gathering parts for my moodboard, I discovered two specific photos on Savee that had a big impression on the general design of the positioning, shaping its visible route.

Attempt to guess what parts have been influenced by these photos 🙂
Growth
The first objective through the improvement section was to make sure a clean, uninterrupted expertise whereas navigating between pages. I wished to keep away from any pauses or delays, making a seamless movement all through the complete website.
The tech stack
I used my ordinary improvement stack, with one key exception: as an alternative of utilizing a CMS for content material administration, I opted to deal with every little thing immediately by way of a JSON file.
Web page transitions
To deal with the transitions between pages and tasks, I began with this Stackblitz offered by GSAP, particularly developed for Nuxt 3.
The transitions range relying on each the present web page and the vacation spot web page. To handle the totally different instances, I examine the worth of the clicked aspect with the present route.
The clicked aspect worth is managed by the routeStore state, created with Pinia, the place a customized worth is handed.
// strategies navigate for the subsequent challenge hyperlink, inside a single challenge web page
const navigate = (e) => {
const route = e.currentTarget.dataset.url
routeStore.setUrl('/projects-single') // set the routeStore worth
navigateTo({ path: route })
}
The present route is retrieved utilizing the useRoute() composable offered by Nuxt.
These two values are in contrast through the onLeave occasion of the web page. Let’s take a better have a look at the transition between tasks:
onLeave: (el, executed) => {
const routeStore = useUrlStore(),
route = useRoute()
// different situations
// from single to single
if (route.title === 'projects-single' && routeStore.url === '/projects-single') {
// ...
const elementToFlip = el.querySelector('[data-next-project]')
useFlipState().worth = Flip.getState(elementToFlip)
// ...
}
// different situations
},
As you possibly can see, I used Flip, a GSAP plugin that permits to handle seamlessly transition between two states.
Particularly, the aspect to flip is handed to the getState() perform. The worth is then assigned to the useFlipState composable so it may be reused on the vacation spot web page.
// composable useFlipState.js
export const useFlipState = () => useState('flip-state');
Lastly, inside the single challenge web page, the transition between the 2 states is carried out utilizing Flip.from:
const flipTl = Flip.from(useFlipState().worth, {
targets: pictureEls[0], // get the primary picture of the gallery
period: 1.2,
z: 0,
ease: 'power3.out',
// ...
})
// border radius animation
flipTl.fromTo(
pictureEls[0], // first gallery merchandise
{ '--borderRadius': isDesktop ? '20rem' : '10rem' },
{ '--borderRadius': isDesktop ? '2rem' : '2rem', period: 0.6, ease: 'sine.out' },
0
)
// ...
Flip.from() returns a timeline the place you possibly can add all the opposite animations you want within the transition; within the code instance there may be the border-radius animation.
Textual content impact
The objective was to include the idea of a diagonal into the textual content animations, making a dynamic and visually attention-grabbing motion.
To attain this impact, I used the SplitText plugin to separate the textual content into particular person characters, after which I utilized a clipPath together with a diagonal transition (each x and y) for the all pages besides the homepage, the place there’s a horizontal-only transition.
Particularly, I created a worldwide animation, clipTitle, which was then referred to as wherever wanted:
gsap.registerEffect({
title: 'clipTitle',
impact: (targets, config) => {
const tl = gsap.timeline({
defaults: { period: config.period, ease: config.ease },
})
// Verify if the textual content has already been break up, if not, break up it and mark it as executed
const chars = targets[0].classList.incorporates('text-split-done')
? targets[0].querySelectorAll('.char')
: new SplitText(targets, { kind: 'chars', charsClass: 'char' }).chars
if (!targets[0].classList.incorporates('text-split-done')) {
targets[0].classList.add('text-split-done')
}
tl.fromTo(
chars,
{
x: config.x,
yPercent: config.yPercent,
clipPath: 'inset(0% 100% 120% -5%)',
transformOrigin: '0% 50%',
},
{
willChange: 'rework',
clipPath: 'inset(0% -100% -100% -5%)',
x: 0,
yPercent: 0,
stagger: config.stagger,
period: config.period,
ease: config.ease,
},
0.05
)
return tl
},
defaults: { yPercent: 30, x: -30, period: 0.8, ease: 'power3.out', stagger: -0.05 },
extendTimeline: true,
})
Background animation
For the background animation, I used TresJs, a library that permits creating ThreeJS scenes with Vue parts in a declarative means. Whereas I might have used ThreeJS immediately or one other WebGL library, I made a decision to go together with TresJs to check it out and discover its capabilities.
That is the fragment shader for the background distortion:
float circle_s(vec2 dist,float radius){
return smoothstep(0.,radius,pow(dot(dist,dist),.6)*.1);
}
void major(){
vec2 facet=vec2(u_resolution.x/u_resolution.y,1.);
vec2 uv=vUv*facet;
vec2 mouse=vUv-u_point;
mouse.y/=u_ratio;
float noise=snoise(vec3(uv,u_time * 3.));
float noise1=snoise(vec3(uv+.1,u_time * 3.));
float noise2=snoise(vec3(uv-.1,u_time * 3.));
float alpha=(noise+noise1+noise2)/3.;
alpha*=circle_s(mouse,.015 * u_mouseInteraction);
float x=1.-noise;
vec3 color1=vec3(u_color1.x/255.,u_color1.y/255.,u_color1.z/255.);
vec3 color2=vec3(u_color2.x/255.,u_color2.y/255.,u_color2.z/255.);
// Mixing primarily based on mixed noise
float blendFactor=smoothstep(.1,1.,x * 1.);
vec3 blendedColor=combine(color1, color2, blendFactor);
gl_FragColor.rgb=blendedColor;
gl_FragColor.a=alpha;
}
The snoise perform will be discovered on this gist, particularly I used the Simplex3D noise by Ian McEwan and Stefan Gustavson and it was used to create a type of colour distortion impact by manipulating the alpha part.
The colours are managed by a state created with Pinia, which receives the colours in rgb format, from a JSON file.
Keyboard-only utilization
One factor I’m notably happy with is that the complete website is absolutely navigable utilizing solely the keyboard. This consists of the challenge web page, the place you possibly can entry particular person tasks utilizing digit numbers, and inside the single challenge pages, you possibly can navigate from one challenge to the subsequent utilizing the best arrow key.
Different tech elements
For the mouse path impact, I began with this Codrops playground (thanks, Manoela! 😊) and tailored it to go well with my particular use case.
For the scrolling impact on the tasks web page, I primarily based it on this CodePen created by GSAP, additional customizing it to match the positioning’s movement and interplay.
404 web page
I tried to simulate the impact of Newton’s cradle, with the colours of the shader altering randomly every time.
Sounds results
In 2022, I got here throughout this sound library and promised myself I might use it in a challenge sometime. What higher alternative than to make use of it for my very own website?
The library incorporates three sound collections, and on the positioning, I particularly used a couple of sounds from the “sine” assortment.
Conclusions
This challenge has been a satisfying expertise of self-expression and technical exploration. I discovered loads about crafting seamless internet experiences, and I’m excited to use these classes to future tasks.
I’m very grateful for all of the appreciation and awards acquired. Profitable my first SOTD on Awwwards has been a real spotlight of this journey, it feels type of unbelievable.
I hope you loved this behind-the-scenes have a look at my portfolio challenge, maybe it could encourage you to your personal work.