Playing with easter eggs: Ideas for making your website more fun
Tags: javascript, whimsical, webdev
Published: 2019-10-16 03:39:48

I recently updated [my personal site](https://rosey.dev) to feature a fun mode, where I tried to add as many easter eggs as I could think of.

I loved my early years making websites: The gaudy colours, using weird CSS properties that were not very user-friendly but tons of fun to mess around with (not gonna lie: I once had a website that set `cursor: none` on link hover, and it was very on-trend), and I wanted to re-create that.

Below I’ve outlined some of the things I added, along with a simple version of the code I wrote (the actual code has a few more bits and pieces) for any JavaScript beginners who may want to try something similar.

### 👆The obvious: Clicking something triggers an easter egg

This one is an easy easter egg to add and usually an easy one to find. I added a click listener on `document.body` that inserted a random emoji on the page whenever you clicked. I also included some seasonal variants (Halloween, Christmas) so that if you visited on special days, the emoji you saw would be suitable for that occasion.

It looks something like this:

```javascript
var today = new Date();
// Regular days just use these emoji
var possibleEmoji = [
      '🐹',
      '🐢',
      '🌼',
      '🍉'
    ];

// Special emoji if close to Halloween
if (today.getMonth() === 9 && [31, 30, 29, 28].indexOf(today.getDate()) !== -1) {
  possibleEmoji = [
    '👻',
    '🎃',
    '🧟‍♀️'
  ];
}

// Special emoji if close to Christmas
if (today.getMonth() === 11 && [21, 22, 23, 24, 25, 26].indexOf(today.getDate()) !== -1) {
  possibleEmoji = [
    '❄️',
    '🎅',
    '🎁'
  ];
}

document.body.addEventListener('click', function (event) {
  /* 
   * generate random number that falls between 0 and the total number 
   * of emoji possibilities
  */
  var randomNumber = Math.round(Math.random() * possibleEmoji.length);
  
  var span = document.createElement('span'); 
  span.textContent = possibleEmoji[randomNumber];
  span.className= 'emoji click-emoji';
  /* 
   * event.clientX is where the mouse was horizontally at the time of 
   * the click. This way we can insert the emoji in the exact location 
   * the user clicked.
  */
  span.style.left = event.clientX + 'px';
  // event.clientY - same idea as clientX, but vertical position.
  span.style.top = event.clientY + 'px'; 
  /* Of course these values are useless if we don’t set the emoji's
   * position to something outside the normal flow of content. */
  span.style.position = 'fixed';
  document.body.appendChild(span);                           
});
```

### ⌨️ Still pretty basic but a bit harder: Keyboard events

I like this one but it has the major drawback of being on desktop browsers only. Still, I added a lot of little keyboard handler easter eggs - I won’t reveal them all in this post (where’s the fun in that?!) - But one is hitting the `c` key (in my mind, short for “clean up”) to make all those emoji that you inserted on the page animate away.

Here’s what it looks like -

```javascript
document.addEventListener('keyup', function (event) {
  if (event.keyCode === 67) { // c
    // Find all emoji elements that we want to sweep away
    var clickEmoji = document.getElementsByClassName('click-emoji');
    var totalEmoji = clickEmoji.length;
 
    /* If you want to support older browsers you may want to 
     * polyfill forEach https://caniuse.com/#search=foreach
    */
    Array.from(clickEmoji).forEach(function (emoji, index) {
      /*
       * Change the animation delay to be random so that they fall off 
       * at different times, not all at once
      */
      var maximumDelay = totalEmoji.length > 10 ? 1000 : 400;
      if (index === 0) {
        emoji.style['animation-delay'] = 0 + 'ms';
      } else {
        emoji.style['animation-delay'] = Math.round(Math.random() * maximumDelay) + 'ms';
      }
       
      /* 
       * Make animation duration random as well for the same reason: 
       * Makes it more interesting if they fall at different speeds
       */
      emoji.style['animation-duration'] = Math.max(Math.round(Math.random() * 700), 100) + 'ms';
      
      // Once the emoji is done falling, we can remove it from the DOM
      emoji.addEventListener('animationend', function () {
        document.body.removeChild(emoji);
      });

      /*
       * The remainder of the animation logic is in CSS, triggered by 
       * the fall-down class
      */
      emoji.classList.add('fall-down');
  });
});
```

-----

Clicks and keyboard events were fun to add but I felt like they were kind of old-hat so I was trying to think of other neat tricks.

### 🖍 Pretty hard-to-find: Selecting certain text on the page

After a bit of thinking I came up with this one, which I thought was pretty unique: An easter egg if you highlight a certain word on the page.

In this case: If you highlight my _name_ on the page, a picture of me will appear.

I accomplished this like so:

```javascript
var profileImage = document.createElement('img');
profileImage.setAttribute('src', './me-1.jpg');
profileImage.classList.add('profile-pic');

document.addEventListener('selectionchange', function() {
  var selection = document.getSelection();
  var selectedText = selection ? selection.toString() : null;
  
  // Warning for old browsers again: May want to polyfill https://caniuse.com/#search=includes
  if (['Rosemarie', 'Rosemarie Robertson', 'Rose'].includes(selectedText)) {
    // Add if you selected my name
    mainIntro.appendChild(profileImage);
  } else if (profileImage.parentNode) {
    // Remove if you de-selected it
    mainIntro.removeChild(profileImage);
  }
});
```

### Any more ideas?

I still want to spend time building out fun things for people to find, so I’d love to hear suggestions! I’m always up for a challenge 😇