Constructing a private portfolio is among the most difficult initiatives for any designer or developer. You’re by no means absolutely happy with the consequence. Every iteration raises new questions, and the method can simply flip into an limitless cycle of rethinking and rebuilding.
This yr marked a brand new chapter for me as I turned a contract developer, and it felt like the fitting second to revamp my portfolio — my first new launch in six years. The mission gave me the chance to discover new concepts, push my technical boundaries, and rethink how I current my work.
On this case examine, I’ll share insights into the inventive course of, design selections, and technical challenges behind the mission.
A. Idea & Expertise
The principle purpose of this portfolio was to create an area to showcase each my initiatives and the WebGL experiments I’ve been creating over the previous few months. From the start, I wished to combine WebGL in a refined approach. The thought was to discover a steadiness between a 2D interface that stays clear and readable, and a 3D setting that provides depth and motion.
The mission began with easy sketches in my pocket book, which helped me shortly outline the construction and consumer circulation earlier than shifting into the design and improvement phases.

B. Inspirations & Design
With a background in design, I challenged myself to create the interface alone. The method was lengthy and generally demanding. It concerned many iterations and a whole lot of refinement earlier than I reached a route I used to be pleased with.
I’ve all the time been keen about typography and printed posters. That naturally drew me towards robust graphic techniques and expressive typographic compositions. The visible route attracts closely from the Swiss Fashion, with a intentionally restricted coloration palette of orange, white, and black.

Most of my inspiration got here from offline experiences. I spent a whole lot of time in bookstores, shopping design, portray, and images books and learning their layouts and typographic techniques. I like taking the time to take a look at grids, margins, and kind selections, after which translating these concepts into the net. These references helped form a transparent and constant visible id. I additionally explored references on Pinterest, the place I usually search for inspiration.
On the identical time, I wished to introduce a 3D dimension utilizing WebGL, a subject I’ve been exploring for a number of months. One of many most important challenges was to seek out the fitting steadiness between this experimental method and a extra structured, editorial aesthetic.
For the homepage, this translated into an overarching 3D geometry that comes with previews of all my initiatives. The method concerned many iterations, experimenting with totally different layouts and interactions earlier than arriving on the closing model. Right here’s a glimpse of the varied iterations I examined:
C. Growth Overview
From the beginning, I wished full management over the event course of, so I made a decision to keep away from frameworks and construct the portfolio utilizing solely vanilla JavaScript. This stored the stack light-weight and helped me higher perceive each a part of the codebase. I additionally carried out a easy PJAX routing system to allow easy, animated web page transitions.
For styling, I relied on SCSS with the BEM methodology, maintaining the code modular and maintainable. All web page information is saved in JSON, offering flexibility with out the necessity for a CMS or static website generator.
For the WebGL elements, I used Three.js mixed with GLSL, enabling 3D geometries and interactive visualizations. GSAP dealt with all of the animations throughout the portfolio, whereas Lenis ensured a easy scrolling expertise.
Undertaking Construction
The portfolio is organized to remain modular and simple to take care of. Web page information is saved in JSON, whereas WebGL elements, reusable JavaScript modules, and SCSS types are clearly separated into devoted directories. This construction makes it simpler to iterate and prolong the mission over time.
Right here’s an summary of the mission construction:
src/
├── information/ # JSON information for every web page
│ ├── about.json
│ ├── archive.json
│ └── ...
├── glsl/ # GLSL shaders
│ ├── archive/
│ │ ├── fragment.glsl
│ │ └── vertex.glsl
│ ├── modules/ # Reusable GLSL modules (noise, utils)
│ ├── work/
│ └── ...
├── js/ # Shopper-side JavaScript
│ ├── index.js # Principal app entry level
│ ├── animations/ # GSAP web page transitions & preloader
│ ├── elements/ # Reusable UI elements
│ │ ├── Availability.js # Availability standing badge
│ │ ├── Cross.js # Interactive cross cursor
│ │ ├── Dimensions.js # Viewport dimensions tracker
│ │ ├── GridHelper.js # Dev grid overlay
│ │ ├── GridRules.js # Grid rule traces
│ │ ├── LocaleTime.js # Native time show
│ │ ├── ScrollIndicator.js # Scroll progress indicator
│ │ ├── ViewSwitcher.js # Listing/Overview view toggle
│ │ └── ...
│ ├── pages/ # Web page controllers
│ │ ├── About.js
│ │ ├── Archive.js
│ │ └── ...
│ ├── utils/ # Helpers (Lerp, Easings, Routing…)
│ └── webgl/ # WebGL renders
│ ├── Canvas.js
│ ├── archive/
│ ├── index/
│ ├── overview/
│ └── work/
└── scss/ # SCSS types
D. Animations & Movement
On this part, I’ll stroll by a few of the movement ideas I used within the mission.
Grid guidelines
To strengthen the editorial and pixel-perfect aesthetic of the interface, I launched a small interactive easter egg. When the consumer clicks the central cross, a set of grid guidelines dynamically body the principle web page title.
Right here’s a preview:
The thought is straightforward: I retrieve the place of components marked with data-rules utilizing getBoundingClientRect(), then dynamically generate 4 traces, one for all sides, positioned with transforms to border the aspect.
Implementation
The script calculates the aspect’s bounding field and creates horizontal and vertical guides positioned relative to the viewport.
<!-- Principal title -->
<h1>A</h1>
<!-- Button -->
<button sort="button" aria-label="Toggle grid guidelines">Toggle</button>
<!-- Guidelines: 4 guidelines created in JavaScript -->
<div class="grid-rules"></div>
class App {
constructor() {
// DOM
this.DOM = {
button: doc.querySelector("button"),
title: doc.querySelector("h1"),
guidesContainer: doc.querySelector(".grid-rules"),
}
// States
this.isActive = false
// Listeners
this.createGuides()
}
/**
* Guides
*/
createGuides() {
this.DOM.guidesContainer.innerHTML = ""
const rect = this.DOM.title.getBoundingClientRect()
const positions = [
{ type: "horizontal", pos: rect.top },
{ type: "horizontal", pos: rect.bottom },
{ type: "vertical", pos: rect.left },
{ type: "vertical", pos: rect.right },
]
positions.forEach(({ sort, pos }) => {
const information = doc.createElement("div")
information.className = `grid-rules__guide grid-rules__guide--${sort}`
gsap.set(information, {
x: sort === "vertical" ? pos : 0,
y: sort === "horizontal" ? pos : 0,
opacity: this.isActive ? 1 : 0,
});
this.DOM.guidesContainer.appendChild(information)
})
}
}
Every information is a 1px line that spans the total width (horizontal) or top (vertical) of the viewport. The container is mounted to the viewport whereas guides are completely positioned inside it:
.grid-rules {
place: mounted;
inset: 0;
pointer-events: none;
}
.grid-rules__guide {
place: absolute;
prime: 0;
left: 0;
background-color: pink;
&--horizontal {
width: 100%;
top: 1px;
}
&--vertical {
width: 1px;
top: 100%;
}
}
Interplay & Animation
The visibility of the guides is toggled on button click on utilizing GSAP, which easily fades the traces out and in.
addEventListeners() {
this.DOM.button.addEventListener("click on", this.handleClick);
}
handleClick(occasion) {
occasion.preventDefault();
this.isActive = !this.isActive;
gsap.to(".grid-rules__guide", {
opacity: this.isActive ? 1 : 0,
length: 0.5,
});
}
It is a simplified model of the system carried out within the closing mission, which you’ll discover right here:
Navigation Switcher
Micro-interactions typically play a key function in shaping the general consumer expertise. For the principle navigation, I carried out a dynamic masks switcher that follows the cursor and adapts to the width of the hovered hyperlink.
When the consumer hovers a navigation merchandise, the masks easily resizes and repositions itself to match the hyperlink’s dimensions, creating extra responsive and tactile suggestions.
Right here’s a preview:
Idea
The interplay depends on monitoring the hovered aspect’s bounding field and updating the masks’s dimension and place accordingly. As an alternative of utilizing static hover states, the masks behaves as a shared visible indicator that transitions between hyperlinks.
This creates:
- A stronger visible hierarchy.
- Smoother navigation suggestions.
- A extra dynamic and editorial navigation expertise.
Implementation
The system listens for hover occasions on navigation hyperlinks, retrieves their dimensions utilizing getBoundingClientRect(), and updates the masks’s remodel and dimension to match the energetic aspect.
The transition between states is interpolated to maintain the movement fluid and aware of cursor motion.
<nav class="navigation">
<ul class="navigation__list">
<li class="navigation__item">
<a category="navigation__link" href="#">Dwelling</a>
</li>
<li class="navigation__item">
<a category="navigation__link" href="#">About</a>
</li>
</ul>
<div class="navigation__mask"></div> <!-- We animate this aspect -->
</nav>
updateMaskPosition(goal, length = 0) {
const targetRect = goal.getBoundingClientRect()
const navRect = this.DOM.navigation.getBoundingClientRect()
const x = targetRect.left - navRect.left
const y = targetRect.prime - navRect.prime
const { width, top } = targetRect
gsap.to(this.DOM.navigationMask, {
x,
y,
width,
top,
length,
ease: "power3.out",
})
}
Outcome
This method creates a steady movement expertise the place the navigation feels reactive moderately than state-based, reinforcing the general movement language of the portfolio.
Try this simplified model I made for my portfolio:
E. Remaining Contact
Remaining touches are sometimes probably the most difficult a part of a mission. Even after refining the design, animations, and interactions, I nonetheless felt one thing was lacking, one thing that would assist the mission stand out from different developer and designer portfolios.
To push the grid guidelines system additional, I launched an interactive ruler function impressed by Figma. Customers can place their very own markers immediately on the interface and place them wherever they need. This function reinforces the general editorial route of the web site whereas turning the format itself into an interactive expertise.
To increase this concept even additional, I additionally added the power to toggle the format grid used all through the positioning with a keyboard shortcut (Choice + G), permitting customers to disclose the underlying construction of the design. It’s a instrument I personally use in each mission to make sure alignment and precision, and I assumed it will be enjoyable to make it accessible to customers as properly.
These refined however playful options helped give the portfolio a stronger id. They bridge the hole between design tooling and consumer expertise, and spotlight how vital construction, precision, and experimentation are on this mission.
F. Conclusion & Learnings
This portfolio is a vital milestone in my journey as a designer and developer. It gave me the prospect to discover new concepts, apply the editorial design method I’m keen about, and push my WebGL experiments additional.
Alongside the way in which, I needed to always steadiness experimentation and usefulness, and think twice about what makes an interplay really feel significant moderately than simply ornamental.
Reasonably than a completed product, this portfolio is an evolving playground, an area for steady exploration, experimentation, and progress.
I hope you loved this case examine. When you’ve got any questions or suggestions, be happy to achieve out!


