pwshub.com

Case Study: Federico Pian Portfolio — 2024


Why Create a Personal Portfolio?

Considering I am already the co-founder of Overpx studio, this is a question many might ask. The reasons are mainly two:

1. The need for a personal space: from 2008 to 2014 I had a blog, fedeweb.net, where I used to write articles about WordPress, JavaScript, Gimp (does it still exist?), and more. After closing it, I’ve missed having a space of my own to share ideas and projects.

2. A personal challenge: I wanted to challenge myself by handling by myself every step of the process, from concept to execution. I took care of each stage: ideation, moodboard, design and development, without relying on anyone else.

Before starting the design process, I took the Obys course on Awwwards, which I highly recommend. It provided useful insights and helped me refine my design approach.

Inspiration

I’ve always been drawn towards geometry, especially circles, precision, and cleanliness in design. While gathering elements for my moodboard, I found two particular images on Savee that had a significant impact on the overall design of the site, shaping its visual direction.

Try to guess what elements have been influenced by these images 🙂

Development

The primary goal during the development phase was to ensure a smooth, uninterrupted experience while navigating between pages. I wanted to avoid any pauses or delays, creating a seamless flow throughout the entire site.

The tech stack

I used my usual development stack, with one key exception: instead of using a CMS for content management, I opted to handle everything directly via a JSON file.

  • Nuxt for static site generation
  • GSAP for animation
  • TresJs for Webgl
  • Tailwindcss for CSS
  • Pinia for state management

Page transitions

To handle the transitions between pages and projects, I started with this Stackblitz provided by GSAP, specifically developed for Nuxt 3.

The transitions vary depending on both the current page and the destination page. To manage the different cases, I compare the value of the clicked element with the current route.

The clicked element value is managed through the routeStore state, created with Pinia, where a custom value is passed.

// methods navigate for the next project link, inside a single project page
const navigate = (e) => {
  const route = e.currentTarget.dataset.url
  routeStore.setUrl('/projects-single') // set the routeStore value
  navigateTo({ path: route })
}

The current route is retrieved using the useRoute() composable provided by Nuxt.

These two values are compared during the onLeave event of the page. Let’s take a closer look at the transition between projects:

onLeave: (el, done) => {
  const routeStore = useUrlStore(),
    route = useRoute()
  // other conditions
  // from single to single
  if (route.name === 'projects-single' && routeStore.url === '/projects-single') {
    // ...
	const elementToFlip = el.querySelector('[data-next-project]')
	useFlipState().value = Flip.getState(elementToFlip)
	// ...
  }
	// other conditions
},

As you can see, I used Flip, a GSAP plugin that allows to manage seamlessly transition between two states.

Specifically, the element to flip is passed to the getState() function. The value is then assigned to the useFlipState composable so it can be reused on the destination page.

// composable useFlipState.js
export const useFlipState = () => useState('flip-state');

Finally, within the single project page, the transition between the two states is performed using Flip.from:

const flipTl = Flip.from(useFlipState().value, {
  targets: pictureEls[0], // get the first image of the gallery
  duration: 1.2,
  z: 0,
  ease: 'power3.out',
  // ...
})
// border radius animation
flipTl.fromTo(
  pictureEls[0], // first gallery item
  { '--borderRadius': isDesktop ? '20rem' : '10rem' },
  { '--borderRadius': isDesktop ? '2rem' : '2rem', duration: 0.6, ease: 'sine.out' },
  0
)
// ...

Flip.from() returns a timeline where you can add all the other animations you need in the transition; in the code example there is the border-radius animation.

Text effect

The goal was to incorporate the concept of a diagonal into the text animations, creating a dynamic and visually interesting movement.

To achieve this effect, I used the SplitText plugin to split the text into individual characters, and then I applied a clipPath in combination with a diagonal transition (both x and y) for the all pages except the homepage, where there is a horizontal-only transition.

Specifically, I created a global animation, clipTitle, which was then called wherever needed:

gsap.registerEffect({
  name: 'clipTitle',
  effect: (targets, config) => {
    const tl = gsap.timeline({
      defaults: { duration: config.duration, ease: config.ease },
    })
    // Check if the text has already been split, if not, split it and mark it as done
    const chars = targets[0].classList.contains('text-split-done')
      ? targets[0].querySelectorAll('.char')
      : new SplitText(targets, { type: 'chars', charsClass: 'char' }).chars
    if (!targets[0].classList.contains('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: 'transform',
        clipPath: 'inset(0% -100% -100% -5%)',
        x: 0,
        yPercent: 0,
        stagger: config.stagger,
        duration: config.duration,
        ease: config.ease,
      },
      0.05
    )
    return tl
  },
  defaults: { yPercent: 30, x: -30, duration: 0.8, ease: 'power3.out', stagger: -0.05 },
  extendTimeline: true,
})

Background animation

For the background animation, I used TresJs, a library that allows creating ThreeJS scenes with Vue components in a declarative way. While I could have used ThreeJS directly or another WebGL library, I decided to go with TresJs to test it out and explore its capabilities.

This 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 main(){
	vec2 aspect=vec2(u_resolution.x/u_resolution.y,1.);
	vec2 uv=vUv*aspect;
	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.);
	// Blending based on combined noise
	float blendFactor=smoothstep(.1,1.,x * 1.);
	vec3 blendedColor=mix(color1, color2, blendFactor);
	gl_FragColor.rgb=blendedColor;
	gl_FragColor.a=alpha;
}

The snoise function can be found in this gist, in particular I used the Simplex3D noise by Ian McEwan and Stefan Gustavson and it was used to create a sort of color distortion effect by manipulating the alpha component.

The colors are managed through a state created with Pinia, which receives the colors in rgb format, from a JSON file.

Keyboard-only usage

One thing I’m particularly proud of is that the entire site is fully navigable using only the keyboard. This includes the project page, where you can access individual projects using digit numbers, and within the single project pages, you can navigate from one project to the next using the right arrow key.

Other tech aspects

For the mouse trail effect, I started with this Codrops playground (thanks, Manoela! 😊) and adapted it to suit my specific use case.

For the scrolling effect on the projects page, I based it on this CodePen created by GSAP, further customizing it to match the site’s flow and interaction.

404 page

I attempted to simulate the effect of Newton’s cradle, with the colors of the shader changing randomly each time.

Sounds effects

In 2022, I came across this sound library and promised myself I would use it in a project someday. What better opportunity than to use it for my own site?

The library contains three sound collections, and on the site, I specifically used a few sounds from the “sine” collection.

Conclusions

This project has been a fulfilling experience of self-expression and technical exploration. I learned a lot about crafting seamless web experiences, and I’m excited to apply these lessons to future projects.

I’m very grateful for all the appreciation and awards received. Winning my first SOTD on Awwwards has been a true highlight of this journey, it feels kind of incredible.

I hope you enjoyed this behind-the-scenes look at my portfolio project, perhaps it would inspire you for your own work.

Source: tympanus.net

Related stories
1 month ago - Behind the scenes of one of Artemii Lebedev's projects: Armur, a portfolio website for the film industry, created for Alexandra Murgu.
1 month ago - During Mount Media's rebranding journey, its website became the ultimate stage for showcasing its "we know how to result" vibe. Here is a long story short about teamwork behind it.
6 days ago - Learn about the challenges and creative solutions that shaped Treize Grammes’ bold rebrand and interactive design.
3 weeks ago - Pilot testing as a PM can help you gather real user insights, de-risk ideas, adapt quicker, and avoid expensive mistakes. The post Conducting effective pilot testing as a product manager appeared first on LogRocket Blog.
2 weeks ago - Customer validation is the step in a customer development process where you validate your solutions against customer needs and expectations. The post Customer validation: Building consistent and repeatable sales appeared first on...
Other stories
2 hours ago - Data visualization tools let you turn raw numbers into visuals — so you have some guidance when making design choices. I talk more on this in today's blog. The post Using data visualization tools as a UX/UI designer appeared first on...
2 hours ago - So, you’re a JavaScript developer? Nice to hear — what do you think this code returns? And yeah, it’s a […] The post Six things you may not know about JavaScript appeared first on LogRocket Blog.
2 hours ago - Try supporting NPS with CES, which helps you uncover where customers struggle, and CSAT, which focuses on product satisfaction. The post Why CES will give you more insights than CSAT and NPS appeared first on LogRocket Blog.
2 hours ago - IdPs (aka Identity providers) are crucial in the modern digital world. Learn what they are and what they do.
4 hours ago - Mobile app development has evolved tremendously, and creating a robust, full-featured app today involves mastering both the front-end and back-end. If you're looking to build something practical, like an e-commerce platform, and want to...