Skip to main content

See A Satellite Tonight is my most successful side project so far, with 5 million users since launch in 2019. It's been entirely a solo project, and I've used it as a proving ground for a bunch of tech that I wanted to learn. It took dozens of APIs and services to put together the experience I wanted: The front page of See A Satellite Tonight

In this post I'll describe how it all works. Frontend tech, satellite-related calculations, backend tech, plus a little about my motivations for building the site.

You may know that all numbers in JavaScript are 64 bit double-precision floating point values. This is sometimes convenient and it works pretty well as a default for novice programmers, who are often confused by integer math, and rightfully so when 1 / 2 = 0. Unfortunately, it makes things slow. Doubles take a lot of memory and floating point math is slower than integer math on CPUs. It's also inconvenient if you want to port existing code to JavaScript, because existing code usually expects to use integer math.

Fortunately, there is a way to make JavaScript do integer math, and it works remarkably well!

Shower curtain tension rods are way better than tripods. They are cheap, strong, available everywhere, and designed to look nice permanently installed in a home. They work perfectly installed vertically floor-to-ceiling and take up only one square inch of floor space. Get a cheap camera mount and you're good to go. They also work for non-permanent installation of other small items like baby monitors or security cameras.

I've left a lot of comments on Hacker News since 2009, when I moved over from Slashdot. HN Search is great for finding old comments, but it can't see comment scores, which are private to the author of the comment. I thought it would be interesting to find my highest-voted comments, so I had to scrape my comments from HN myself. Here's how I did it:

I just moved some posts here from an old Blogger blog that I made many years ago. Now that all my posts are here I wanted to redirect the whole old blog to this new one. Blogger doesn't have a built-in way to do it, but it can be done! Here's how:

"Safari on Windows?", you say. "That's impossible! Safari doesn't run on Windows." And you're right! I mean it used to, but Apple stopped supporting Windows way back in 2012. Which is a bummer for web developers who want to test Safari compatibility.

But...

You may have noticed that when you drag something on your screen, it will often lag behind your mouse or finger, as if attached by a rubber band. This is input latency: a delay in the computer's response to your actions.

This is part 2 of a series on input latency. Check the first post for background information about input latency.

This post contains techniques you can use as a developer to reduce input latency in your applications. But first, a discussion of something that you shouldn't do:

tl;dr replace t.name with t.op.name to get rid of the :0

When getting the names of things in Tensorflow I've sometimes been confused by the difference between x and x:0. It turns out that x:0 is the name of a Tensor object, while x is the name of the op that generates it (such as Add or MatMul).

If you have a Tensor object t and you say t.name, you will get a name with :0 at the end. If you want the name without :0, don't just try to use string processing to remove the :0! Instead, you can access the op related to the Tensor with the op member variable, so you can get the name you want with t.op.name.

If instead you have an operation my_op and you want the name of its output tensor, you can say my_op.outputs[0].name.