DEV Community

Cover image for Implementing a Konami Code Easter Egg in Svelte by Leveraging Svelte Stores
Pierre Bouillon
Pierre Bouillon

Posted on

Implementing a Konami Code Easter Egg in Svelte by Leveraging Svelte Stores

The Konami Code is a originally a cheat code that now belongs to the pop culture.

It's a fairly traditional code that consists of the following key sequence: B A

Initially used in many Konami Games, it then spreads to other video games and even in other software and websites such as in one of the Bank of Canada's website!

Since it has spread so far into the "geek culture", why not incorporating it into your next website?

In today's article, we are going to see how to detect the Konami Code in Svelte by leveraging the concept of stores in order to create a small easter egg 🥚.

Table of Contents


Referencing the Konami Code

The Konami Code will be a sequence of keys that can either be:

  • Arrow Up
  • Arrow Down
  • Arrow Left
  • Arrow Right
  • a in lowercase or uppercase
  • b in lowercase or uppercase

From that point, we can create a custom type to work with:

type KeyCode =
  | 'ArrowUp'
  | 'ArrowDown'
  | 'ArrowLeft'
  | 'ArrowRight'
  | 'KeyB'
  | 'KeyA'
  | undefined;  // 👈 Other keys are to be ignored
Enter fullscreen mode Exit fullscreen mode

We can then represent the Konami Code as a sequence of KeyCodes:

const konamiCode: KeyCode[] = [
  'ArrowUp',
  'ArrowUp',
  'ArrowDown',
  'ArrowDown',
  'ArrowLeft',
  'ArrowRight',
  'ArrowLeft',
  'ArrowRight',
  'KeyB',
  'KeyA',
];
Enter fullscreen mode Exit fullscreen mode

Detecting the Last Pressed Keys

Creating a readable store

The last pressed keys sequence will be store that can only be modified when a key is pressed, not from the outside.

For that, Svelte has the notion of readable store.

In our case, we want the store to listen to any key down event when first subscribed and to remove this listener when unsubscribed:

const lastKeyPressed = readable(
  new Array<KeyCode>(),
  () => {
    const handleKeyDown = (event: KeyboardEvent): void => { };

    window.addEventListener('keydown', handleKeyDown);

    return () => window.removeEventListener('keydown', handleKeyDown);
  }
);
Enter fullscreen mode Exit fullscreen mode

And just like that we created a store that will hold a sequence of KeyCode (or undefined if a pressed key does not belong to the Konami Code)!

Implementing the handleKeyDown function

Now that we have our container, we still have to implement the logic that will be executed on each key pressed.

What we would ideally like is to map a pressed key to a KeyCode and append it to the sequence.

We can start by creating a map that will convert a the KeyboardEvent.key property to a KeyCode:

const keyMap: Record<string, KeyCode> = {
  ArrowUp: 'ArrowUp',
  ArrowDown: 'ArrowDown',
  ArrowLeft: 'ArrowLeft',
  ArrowRight: 'ArrowRight',
  a: 'KeyA',
  b: 'KeyB',
  A: 'KeyA',
  B: 'KeyB',
};
Enter fullscreen mode Exit fullscreen mode

What is left is to use it to detect which KeyCode has been pressed:

const lastKeyPressed = readable(
  new Array<KeyCode>(),
  () => {
    const handleKeyDown = (event: KeyboardEvent): void => {
      const keyPressed = keyMap[event.key];
    };

    window.addEventListener('keydown', handleKeyDown);

    return () => window.removeEventListener('keydown', handleKeyDown);
  }
);
Enter fullscreen mode Exit fullscreen mode

However, we might have the key but we do not have any way to access the current value held by the store.

For that, the function used in readable takes two additional parameters:

  • A set function that can be used to set the value of the store
  • An update function that uses a callback to modify the current value of the store

While set would not help in appending a value, update definitely will, let's grab it:

const lastKeyPressed = readable(
  new Array<KeyCode>(),
  (_set, update) => {
    const handleKeyDown = (event: KeyboardEvent): void => {
      const keyPressed = keyMap[event.key];

      update((currentSequence: KeyCode[]) => {
        const next = currentSequence.concat(keyPressed);

        // 👇 Discards the oldest value if the sequence is too long
        if (next.length > konamiCode.length) {
          next.splice(0, 1);
        }

        return next;
      });
    };

    window.addEventListener('keydown', handleKeyDown);

    return () => window.removeEventListener('keydown', handleKeyDown);
  }
);
Enter fullscreen mode Exit fullscreen mode

We now have a store that is storing the latest pressed keys and exposes them as sequence of the Konami Code.

Now onward to detecting it!

Detecting the Konami Code

We have several ways of signaling to a consumer when the Konami Code has been entered.

However, as I'm thinking of stores as a kind of RxJS's Observables, I tend to prefer deriving a value from it to keep my code as declarative as possible.

If the concept of "declarative code" is not something you are familiar with, Joshua Morony has some wonderful videos on that subject:

Hopefully, it seems to also be the case for the Svelte core dev team as it is possible to derive a store from another one by using derived.

To derive a store, the syntax is pretty straightforward:

  • As a first parameter, the derived function is expecting the store to derive its value from
  • As a second parameter, we should define a function that takes the value emitted by the store we derived from and infer the value of the current store

In our case, the inferred value will simply be a boolean evaluated to true if the current sequence matches the Konami Code:

// 👇 Don't forget to export this store!
export const isKonamiCodePressed: Readable<boolean> = derived(
  lastKeyPressed,
  ($pressedKeys: KeyCode[]) => JSON.stringify($pressedKeys) === JSON.stringify(konamiCode)
);
Enter fullscreen mode Exit fullscreen mode

We could have computed the value of JSON.stringify(konamiCode) instead of recomputing it everytime but for the sake of this tutorial I will spare you some additional code

Reacting to Its Detection

With our Konami Code detection store, we can now use it in our Svelte app to add a small easter egg.

In a new Svelte component, all we have to do is to subscribe to the store and react to whenever it has been entered:

<script lang="ts">
  import { onDestroy, onMount } from 'svelte';
  import type { Unsubscriber } from 'svelte/store';

  import { isKonamiCodePressed } from '$lib/stores/konami';


  let unsubscribe: Unsubscriber = () => {};

  onMount(() => {
    unsubscribe = isKonamiCodePressed.subscribe(
      (isKonamiCodePressed: boolean): void => {
        if (!isKonamiCodePressed) return;
        console.log('Konami Code detected!');
      }
    );
  });

  // 👇 Don't forget to remove the event listener
  onDestroy(unsubscribe);
</script>

Enter fullscreen mode Exit fullscreen mode

While it works, a console.log might not be the most funny thing we can do with that.

Let's build something visual and unexpected, like confetti 🎊!

Grab JS Confetti:

npm i js-confetti
Enter fullscreen mode Exit fullscreen mode

And replace the former code with the following one:

<script lang="ts">
  import { onDestroy, onMount } from 'svelte';
  import type { Unsubscriber } from 'svelte/store';

  import JSConfetti from 'js-confetti';

  import { isKonamiCodePressed } from '$lib/stores/konami';

  let unsubscribe: Unsubscriber = () => {};

  onMount(() => {
    const jsConfetti = new JSConfetti();

    unsubscribe = isKonamiCodePressed.subscribe(
      (isKonamiCodePressed: boolean): void => {
        if (!isKonamiCodePressed) return;

        jsConfetti.addConfetti();
      }
    );
  });

  onDestroy(unsubscribe);
</script>
Enter fullscreen mode Exit fullscreen mode

You can now use this component on whatever page you want the user to be able to enter the Konami Code !

Wanna see a live example ? Try it out on my landing page!

You can also see the implementation from which this article is inspired from the sources:

GitHub logo pBouillon / pbouillon.github.io

My personnal website

Landing Page

My landing page, built with Svelte 4, deployed with GitHub Actions and hosted on GitHub Pages.



I hope that you learn something useful there!


Photo by Annie Spratt on Unsplash

Top comments (0)