Feb 26, 2026

A client that wanted an animated typing effect on their website. A word would be typed out. Pause. The word would be deleted (backspace). Iterate an array of options. Claude went with setTimeout(). I prefer requestAnimationFrame() and a state machine. Full code in a Gist.

_step( now ) {
  if( !this._messages.length ) return;

  const word = String( this._messages[this._index] ?? '' );

  switch( this._phase ) {
    case 'TYPING': {
      if( this._character < word.length ) {
        this._character += 1;
        this.$span.textContent = word.slice( 0, this._character );
        this._nextAt = now + this.TYPING_MS;
      } else {
        this._phase = 'PAUSE_FULL';
        this._nextAt = now + this.PAUSE_FULL;
      }
      break;
    }

    case 'PAUSE_FULL': {
      this._phase = 'DELETING';
      this._nextAt = now + this.DELETING_MS;
      break;
    }

    case 'DELETING': {
      if( this._character > 0 ) {
        this._character -= 1;
        this.$span.textContent = word.slice( 0, this._character );
        this._nextAt = now + this.DELETING_MS;
      } else {
        this._phase = 'PAUSE_EMPTY';
        this._nextAt = now + this.PAUSE_EMPTY;
      }
      break;
    }

    case 'PAUSE_EMPTY': {
      this._index = ( this._index + 1 ) % this._messages.length;
      this._phase = 'TYPING';
      this._nextAt = now + this.TYPING_MS;
      break;
    }
  }
}
Back to Notes