Butterfly Distance

Introduction

Introducing Butterfly: the one stop shop for keeping up with your long distance partner!

I’ve been in a long distance relationship for a few years now. A few months ago, my girlfriend and I looked into using an app to help us feel closer to each other. The main feature we were looking for then was a countdown timer. The app we found, though, did not have a good UI and had many ads –yuck.

So, I decided to build my own version of this application, along with some more features. The core functionalities of my web app –called Butterfly– are as follows:

Homepage

The homepage has three features. First, it has a daily love quote. Second, it displays the soonest countdown timer, so partners can know when they will see each other next. Lastly, it picks a few random photos from the photo album and shows them in a masonry layout (photos omitted for privacy).

Timers

The Timers page allows for either partner to see and delete their current timers alongside create new countdown timers. Each timer has an icon, which is an emoji that can be picked from the custom dropdown I made (with inspiration from this), a name and a date sometime in the future.

Photos

Lastly, the photo album is a paginated grid of all photos uploaded by either partner. When a user hovers over a photo, they have the option to delete that photo. Also, at the foot of the page, there is a drag and drop place to upload new photos.

Technical Overview

I recently read a blog post by Josh Collinsworth outlining the limitations of React. This post inspired me to consider alternatives for my application. I eventually landed on SvelteKit, a framework that uses Svelte.

Svelte’s main value proposition over React, in my opinion, is the simplicity. The key insight behind Svelte is that Web Development is essentially just three things, JavaScript (or TypeScript if you come from a background of strictly typed languages like me), HTML and CSS. Further, these elements do not need to be generated by the browser in real time. Instead, these elements can be woven together at compile time.

The realization of this insight leads to being able to develop more simple and elegant applications faster.

SvelteKit offers a few more convenient features on top of Svelte such as Routing and Server Side Rendering (SSR).

As for hosting and backend services, I used Cloudflare Pages and Workers upon recommendation by Luke Mann. For data storage, I used Cloudflare R2 blob storage. Because my application is not very big, these services are all free!

For authentication, I used Google Auth, which was actually a little more sitcky to set up than I was expecting. This blog post came to the rescue.

For frontend tooling, I used an Open Source toolkit called Skeleton, alongside Tailwind. The skeleton components look good and were really easy to set up. Tailwind came in clutch for a few niche cases including the masonry layout for the photos.

Lessons Learned

Here are some lessons I learned:

Rendering large images in webpages takes a long time.

In hindsight, this seems pretty obvious, but in the moment it was relatively frustrating. I kept having really long load times and occasional internal errors being thrown from my Cloudflare worker. At first, I thought that if I made concurrent requests to the worker, this might speed things up. So I implemented six concurrent requests to the bucket at a time (the max based on the spec), but this did little to solve the problem. I then realized that really the problem was that my images were too large. Luckily, this browser image compressing module came to the rescue. After some brief experimentation, I figured out that I could compress the photos from 1-3MB all the way down to a ~50KB with relatively little loss in quality. Problem solved.

API Design Is Crucial

I dedicated a significant portion of this project to API design and implementation. Upon reflection, I realized that my code became somewhat more complex than necessary. This complexity arose from the initial oversight of not investing sufficient time in defining the structure of my APIs. As previously mentioned, a critical concern was efficiently delivering photos to the browser. I frequently encountered the challenge of finding the right balance between providing enough photos to make the application engaging and preventing excessive demands that could overwhelm the server or result in performance issues. To address this, I incorporated data pagination as a crucial component of my API design, allowing me to strike that balance effectively.

Further Development

I am very happy with how this website came out. Overall DX including deployment and observability were made super easy (and free!) with Cloudflare. SvelteKit was for the most part a breeze to work with.

For further features, I am considering using my Cloudflare worker to email notifications when countdown timers reach certain times. And, if I have more time, maybe implementing a fun “letter-sending” chat feature.

Thanks for reading. If you have any questions about this project, feel free to reach out!

Ari

Updated: