Hi 👋, I'm Stafford Rose a Front-end Web Developer

I am passionate about building interactive, responsive, and user-friendly websites. I enjoy developing landing pages, ecommerce storefronts, admin dashboards, and product configurators. In my free time, I enjoy camping, canyoneering, hiking, and cycling.

Technologies I Use

  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • React
  • Next.js
  • Gatsby
  • Redux
  • Zustand
  • Styled Components
  • Emotion
  • Tailwind CSS
  • Framer Motion
  • GSAP
  • Three.js
  • Firebase
  • Supabase
  • Prismic

Recent Projects

Address Book
TypeScript
Zustand
Formik
Supabase

Address Book

Under Development

Address Book is a full-stack application for managing personal and business contacts. I developed it with Next.js in Typescript, and I used Supabase's managed database, authentication, and storage infrastructure for the backend. Address Book supports importing and exporting contacts via the vCard standard and sharing contacts through QR codes. The latest vCard specification (v4.0) was published over 10 years ago and was never fully adopted by major tech corporations, like Apple (v3.0) and Google (v2.1). Despite this fragmentation, I was interested in learning about the benefits and limitations of the only major contact file format I'm aware of. To parse vCards during import, I modified the script of node-vcard. To generate vCards for export, I reverse-engineered my modified version of the node-vcard script. The vCard standard supports multiple contacts in a single VCF file, so I added the ability for users to both import and export multiple contacts at once. A contact manager seemed like a solid use for QR codes, so I used node-qrcode, which is called via a Next.js API route. For now, the application only allows QR code sharing (export), but I plan to add an import method as well. This will require additional validation to ensure the contents of the QR code are, in fact, valid vCard fields. I exclusively used Firebase for the backend of our web applications at my previous work. I learned firsthand about the challenges of using a NoSQL database with an ever-expanding number of collections, relationships, and queries - it was a constant battle to stay under Firestore's 200 composite index limit! For this project, I knew I wanted to dive into SQL. When making the jump from Firebase, Supabase seemed like the no-brainer choice to help me gain experience with PostgreSQL, while not feeling hindered by backend challenges such as authentication and user management.

View Project
NBA Replay
TypeScript
Emotion
Zag
Three.js

NBA Replay

NBA Replay is a play-by-play game recap tool. I wanted to make a project that would allow me to use what I had been learning in Three.js. With the NBA Playoffs happening at the time, I decided to make a 3D court visualization that could be played back at multiple speeds or scrubbed through with a slider. Each game of the 2021-2022 season has a court visualization of made/missed shots along with an ascending list of game actions. The most challenging part of the project was working with the data. The NBA doesn't offer a public API, and the endpoint for the current season's schedule is a JSON file with all 1000+ games. Initially, I attempted to store the 2021 season schedule and play-by-play data in my project's public folder. This didn't work because Vercel has a 50MB compressed file size limit for serverless function invocations (it's an AWS limit). My compressed public folder was a few megabytes over the limit for a single season. The solution was to keep the schedule and basic game data in the public folder, separated into the preseason, weeks of the regular season, and playoff rounds; then, use the unofficial NBA API to get play-by-play data on request. This reduced the public folder size to just a few megabytes, while preventing users from having to download the entire season when they first view the schedule. I couldn't find any low poly count basketball hoop models, so I made my own with Blender. Prior to this project, my only experience with 3D modeling software was making a rudimentary campervan layout in SketchUp about a decade ago. Knowing the model would take up very few pixels on the screen and with the help of a few YouTube tutorials, I was able to model a basic basketball hoop that was only 79KB in size.

View Project
Connect Squares
TypeScript
Next.js
Chakra UI
Framer Motion

Connect Squares

Connect Squares is a clone of an Android game (Connect Me) that I made to expand my understanding of JavaScript and Web APIs. Connect Squares is puzzle game where the player must join the "connectors" on each board piece to matching connectors on other board pieces. There can be no connectors facing an empty square or the edge of the board. To make the game challenging, the color of a board piece determines its behavior: Purple can be moved along x-axis/y-axis and can be rotated, Green can be moved along x-axis/y-axis, Brown can be moved along either x-axis or y-axis and can be rotated, Yellow can be moved along either x-axis or y-axis, Orange can be rotated, and Red cannot be moved or rotated. The game can be played in one of three difficulties: Normal, Hard, and Expert. Normal is played on a 4x4 grid and board pieces are limited to four colors: Purple, Green, Orange, and Red. Hard is played on a 5x5 grid and includes all board piece colors. The probability of a piece being Brown or Yellow is 40% Expert is played on a 6x6 grid and includes all board piece colors. The probability of a piece being Brown or Yellow is 60% I chose to automate the level creation process, so I wouldn't have to manually create 300 unique levels. I wrote a script that: 1. Determines the number of board pieces based on board size and progress, 2. Sets the color of each board piece based on availability and a pre-determined probability distribution, 3. Randomly sets the first board piece, 4. Randomly sets subsequent board pieces based on position of previously placed piece, 5. Verifies that all board pieces are bordering at least one other piece along the X or Y axis, 6. Adds matching connectors at the intersection of all board pieces, 7. Shuffles eligible board pieces, respecting x-axis/y-axis movement behavior, and 8. Rotates eligible board pieces. To make levels more challenging as the player advances, I simply increased the number of board pieces. This means it's very possible (likely even) that some subsequent levels will be easier or significantly harder than the level preceding it. I was fine with this tradeoff, because the game is solely intended for my portfolio.

View Project
Portfolio Site
TypeScript
Twind
Three.js
GSAP

Portfolio Site

I had a few primary objectives when building my porfolio website: 1. Implement dark mode, 2. Respect users motion preferences, and 3. Apply understanding of technologies that I would be learning through building the site. Dark mode was fairly straightforward to implement with Tailwind CSS. I used a package called next-themes that made toggling as simple as possible, while adhering to users prefers-color-scheme preference. The main challenge I'm still facing is the behavior of the mobile wireframe hero animation when toggling between light and dark modes. Currently, the animation must restart when the mode is changed. Each page of this site, but especially the home page, has animations that may be unpleasant for some users. I made it a priority to respect users prefers-reduced-motion preference (if requested). Tailwind CSS has a motion-reduce modifier that covers most use-cases. I used a media query for the Technologies section of the home page, and I added a play/pause button for the mobile wireframe animation when a user has requested minimized motion. After my departure from Leisure Time Inc., I took some time to begin learning technologies that would advance my career and make me a more well-rounded front-end dev. I chose to use my portfolio site to apply the concepts I would be learning, so I built the site in TypeScript, designed it with Tailwind CSS, and developed a hero animation with Three.js and GreenSock. Each project in my portfolio is built with TypeScript, but this site is the first project I started building with TS. While I still have a lot to learn about the language, I enjoy how it has improved my workflow. Refactoring is no longer such a daunting task, I introduce fewer bugs, and I don't feel like declaring types disrupts my flow. I've used CSS-in-JS libraries in practically all my work as a web developer over the last 412 years. Prior to that, I would customize the CSS of various WordPress themes, which was mostly a nightmare. The themes I used from one particular agency had the !important flag scattered throughout the codebase. My limited understanding of the CSS cascade, coupled with poorly designed themes, made CSS frustrating. Learning JavaScript, React and CSS-in-JS removed the most frustrating parts of CSS for me. I find component-based UI architecture to be a far superior method of designing websites. After so much time with libraries like Styled Components, Emotion CSS, and Framer Motion, the developer experience of a utility-first framework like Tailwind CSS was a bit jarring at first. I ended up going with a tailwind-in-js solution to ease the transition. I settled on Twind because I enjoy the API and it seems like a promising project. It hasn't received many updates over the last few months, so I may need to re-evaluate in the future. Three.js and GreenSock (GSAP) have become two of my favorite tools. I used them to create the interactive website wireframe animation at the top of the home page. Desktop users can move the mouse horizontally and mobile users can scroll vertically to reveal/hide the elevation of the wireframe's layers and elements.

View Project

Available for Hire

I'm seeking to join a front-end team where I can make an impact and advance my skills as a developer.

View Resume