Built for

Hello there 👋

I am Cairin, a design engineer living in Cape Town, South Africa.

I currently work at a company I co-founded, Fynbos. While I am not currently looking for new work, the opportunity to work with you is so great that I'd be willing to leave my post. Tailwind is only one of two companies I'd drop everything at the opportunity to work with.

My highlights reel

I have always been curious about how the world works. As a child, I often tinkered with family members' electronic devices to learn how they worked. Later, this turned into fiddling with my Grandfather's AutoCAD drawings, where I learned how to use the different tools, even though I needed to be older to understand the drawings' contents. I took a technical drawing class in high school and placed fourth in the country for my final exam.

At university (studying electronic and computer engineering), I designed and built a data logging and release system for a CubeSat re-entry capsule. I remember being drawn to this project specifically because it required the most diverse skill set to complete, many of which were new to me. I used CAD software for 3D printing, played around with some cool Raspberry Pi gear, and spent an unreasonable amount of time testing my system in my digs freezer - to ensure everything would operate when strapped to a weather balloon.

Right out of varsity, I joined a home automation startup. I built many things there, from web apps (Vue with Cordova) to PCB schematics. This work led me to discover my enthusiasm for crafting interfaces.

Enter Tailwind, stage left!

My next stop was a much larger startup based in San Fran. Being a larger team, the company was more structured, which meant I worked with people focused on engineering or design. I quickly realized that communication was the bottleneck for successfully implementing features and products. To fill this void, I spent much time learning about design systems. I read books such as Laying the Foundations and Refactoring UI (You might have heard about this one?) and even joined the Interaction Design Foundation for a while.

As part of a remote team in Cape Town, I embraced the design engineer role and implemented component systems to unify the company's product design language. Our team was working on a new product that eventually got shelved. We took our experience building the product and founded Fynbos to try to realize what we had been building.

When we started Fynbos, I designed our branding. Since then, I have built almost everything user-facing. Including crafting a set of accessible, semantic HTML components and developing and implementing animations in Framer motion or using the Headless UI Transition.

Mobile header

I also built tooling to enhance our developer experience. I optimized our error handling, making handling errors from our backend much easier. Our backend (written in Golang) communicates with our front end using GRPC. The error framework I built made handling validation errors trivial (by allowing the backend to be the single source of truth) and automatically ensured errors were easy to handle on the client. Using generics in the error framework also made typings simple to handle, allowing us to move the complexity away from the call site of the function.

/**
 * action is a typical Remix action function.
 * It will be triggered on form submission.
 */
export async function action({ request }: ActionFunctionArgs) {
  const form = await request.formData()
  const name = form.get('name') as string

  /**
   * This is a nice helper function,
   * which ensures all our server actions are csrf protected.
   * It will throw an error in the form of a http response
   * if invalid.
   * This is necessary because Remix doesn't have middleware yet.
   */
  await validateCSRFToken(request, form)

  /**
   * We standardize the shape of potential errors returned to the client.
   * This ensures the types can be inferred by the useActionData hook.
   */
  const errors = {
    form: '',
    name: ''
  }

  /**
   * grpc.setUserName is a generated function based on the proto
   * definitions.
   * The request is passed along for cookie auth.
   * response will be of type:
   *   SetUserNameResponse | ConnectError
   */
  const response = await grpc.setUserName(request, {
    name
  })

  if (isConnectError(response)) {
    /**
     * This is where the magic happens ✨
     * 1. We know response is type ConnectError because of the typeguard
     *   above.
     * 2. response.error will generate an http error response, mapping
     *   the grpc error code appropriately.
     * 3. If there are validation or precondition failures, they will be
     *   appended to the http response body.
     * 4. response.error allows passing params to show a snackbar
     *   on certain error codes. This is useful for places like
     *   /login where we can't tell the user if their username or
     *   password is incorrect.
     */
    return response.error({ errors })
  }

  /**
   * At this point we know the request was a success.
   * response is now of type SetUserNameResponse only.
   * We can now return some data required by the client,
   * or redirect elsewhere.
   */
}

Other contributions I've made

I am proud of most of my work. If I'm not proud of something I've done, I haven't finished working on it.

Her perspective was the first (non-trivial) site I built entirely on my own, and I had tons of fun doing it! The design had some general constraints, but I had creative freedom for the most part regarding layout and styling of components. A headless CMS drives its content. I even designed a logo proposal for them.

What I'm most excited about

I'm excited for my work to have an impact. The last couple of projects I have worked on (for various reasons) have been seen and used by very few people. I'm very excited to interact with people using the software I design and to find out why they do/don't love it so I can improve.

I'm also very excited to learn from and work in a team that sees the value in combining design and engineering. I have long been a fan of Tailwind, and I'm not just referring to the technology. I've always tried to instill ideas I've heard about from Tailwind in the companies I've worked at. Seeing many of those practices in action would be amazing, straight from the source.

You have built a phenomenal team; joining would be a great privilege.

That aside, there isn't anything on your list of upcoming projects that doesn't sound enthralling. Here's my top 5, with why I find each thing exciting:

  • Create a tool for designing color palettes - I have used many tools to create color palettes, but I have never built one myself and I know how tricky building color palettes can be. I would have great fun building the tool.
  • Design and build a command palette component for Catalyst - I have built multiple command palettes before, but never had the chance to really focus on polishing them. This could be a culmination of my previous efforts.
  • Design and build an interactive microsite for the Tailwind CSS v4.0 release - In the past I have always been excited to read your release notes. I love the way you tell a story with your releases. This is definitely a skill I’m excited to hone.
  • Prototype APIs for scroll-driven animations in Tailwind CSS - Sounds like there are many interesting nuances to explore here.
  • Explore new color palettes with automatic dark mode support - I’ve been a fan of this idea ever since I first found the Radix Colors. I have implemented something similar to this before, and think it would definitely be a great addition to the Tailwind palette.

Outside of work

In my free time, I enjoy brewing coffee and crafting cocktails.

I have two very fluffy Siberian cats! Feela and Mercury.

Cape Town is GMT+2, which falls slightly outside the allocated time zone. However, I'm happy to adjust my schedule for this opportunity and will move to the correct time zone if the extra hour doesn't work!

I look forward to hearing from you.