Theo's Blog

Quitting Your Dream Job (Twice)

Sometimes it's important to do the thing that feels a little stupid.

I'm starting a company.

How did I get here? I'm just a music-loving skate nerd from a small farm town. My first "real job," a contract dev role, was more a generous gift than an earned position. If the hiring manager didn't happen to have the same taste in music, I probably wouldn't have gotten the role.

Oh also — worth mentioning that the role was on the Creative Team at Twitch. Fresh out of university, with no experience at all, I got to write the code that ran Twitch's marathon, including Power Rangers, YuGiOh, and the viral Bob Ross, which still runs today.

I stayed at Twitch for four years, hopping from team to team, building dozens of projects I'm proud of to this day. It's hard to put into words how much I was able to learn here. One lesson stuck out — I learned I could build some pretty damn good stuff.

The First Resignation

Realizing that I had outgrown my role was a long, painful process. My last year was particularly rough. I saw so many points that hurt both creators and users. I wanted to destroy, rebuild, and improve everywhere I could. My ambitions helped me get some pretty cool stuff out, but I was getting tired. My work was no longer fulfilling. My time wasn't spent building; it was spent convincing people that we needed to build and ship the right things.

My desire to build overpowered the comfort I got from my role at Twitch. One of my favorite sites from my childhood, Turntable, announced they were coming back and had begun hiring. The opportunity to build was being dangled in front of me, and I had to bite. I left Twitch on the last Friday in January 2021 and started at TTFM Labs the following Monday.

Startup Life

Going from a 2,000-person company to a two-person company is, uh, quite an adjustment.

My initial role was to build, of all things, the Android app. We had a working prototype within a week. Three days later, we had ported to iOS successfully. The web app (written by contractors at the time) was the next target. One month in, I'd managed to create the TTFM client on all platforms.

I was building again. Faster than ever. I was hooked.

We started hiring. I helped make a great team. We were shipping at an alarming rate, recreating the music sharing experience I missed from my high school days.

The feeling of "solving problems from scratch" motivated me to build like I had never built before. I wish I could say this continued past the first two months.

Losing Focus

It didn't take long to run into some familiar red tape. Our backend was labeled by leadership as "do not touch." All of the outages, bugs, and other weird behaviors became client-side problems we had to solve in increasingly obtuse ways.

In a short time, my role transitioned away from "solving technical problems while improving the product." I was back in the bureaucracy. The foundation we were building on was weak, and we were being asked to build higher. I pushed for us to refocus and reinforce what we had before our tech collapsed under the weight.

It took a while, but they listened. We replaced our monstrous 7,000 LOC socket server with a minimal, maintainable implementation under 350 LOC. This was a huge win, but I had become disillusioned by the process.

I had spent almost half a year justifying code that took under 10 hours to write.

Finding My Drive Again

My work was no longer providing the fulfillment I had quit Twitch to pursue. I needed to build.

I spent a week putting too much time into a web game about Dogecoin. It was the most fulfillment I had felt in months. It also reinforced the big lesson from Twitch: I can go from concept to product pretty damn quick.

Speaking of Twitch, I was still a regular user. The problems I wanted to solve hadn't gone anywhere. From the inside, creator pain points were rarely considered beyond dinner discussions. From the outside, those same problems stuck out like weeds, begging to be cut.

Multi-person content seemed particularly hard to create, so I started a new project — Round. In a few days, I had something usable. A week later, it was borderline useful. My energy was back.

Electrified as ever, I started showing some friends. Unlike previous endeavors, my excitement was reflected. They all wanted to use it as soon as possible.

The Second Resignation

When I moved from Twitch to TTFM, I took a third of my previous compensation in hopes of finding fulfillment in my work. To put it bluntly, Round is the most fulfilling work I've done in a while. I want to ride this wave.

I'm leaving TTFM Labs to start my own company.

Which is incredibly dumb.

But I can't imagine doing anything else.

Quitting your job to start a streaming company is dumb. Missing this opportunity feels way dumber.

T3 Tools

I want to make tools that inspire a sense of craftsmanship. I am starting T3 Tools to do just that.

We have a lot to build. Round is just the start. If all goes well, we'll be able to build the toolbox that powers the future of live content creation.

I'm so hyped. I can't wait to share more about T3 soon.

If you're also excited about live creator tools, modern dev practices and patterns, or building in general - hit me up. We'll be hiring soon :)

Using Vite On Vercel

I like fast, simple dev environments. Vite has quickly become my go-to build tool for any new single page app project. Vercel is my host of choice, greatly simplifying the deployment experience for both static web apps and associated APIs.

I've been loving Vercel's serverless function implementation, which enables quick deploys of lambdas by adding JS (or TS) files to the /api directory in your repo. You can even run these locally with the Vercel CLI.

Sadly, Vite is not quite as drop-in a solution on Vercel as other build tools (Next.js, Gatsby, Nuxt, etc). After a good bit of hacking, I have managed to get everything working consistently enough that I felt obligated to share. Here's a rough how-to on the steps to get a fresh Vite project running smoothly with Vercel's builds, deploys, and CLI.

Step One: Init and push

Start a fresh vite project with npm init @vitejs/app. If you prefer Yarn, follow along here.

I'll be initializing a fresh React and Typescript project, but these instructions should work regardless of your framework or choice between JS and TS.

Once you've initialized the project, make a fresh Github repo, cd into the dir, npm install, and push it up.

Rough bash:

cd !! YOUR PROJECT DIR !!
npm install
git init
git add -A
git commit -m "init"
git branch -M main
git remote add origin !! YOUR REPO URL HERE !!
git push -u origin main

Step 2: Deploy to Vercel

If you are making a single page app (you likely are if using React or Vue), you will need to do a little more config.

By default, Vercel tries to resolve all requests to a file at the path. Works great in Next. Not great for SPAs. To enable non-root routes, you will have to make a vercel.json config file that redirects to the root index.html.

vercel.json

{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}

Once this is added, you can go to Vercel.com and create a new project. For framework, select "other". For "Output directory", override the default with dist

Vercel config

Click "deploy" and you should be live in no time!

If you do not plan on using Vercel's serverless functions or CLI, you can stop here

Vite's built output is a simple static webapp, which vercel is more than equipped to handle. The vite dev server has a few more weird quirks that you will have to resolve before it will play nice with Vercel's CLI.

Step 3: Wrangling the CLIs

Vercel's CLI can be installed with a quick npm i -g vercel (more info here).

To assure our changes work, I will also be creating a simple /api/hello-world endpoint to confirm the local dev environment is working.

I feel obligated to inform you that HERE BE DRAGONS. There's some really weird behaviors in how the Vercel CLI interacts with the vite dev server. I've managed to work around most of these issues as long as this pr gets merged.

First, we have to modify our Vercel project settings once more to point it at a "safer dev command". If you're thinking of modifying the "dev": "vite" key in your package.json, do not do this. It will break. I have no idea why.

Toggle "override" for "DEVELOPMENT COMMAND" and set it to npm run {vercel-special-command-name}.

Vercel dev special config

The following is weird enough that I stubbed out a commit with all the related changes to make it easier to apply to your project

Once we have told vercel about this special command, we have to create it. Vercel CLI uses the --port argument for...something. 🤷‍♂️

Add the following scripts in package.json

"vercel-dev-helper": "vite --port $PORT",
"vdev": "vercel dev --local-config ./vercel-dev.json"

You may have noticed that the vercel dev command is pointing to a unique local config. This is because the SPA rewrite in our vercel.json does not work with vite's dev server.

Easiest fix is to create a vercel-dev.json with a single {} insite to undo that config :).

Now npm run vdev and you should be good to go!

Wrap up

Assuming my fix for import pathing gets merged, you should now be good to go! As annoying as this is to config compared to Create React App, Next, and other build tools, it may not seem worthwhile. But man, Vite is fast and simple as heck and I'll be damned if I have to give it up for a few CLI incompatibilities.

In the future, I'd hope these changes are integrated into Vercel's tools, and that we'll see a Vite option in the "frameworks" dropdown :)

Thank you for reading! Github Repo here for those interested in the full source

AirPods Max Review

No Magic Here

I'll admit that I went in hopeful. The AirPods Pro more than impressed me. They're my "every day headphone", which hurts to say as an audiophile, but also speaks to their quality.

These things, however. These are getting returned.

That's not to say they're all bad or anything. I can see a really good Version Two in the future. But I did not purchase a Version Two. Sadly, what we have right now in the AirPods Max is a disappointment, and I cannot recommend them.

Build

Some parts of the AirPods Max are best in class. The pad material is fantastic. The all-metal framing and body makes my HD800's feel cheap.

I think the top band is really nice. Apparently that's controversial? idk. I like the mesh a lot. I'm concerned it is not replaceable, which is scary at this price, but it is showing no wear and should last.

The cups pivot "out", preventing them from sitting around your neck while flat. These are meant to be on or on a table, not "around".

Volume knob is fine. Surprised the copy-paste from the Watch went so well (seriously these wheels feel identical). Not much to note here.

The "cable" port (lightning, for charge + audio passthrough) is on the right. Let me emphasize this. THE RIGHT SIDE. The ENTIRE AUDIO INDUSTRY has standardized putting ports on the left for DECADES. I'm more pissed about this than the headphone jack removal tbh.

I only have two gripes with the build of the headphones themselves, both small. The cups touch when the headphone is sitting "flat", which is scary metal-on-metal contact. No scratches thusfar 🤞

The other issue is the button on the top right (noise cancellation toggle). It's placed exactly where I touch to adjust their position on my head, causing a lot of accidental presses. Easy enough to fix, but I've only managed to trigger it accidentally.

Fit

I did not expect something this heavy to feel so good on my head. These are very wearable. I tend to complain a lot about headphone wearability, so I'm surprised that I had no issues wearing these for 4+ hours at a time.

Case

This deserves it's own section. I am truly floored at how awful this thing is.

Firstly is how it looks. The thing is a crap magnet. It hasn't left my desk and it's still managed to pick up a ton of cat hair, fingerprints, and various gunk. Even when clean, it looks awful.

Using the case is, at best, unpleasant and inconvenient. At worst it's truly aggravating. I've yet to find a motion to elegantly remove the Max from the case without both cups violently slamming each other. The top magnet flap thing is hilariously flimsy.

The charge port cut-out is so bad it's memeworthy. The alignment shifts based on band size. I honestly don't know how this passed Apple QA.

Seriously, this case is a joke, and Apple should apologize and ship all early adopters a better case. If these headphones were good, I would struggle to notice because of how much this awful case colored my impressions. Do better, Apple.

Sound

Okay, time for the important part.

Due to...surprising changes in sound characteristics when switching between modes (noise cancellation on/off, transparency mode, and wired vs wireless), I chose to review the sound exclusively in the "default" mode (noise cancelling on, wireless). As this is their intended use case, I think it is a fair representation of what they have to offer. If you intend to regularly use transparency mode or wired connectivity, I, uh....wish you luck with that.

All testing was done using Tidal, master quality where available. I used a lot of different headphones as "reference", but relied most on my AirPods Pro, modded HD800's, Ether C, and SHP9500.

Anyways.

Bass

Clear, surprisingly deep, quick, bloated in sub range. Apple pulled a lot of sub bass out of these. Impressive in some songs, unintentionally overpowering in others.

The flaws in the bass aren't as simple as the Sony XM1000's EQ nightmare. There's something deeper in here, pulling really low bass into an audible range it shouldn't be part of. I noted In Degrees by Foals and Good News by Mac Miller as examples of songs where the sub takes way more space than it should

I don't want to be all negative. The sub bass presence is fantastic on a lot of stuff, such as bass-y electronic music (Feelin by DJ Rashad stood out to me.)

My frustration with the bass is in how much it hurts the versatility of the headphones. It can come out of seemingly nowhere and take up way too much "space". Thankfully, as we will get into next, it doesn't seem to interfere with vocal or treble much

Vocals

Vocals are, imo, the shining point of these headphones. I struggled to find tracks that covered the vocals whatsoever. Regardless of "how much sound" was going on, these always managed to maintain a clear, centered vocal image.

The only catch is a quirk in the treble, which I will get into next

Treble

Treble detail is impressive, but at the cost of sharpness. There's a wide range in the treble that's way, way too sharp for a pleasant experience. They remind me of my HD800's before I modded them, but even sharper at times.

There are a number of tracks that hit this sharp range. Corn Maze by Aesop Rock & Tobacco was genuinely unpleasant to listen to for this reason. Peach, Plum, Pear by Joanna Newsom sounds great until the "chorus" at 1:38, where a bit of static on the recording hits like a dagger.

I want to emphasize that this is a thing you're gonna have to deal with. There's no genre or style of music that avoids this sharp range entirely. Thankfully, of all the flaws in the headphones, this feels the most like a "bug", and I think it can be addressed with software.

Imaging and Sound Stage

The imaging of these things is so, so, so strange. On tracks meant to be wide, it's shockingly immersive. I did not try any of the "spatial audio" stuff, but I'm sure this works great for that.

That said, these are closed back headphones. Narrow ones at that. There's only so much that can be done to make a "wide" sound, and these pull out all the tricks. Hard stereo cut. Boosted sub bass. Some weird dynamic range and stereo "compression" that's hard to put into words.

These achieve a wide space, and they don't lose vocals in the process, but man, they do some weird shit to achieve it.

The quirks this causes are painful on some tracks, such as Love Letters by Metronomy. The intro is a chill piano + horns ballad, which transitions into a louder, more dynamic, wider "full band" around a minute in. No headphone in my collection handles this transition worse. The effect of the band coming in is lost entirely, the "space" feels no more full. This isn't because the band doesn't sound overwhelmingly large - I promise it still does - more that the quieter intro was WAY TOO DAMN WIDE.

Sorry, I'm a little salty these headphones made even Metronomy sound bad.

Final thoughts

There are good things here. There are good sounds here. There's too many overwhelming flaws for a headphone in this price range.

I'm of the belief that something in this price point has to justify the cost with versatility or unique ability, and the AirPods Max offer neither. There are songs with impressive range, quality bass, and well tuned vocals. There are just as many songs that have their "space" destroyed, that live in the sharp treble range, or get blown out by the over-present sub bass.

Unless you exclusively listen to EDM with trimmed up highs, these are not versatile enough to be your primary headphone. At $550, the lack of flexibility is insulting, especially when compared to a headphone as forgiving as the AirPods Pro.

The only "party trick" these have that my other headphones don't is a bit more width (for a closed back) and a lot more sub bass. Although cool at times, neither of these qualities come close to justifying the cost, much less a spot in my collection.

So...yeah. Don't bother with the AirPods Max. Next revision has a lot of potential.

Alternatives

If you want a good portable bluetooth headphone, AirPods Pro are still the best on the market.

If you really want wireless over ears, grab some refurbished Sony XM1000's for under $200. These have qualities I vastly prefer to the Sony's, but not for a $350 price increase.

If you just want some good over ear headphones for your desk and don't mind a cable, the Phillips SHP9500 is still my favorite headphone. Surprisingly neutral, incredibly comfy, easy recommendation.

Hello World

This is long, long overdue.

I'm Theo. I am nerdy about a lot of stuff. I want to start writing more about the things I'm nerdy about. I made this blog to host the things I write.

This blog is also built on things I'm nerdy about. My personal site was previously a trim Gatsby app, shipping ~200kb down the pipe. I'm way too proud that this site, blog and all, is under 100kb.

tl;dr on the tech - Next.js rewrite deployed on Netlify

It's nothing too fancy. Still pumped about the lighthouse score tho

I'll likely write more on the tech itself in the future - but for now, know I'm loving this stack and highly recommend it.

Next post will be the AirPods Max review, follow me on Twitter to see when that's out

Thanks for stopping by 🙂

-Theo