JavaSpooky: Using JavaScript to revive an old horror webcomic from a flashplayer grave.
Tags: javascript, halloween
Published: 2020-10-31 19:47:40

Back in the day, a certain [internet webcomic](https://comic.naver.com/webtoon/detail.nhn?titleId=350217&no=31&weekday=tue) achieved a level of infamy for it's startling twist.

However, the shocking twist that powered that comic was written with [Adobe Flash Player](https://en.wikipedia.org/wiki/Adobe_Flash_Player), which will be completely deprecated from the internet on December 31, 2020.

And thus, a part of internet history was lost to the ages...

Or was it? (BE WARNED, the below link contains spooky jump scares)

https://thatspookycomic.github.io/

Were you brave enough to try it out? I decided to recreate the infamous effect using nothing but vanilla JS, HTML, and CSS along with some new-school web APIs. You can compare the results of the page above with a [recording of the original effect](https://www.youtube.com/watch?v=_vI0Wmxc2cY).

## So how was it done?

### The Jump Scare sound

Let's start from the top of the page. You probably noticed the pumpkin emoji that the page tells you to click on, right?

![Pumpkin Emoji with some text telling you to click it](https://dev-to-uploads.s3.amazonaws.com/i/9btja8yeb2nvtaqq311h.png)
 
Seems like a cute little innocent Halloween fun, right? Well, it actually hides a sinister purpose.

In order to play the jump scare noises on the page, I use a web API called [Audio](https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement/Audio). 

Now, the Audio tool is designed to prevent the annoyance of auto-playing media that starts when a webpage is opened. If the user has not interacted with the document, when you try to play a sound you get this error: 

![Dev Tools console error saying user has to interact with document before audio will play](https://dev-to-uploads.s3.amazonaws.com/i/8s1nl7jcko2fpc5e00yu.png)

So in order for us to do something like:

```javascript
const spookySound = new Audio('audio/spooky-sound.mp3');
spookySound.play();
```

We first have to incentive the user to click somewhere on the page! So I dropped in a little JS to update a pumpkin emoji onclick:

```html
<span id="clickEmoji" onclick="emojiClickChange()">🎃</span>
```

```javascript
function emojiClickChange() {
  document.getElementById('clickEmoji').innerText = "👻";
}
```

We are now ready to fire off some scary sounds!

### Triggering the Jump Scare

Next up, we need to detect when the user has scrolled to a certain point on the page, where we need to fire the jump scare effect.

To do that, we use the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).

I dropped an id on the two images where I wanted the jump scare to occur:

```html
<img src="images/7.jpg" id="firstTarget" />
...
<img src="images/17.jpg" id="secondTarget" />
```

and then I create an observer and observe those images:

```javascript
let observer = new IntersectionObserver(handler);
observer.observe(document.getElementById('firstTarget'));
observer.observe(document.getElementById('secondTarget'));
```

Now, we can create a function that will be called whenever the state of those observed items changes!

```javascript
function handler(entries) {
  for (entry of entries) {
    if (
      entry.target.id === 'firstTarget'
      && entry.isIntersecting
      && !firstJumpScareActivated
    ) {
      playFirstJumpScare();
    }
  }
}
```

Whenever any of the observed items changes state the `handler` function is called. We can read `entry.target.id` to know what item we are dealing with, `isIntersecting` to know if the user has scrolled the item into view, and I use a boolean `XJumpScareActivated` to make sure the effect only happens once.

One last thing, if your images load in slow, the effect might be triggered if the id is briefly in frame when the page loads. The right way to fix this is to wait for all images to be loaded before starting the intersection observer, but for the sake of simplicity, a setTimeout did the job for me:

```javascript
setTimeout(() => {
  observer.observe(document.getElementById('firstTarget'));
  observer.observe(document.getElementById('secondTarget'));
}, 3000)
```

Great, we can now tell when the user has scrolled our target item into view, and we are ready to play sound. Last up, we need to create the rapid scrolling jump effect!

### Auto scrolling the user around

In order for this jump scare to work properly, we want to rapidly scroll the user through the comic frames while playing a sound. The scariest part of this effect comes from the fact that the user thinks they have control of the pace of the comic, and we want to rapidly tear that control away from them.

The way I built this was by scrolling to each part of the page I wanted to scroll the user to, and in the dev tools console, typing `window.scrollY`:

![Screen Shot 2020-10-31 at 2.31.09 PM](https://dev-to-uploads.s3.amazonaws.com/i/n05lw7hexlrtc5ytfwar.png)
 
Now that I had the Y coordinate I wanted, I just trigger the scroll effect at setTimeout intervals on each Y coordinate. The code looks like this:

```javascript
function playFirstJumpScare() {
  setTimeout(() => {
    clickSound.play();
    window.scrollTo(0, 8441);
  }, 800)

  setTimeout(() => {
    window.scrollTo(0, 9090);
  }, 900)

  setTimeout(() => {
    window.scrollTo(0, 9660);
  }, 1000)

  ...
}
```

Future improvements could involve putting all the times and scroll positions into an array of objects and mapping through them:

```javascript
[
  {
    time: 800,
    scrollPos: 8441
  },
  ...
]
```

But today is Halloween already and I needed to release this thing, stat! So for now, the code stays ugly.

Once I activate the jump scare, I set a boolean to true so that it doesn't happen again:

```javascript
firstJumpScareActivated = true;
```

Finally, to get the website online, I created a new GitHub account and used [GitHub Pages](https://pages.github.com/), you can see the full code of the website [here](https://github.com/thatspookycomic/thatspookycomic.github.io/).

I hope this was informative, interesting, and most importantly, terrifying. Feel free to share the comic with all your friends this spooky last night of October! Happy Halloween!