web animation
April 17, 2023

How I made a more human-like animation 

After a couple of years of having “Hello, world!” written on my web page, I have finally decided to take it to the next level and create an animation that would type those same words. I started looking for a similar animation on the Internet since I did not want to waste time reinventing the wheel.

The first example I came across was the one on this page. This is how it looks after adjusting the background and font color:

You might be wondering: What’s wrong with this animation?

In my opinion, the animation is too perfect. The reason I say this is not to be overly dramatic. It is because I need an animation that would look more like human typing.

But, what is the difference? — is another question you might be asking. Fair enough, let me explain.

People don’t have perfect timing between key presses

The first thing I noticed when I saw the animation in the example above is the timing. People usually don’t have an ideal timing between key presses — the keys are at different distances and they have different finger mechanics or even different strategies of typing (my dad still types with two fingers).

People make mistakes

It’s hard to imagine that a human would press the right key 100% of the time. Sometimes we make mistakes.


Based on those two requirements, I decided to make my typewriter animation that would have more random timings between key presses and would sometimes make mistakes (ended up sort of reinventing the wheel).

Step 1 — Character emitter

The best way to implement a typewriter animation, I imagined, is to have an algorithm typing characters. This is what I came up with:

Inside an interval, I simply concatenate the current value with the next character from the original value. I enabled subscribing-unsubscribing mechanisms, similar to RxJS in case I would need to stop the animation (If the page is changed, for example).

Note: You can implement similar behavior using RxJS with about three lines of code, so consider doing that if you already have it in your project.

At this point, I got to have the result I'd started with.

Step 2 — Making mistakes

Let’s first think about how to represent a mistake inside the text. I asked myself —What does it mean to make mistakes? And the answer is — I try typing Hello, world!, but instead, I type Hello, wprld. It might happen that I spot the mistake right away, delete the wrong character, and type the right one.

So a text with a mistake can be represented as follows: Hello, wp{r}orld!

  • p — the character that I got wrong
  • {r} — the string that will mean “delete the last character”

The rest is just correct text.

Here is the live result:

Step 3 — Automate making mistakes

Although we could get away with having multiple versions of our text with different mistakes, it would be more complicated if we were to have multiple texts. So let’s automate the process of making mistakes.

I refactored the code a little and moved the CharacterEmitter class into a separate file.

In short, this is what this code does:

  1. Takes the initial string and iterates through each character
  2. Randomly picks whether the current iteration has a spelling mistake or not
  3. If the iteration is picked, calls the getCloseCharacterfunction to get a character near the current character
  4. Adds the character and the remove-string before the correct character

I made it more random in order to make it different every time — too many mistakes, as well as no mistakes, are less fun. I found experimentally that I am happy with the amount of randomness from the example.

Note: You might have noticed the Random class I imported. It is a basic class that wraps Math.random. You can find its code at the end of the article.

Step 4 (Final step)— Making timings more random

In order to make timings more random, we need to have different delays between key presses.

I created the DelayLimits interface to store the min and max delays. Then I added a timeout, emitting the value after a randomly generated time.

And here it is, my personal take on making this animation. You can find the code of the current project on GitHub.