portfolio

Live
image of max (my dog) looking very peaceful

motivation

Every developer needs a portfolio! Whether it be to showcase all of the cool projects they've created, give others a glimpse into who they are, or simply to share pictures of their beloved animals with the world! One of the biggest goals of this project was to create an enjoyable experience for anyone who stumbles upon it and I hope you had as much fun exploring it as I did making it.

tech

process

Ever since creating Triva, my full-stack community-based trivia platform, having a solid planning and design phase has become an important part of my development process. Both phases gave me a clear sense of direction I could rely on for the rest of the project. To start, I outlined the three main dependencies for this project, Next.js as the core of the application, TypeScript for type safety, and Playwright for end-to-end testing.

My approach for this project was reversed from the usual, in that I started with the design. Going straight into Figma, taking all of the lessons I'd learned from my past projects with me, I meticulously built up the design, component by component, page by page, theme by theme.

Design can be challenging at times (really, most of the time for me!). Sometimes the creativity flows; other times, not so much. When I found myself in a creative block, I often realized all I needed was a healthy little break. I reminded myself, many times throughout the process, "Ideas cannot be rushed". Whenever a "What if...?" thought popped into my head, I would not hesitate to explore it! This mindset guided me through the entirety of the project, from design to implementation. Playing with the end result brings me true happiness, and I hope it does for you too!

With the design intact, I jumped back into the planning. First, I took the design and outlined the core components I thought I would need on pen and paper. For each component, I then mapped color-specific properties, like border-color and background-color, to CSS variables that would differ between the different themes. Doing so, I felt, would lead to a more organized approach to theming, and lo and behold, it did. With the initial plan and design completed, I could finally begin!

Just like with Triva, I outline an initial, and ever-growing, to-do list, which now took the form of a neat and tidy markdown file (a step up from the .txt files and notepad application I was using before!). The implementation went much like the design. Component by component. Section by section. Page by page. I found this to be a very nice workflow. Breaking things down in this manner helped me avoid feeling too overwhelmed at any point in time and allowed me to spot issues before moving on to the next section.

Of course, I didn't limit myself to the exact plan I laid out. For instance, the Voronoi portrait slider in the contact section and Polyrhythm Visualizer in the About section grid were left as black boxes in my initial design for future ideas to come! It was my first portfolio and I wanted to have as much fun as possible building it—both features were a joy to implement!

The final pages to implement were the case studies, including this one. Writing is another creative challenge. While far from being a skilled writer, I did my best and, most importantly, had fun doing it! It is yet another skill that will improve with time and diligent practice!

As I finish this write-up, this project is nearing completion (for now...). There's just a bit of polishing, testing, and refactoring to do and I'm so excited to show it to everyone I know! Overall, it has been a blast to create, from start to finish.

max looking handsome for the camera
max laying on the floor in a funny position, head turned towards the camera

outcome

I'll let you be the judge—my opinion may be a bit biased, haha. This portfolio serves as a playground for me to test and explore new ideas that come to mind. I'm sure that, in a year or two, it will be very different from what it is now. If there's one thing I hope anyone takes away from this portfolio, it is sharing the joy I get from seeing the pictures of my favorite animal! He was the best and his name is Max. :)

struggles, insights, and more

For me, building is definitely the best way to learn! Throughout this journey, I learned a ton about a variety of areas. From how to use Inkscape to create custom SVGs, like the row of lightbulbs seen on the Home page, to exploring how the browser rendering pipeline works and what forced synchronous layout is, and how to dive into the performance tab to detect and fix said forced synchronous layouts.

The biggest technological goal of this journey was to learn how both Next.js and TypeScript operate. While a portfolio doesn't truly tap into Next.js's full-stack potential (at least mine doesn't), I learned a ton about the newer App Router and its conventions, as well as the benefits and drawbacks of server-side rendering a React application. Initially, I found both to be quite overwhelming, but after a few days, I could already feel my comfort growing with these new technologies. As I near the end of this project, the difference between where I started and where I am now is night and day.

In building this portfolio I diagnosed such a variety of unique and intriguing problems that I may as well have gained the qualifications to become a doctor in the process! Jokes aside, I was met with a truly diverse set of issues. Some notable examples are...

• The troubles of implementing theming in a primarily server-side rendered application and, in general, learning about the implications of server-side rendering a React application.

• How transform origins differ between SVG and regular HTML elements.

• Troubleshooting obscure errors that appeared when trying to run a headed WebKit instance. After hours of scouring the internet and scratching my head (it was getting quite bloody at this point!), I figured out that outdated graphics drivers were the cause of all of those low-level d-bus, graphics process, and permissions errors I encountered! (Phew! I could finally perform manual testing in WebKit again!)

• The complexities of forced synchronous layout which can manifest in so many different ways—some intuitive, others... debatable. It may appear when you least expect it. However, for my fellow devs, it can often be avoided by following the general guideline of performing style reads before your writes!

With the help of the mighty StackOverflow and Google gods, I ended up being able to navigate this seemingly endless sea of troubles. Every new challenge comes with its own lessons, and every new project comes with its own set of challenges. I would say one of the most challenging and enjoyable aspects of this project was creating the polyrhythmic visualizer.

In many of my previous creative coding projects, I relied on p5.js—a popular creative coding library inspired by Processing—however, for the polyrhythmic visualizer, I wanted to work with and learn the Canvas API and all of its primitives.

The biggest inspirations for this visualizer will be linked below, and I want to personally thank Hyperplexed for being so motivating in all of his videos. The way he breaks his thought process down makes me feel like that, with a little bit of research and trust in the process, I can accomplish anything.

I want to highlight two experiences during this wonderfully fun dive into the Canvas API, but to start I would like to give a brief overview of how the Polyrhythmic Visualizer works.

The main idea is that there are arcs with a single point that travels along its arc's circumference and anytime a point impacts with the center line (the faded and greyed-out line in the center of the canvas), its associated sound will be played. Each point starts on the left half of it's arc at the vertical center of the canvas. The points then rotate based on a base rotation speed scaled according to their arc's size. This led to the points of the smaller arcs (the ones in the center) completing their full rotations much faster than the larger arcs.

The beauty behind this is that as the points desynchronize from their starting points, they will start to create beautiful patterns, both visually and audibly, which I find just entirely mesmerizing. The real magic happens when they eventually all resynchronize at their initial starting points, resulting in a glorious, simultaneous harmony of sounds. I absolutely love it. I've been eager to build something like this ever since I first saw the first video linked in the inspirations section below!

Now this may get a bit technical, but the first experience I want to detail is the troubles I went through to detect collisions with the center line. After an hour or two of exploring deeply into the MDN documentation surrounding the Canvas API, I finally found something that looked promising! The "isPointInPath" method of the canvas 2DContext object! I had to do a bit more research into the 2DPath object then implemented it and it seemed to work perfectly! Except! There was one major flaw. The method completely failed me when it came to Safari and iOS Safari.

Determined to squash this dastardly bug, I experimented a bit and came up with a pseudo-isPointInPath method that detected whether or not the point was sufficiently close enough to the center of the line that it could be considered impacting.

The second experience I want to share came after the Polyrhythmic Visualizer was fully implemented and working (on my machine...)! The issue was that, upon testing on iOS Safari, I found that the canvas animation on its own was completely fine; however, once an impact happened and a sound was played, it became completely unusable.

After some research, though it was more of a history lesson on the HTMLAudioElement, I found that this older Audio API is just not a robust way to play sounds in the browser, especially when working with a bunch of sounds that may be played simultaneously. This was quite depressing, as I wanted anyone to be able to experience this neat audiovisual canvas element, regardless of the device they were using! I decided to set it aside for now to allow myself to focus on other parts of my portfolio.

Two weeks later, this issue was still in the back of my mind, haunting me. It was time to deal with this once and for all! I scoured the web once again and found the Web Audio API. The API was pretty daunting at first glance. It seemed quite complex, as there were so many different parts of the Web Audio API to learn about, such as all of the different types of AudioNodes, AudioContext, and AudioBuffers. In the end, it wasn't all too bad.

I learned exactly what I needed, implemented it, and refactored my existing code to work with the new implementation. Finally, it was time for the iOS test. It felt as if time slowed as I watched the first point get closer and closer to hitting the impact line, but then I was met with the biggest relief as all of the points impacted and played their beautiful rhythms. It worked!!!! It was a wondrous moment. I was so happy to see my research pay off.

This challenge ended up being a blessing in disguise. It pushed me to learn the powerful Web Audio API. A new tool in my ever-growing belt that will serve me well for future projects dealing with audio manipulation on the web!

This write-up is truly just a glimpse of it all, and I hope it effectively captures some of the highs and lows I experienced during the process.

future plans

Being v1.0.0 of my portfolio, it is very much subject to change—much like a mutable object, it may end up looking completely different in a year or two! In the future, I plan to create a dedicated page for showcasing all of my creative coding projects. For now, though, I'm really happy with how it turned out. If you have read this far into the ramblings of a stranger on the internet, I want to say that you're awesome and that I owe you a big thank you!

Inspirations

Prev
Next