Useless Hack a Week.

Browser Jumpscares, a Halloween special hack

Cover Image for Browser Jumpscares, a Halloween special hack
Nick
Nick

BOO!

Boo

Did that scare you? Probably not, but this extension will.

Browser Jumscares

Browsing the internet is too peaceful. Its usually quiet, slow paced, and a very mundane experience.

We changed that with Browser Jumpscares.

This extension makes it so randomly while browsing the internet, you can be jump scared.

Why? Why make something so evil?

Why? Because its Halloween.

Why do we watch scary movies? Why do we visit haunted houses? Why do we do anything that involves making us uncomfortable or scared?

scary Smile, 2022

BECAUSE BEING UNSETTLED IS EXCITING

Maybe it's the adrenaline rush, maybe it's feeling closer to death. All we know, is there is something that draws us to being spooked, and thats worth embracing every once in a while.

Storytime

Back in high school, there was an abandoned house near where I lived, and for the first time in 10 years, the back door was unlocked...

unlocked Creeeeeaaaaak

The door opens... REVEALING

A very normal, empty house house

I had multiple friends coming over to my house that day, and they all arrived at different times, so we came up with a genius idea:

Let's check this place out BEFORE one of our friends arrive, have one of our friends hide in a room in the abandonded house, and return later with our late arrival, and pretend this is the first time inside.

diagram

Our friend will be hiding in one of the room, and our unsuspecting friend will open the door.

And it worked perfectly.

We scared him good, real good.

What is the point of this story?

Scaring people is FUN, and as we get older, we're less likely to have time to be childish, scare each other, visit abandonded houses, or have the free time to watch scary movies, go to halloween horror nights, or do things that would otherwise excite us.

Movie

And that's where this extension comes in.

Implementation

Let's go over the file structure of this hack.

File Structure

It's very simple, all we have is

  • A typical manifest.json file (Which all google extensions have)
  • A background.js file for our jumpscare logic
  • A content.js file with our toggle hotkey script
  • Folders to store our jumpscare images & audio

manifest.json

{
    "manifest_version": 3,
    "name": "Jump Scare Extension",
    "version": "1.0",
    "description": "A Chrome extension for jump scares",
    "permissions": [
        "activeTab",
        "alarms",
        "storage",
        "scripting"
    ],
    "host_permissions": [
        "http://*/*",
        "https://*/*"
    ],
    "content_security_policy": {
        "extension_pages": "script-src 'self'; object-src 'self';"
    },
    "web_accessible_resources": [
        {
            "resources": [
                "images/*.png"
            ],
            "matches": [
                "<all_urls>"
            ]
        },
        {
            "resources": [
                "audio/*.mp3"
            ],
            "matches": [
                "<all_urls>"
            ]
        }
    ],
    "background": {
        "service_worker": "background.js"
    }
}

In this file, we simply give ourselves all the permissions needed to make jumpscares work, reference our background script, and allow the extension to access our images and audio.

content.js

document.addEventListener('keydown', (e) => {
    if (e.key === '`') {
        chrome.runtime.sendMessage({ message: "toggle_jumpscares" });
    }
});

This file specifies what the toggle hotkey ('`') will be, and what message to send to the other chrome functions.

Chrome Functions

chrome.runtime.onInstalled.addListener(async () => {
    await chrome.storage.local.set({ jumpscareEnabled: true });
    setJumpScareAlarm();
});

This listener activates when the Chrome extension is installed or updated. It ensures that the jump scare feature is enabled in the extension's local storage and sets up the initial timer for the jump scare using the setJumpScareAlarm function.

chrome.alarms.onAlarm.addListener(async (alarm) => {
    if (alarm.name === 'jumpscareAlarm') {
        const result = await chrome.storage.local.get('jumpscareEnabled');
        if (result.jumpscareEnabled) {
            initiateJumpScare();
            setJumpScareAlarm();
        }
    }
});

This listener keeps an eye out for triggered alarms. If the alarm named jumpscareAlarm is set off, it checks if the jump scare feature is active. If it is, the extension initiates a jump scare and resets the timer for the next one.

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.message === "toggle_jumpscares") {
        chrome.storage.local.get('jumpscareEnabled', (result) => {
            // Toggle the jumpscareEnabled value
            const newState = !result.jumpscareEnabled;
            chrome.storage.local.set({ jumpscareEnabled: newState });
            if (newState) {
                setJumpScareAlarm();
            } else {
                chrome.alarms.clear('jumpscareAlarm');
            }
        });
    } else if (request.message === "disable_jumpscares") {
        chrome.storage.local.set({ jumpscareEnabled: false });
        chrome.alarms.clear('jumpscareAlarm');
    } else if (request.message === "reset_jumpscares") {
        chrome.storage.local.set({ jumpscareEnabled: true });
        setJumpScareAlarm();
    }
});

This listener waits for specific messages from other parts of the extension.

It provides functionalities to toggle the jump scare feature on or off, disable it, or reset it. Depending on the message received, it either updates the local storage's jump scare setting, clears the current jump scare timer, or sets a new one.

You can use the '`' key to toggle the extension. This makes it really easy for you to have it off while you are using your computer, but easy to enable if you want to prank your friend when they come over, or when someone uses your computer specifically.

setJumpscareAlarm

function setJumpScareAlarm() {
    // Set an alarm to go off in a random time within 20 minutes
    const randomTime = Math.random() * 20;
    chrome.alarms.create('jumpscareAlarm', { delayInMinutes: randomTime });
}

This function sets the timer on which the jumpscare will run on. Here, I have set it to randomly play within 20 minute intervals, but it can be set to happen as frequent or infrequent as you want.

initiateJumpScare

function initiateJumpScare() {
    chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
        const activeTab = tabs[0];
        if (activeTab && typeof activeTab.url === 'string' && !activeTab.url.startsWith("chrome://") && !activeTab.url.startsWith("https://chrome.google.com/webstore/")) {
            chrome.scripting.executeScript({
                target: { tabId: activeTab.id },
                func: triggerJumpScare,
                args: []
            });
        }
    });
}

Some URLs do not allow autoplay content, especially from audio sources to happen on their pages. This can cause a bug where the jumpscare image will appear, but without the audio. Since the image dissapearing is tied directly to the end of the audio file, this can cause the jumpscare image to stay stuck on your screen.

This function helps avoid that by preventing the logic from running all together if the current URL is not a suitable one for triggering the jumpscare. It checks if it should run that function in the active tab, and inserts the triggerJumpScare function if conditions are met.

triggerJumpScare

function triggerJumpScare() {
    const jumpScares = [
        {
            imgSrc: chrome.runtime.getURL("images/example.png"),
            audioSrc: chrome.runtime.getURL("audio/example/mp3")
        },
        {
            imgSrc: chrome.runtime.getURL("images/example2.png"),
            audioSrc: chrome.runtime.getURL("audio/example2.mp3")
        }
        // ... other jump scares
    ];

    const randomIndex = Math.floor(Math.random() * jumpScares.length);
    const selectedJumpScare = jumpScares[randomIndex];

    // Play the jumpscare audio using Web Audio API
    const audioContext = new (window.AudioContext || window.webkitAudioContext)();

    fetch(selectedJumpScare.audioSrc)
        .then(response => response.arrayBuffer())
        .then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
        .then(audioBuffer => {
            const source = audioContext.createBufferSource();
            source.buffer = audioBuffer;
            source.connect(audioContext.destination);
            source.start();

            // Check if audioContext is running
            if (audioContext.state !== "running") {
                // If not running, it means autoplay might be blocked. Return early.
                return;
            }

            // Inject the shake keyframes CSS
            const styleElement = document.createElement('style');
            styleElement.textContent = `
                @keyframes shake {
                    0% { transform: translate(-50%, -50%) translate(0, 0); }
                    10% { transform: translate(-50%, -50%) translate(-10px, -5px); }
                    20% { transform: translate(-50%, -50%) translate(10px, 5px); }
                    30% { transform: translate(-50%, -50%) translate(-10px, -5px); }
                    40% { transform: translate(-50%, -50%) translate(10px, 5px); }
                    50% { transform: translate(-50%, -50%) translate(-10px, -5px); }
                    60% { transform: translate(-50%, -50%) translate(10px, 5px); }
                    70% { transform: translate(-50%, -50%) translate(-10px, -5px); }
                    80% { transform: translate(-50%, -50%) translate(10px, 5px); }
                    90% { transform: translate(-50%, -50%) translate(-10px, -5px); }
                    100% { transform: translate(-50%, -50%) translate(0, 0); }
                }
            `;
            document.head.appendChild(styleElement);

            // Display the jumpscare image with shake animation
            const jumpScareContainer = document.createElement('div');
            jumpScareContainer.innerHTML = `
                <img src="${selectedJumpScare.imgSrc}" alt="Jump Scare" />
            `;
            jumpScareContainer.style.cssText = `
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                z-index: 10000;
                animation: shake 0.5s infinite;
            `;
            document.body.appendChild(jumpScareContainer);

            source.onended = () => {
                jumpScareContainer.remove();
                styleElement.remove(); // remove the style once done
            };
        });
}

The heart of the jump scare functionality lies here.

This function contains an array of different jump scares, each with its image and audio. It randomly selects one of the scares and attempts to play its audio. If the audio plays successfully (i.e., it's not blocked due to browser restrictions), the image is displayed with the hardcoded CSS animation (shaking), and then removed when the audio file finishes playing.

Results

A new great way to spook n prank ur friends!

P.S They are loud, so be prepared 0.0

 

Code for this project can be found here!

Do you like unhinged content? Follow me on X! Or Buy me a coffee!