Blacket/Triangulet Game Modal Opener

Adds a Games button to Blacket/Triangulet

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Blacket/Triangulet Game Modal Opener
// @version      2.5.0
// @description  Adds a Games button to Blacket/Triangulet
// @match        https://blacket.org/*
// @match        https://tri.pengpowers.xyz/*
// @match        https://coplic.com/*
// @grant        none
// @namespace https://greasyfork.org/users/1479014
// ==/UserScript==

(function () {
    'use strict';

    // Insert games panel
    function addGamesPanel() {
        const infoPanel = document.querySelector('.styles__infoContainer___2uI-S-camelCase');
        if (!infoPanel || document.querySelector('#gamesPanel')) return;

        const clone = infoPanel.cloneNode(false);
        clone.id = 'gamesPanel';

        // Header row
        const headerRow = document.createElement('div');
        headerRow.className = 'styles__headerRow___1tdPa-camelCase';
        headerRow.style.display = 'flex';
        headerRow.style.alignItems = 'center';

        const icon = document.createElement('i');
        icon.className = 'fas fa-gamepad styles__headerIcon___1ykdN-camelCase';
        icon.setAttribute('aria-hidden', 'true');
        icon.style.marginRight = '0.5vw';

        const headerText = document.createElement('div');
        headerText.className = 'styles__infoHeader___1lsZY-camelCase';
        headerText.textContent = 'Games';

        headerRow.appendChild(icon);
        headerRow.appendChild(headerText);
        clone.appendChild(headerRow);

        // Styled button like "Upgrade Now!"
        const buttonWrapper = document.createElement('div');
        buttonWrapper.className = 'styles__button___1_E-G-camelCase styles__upgradeButton___3UQMv-camelCase';
        buttonWrapper.setAttribute('role', 'button');
        buttonWrapper.setAttribute('tabindex', '0');
        buttonWrapper.style.cursor = 'pointer';
        buttonWrapper.onclick = createGamesModal;

        const buttonLink = document.createElement('a');
        buttonLink.href = '#';
        buttonLink.style.textDecoration = 'none';

        const shadow = document.createElement('div');
        shadow.className = 'styles__shadow___3GMdH-camelCase';

        const edge = document.createElement('div');
        edge.className = 'styles__edge___3eWfq-camelCase';
        edge.style.backgroundColor = 'var(--secondary)';

        const front = document.createElement('div');
        front.className = 'styles__front___vcvuy-camelCase styles__upgradeButtonInside___396BT-camelCase';
        front.style.backgroundColor = 'var(--secondary)';
        front.textContent = 'Games';

        buttonLink.appendChild(shadow);
        buttonLink.appendChild(edge);
        buttonLink.appendChild(front);
        buttonWrapper.appendChild(buttonLink);
        clone.appendChild(buttonWrapper);

        infoPanel.parentNode.insertBefore(clone, infoPanel.nextSibling);
    }

    // Modal logic
    function createGamesModal() {
        if (document.getElementById('bigModal')) return;

        const backdrop = document.createElement('div');
        backdrop.id = 'modalBackdrop';
        Object.assign(backdrop.style, {
            position: 'fixed',
            top: 0,
            left: 0,
            width: '100vw',
            height: '100vh',
            backgroundColor: 'rgba(0, 0, 0, 0.5)',
            zIndex: 2147483645,
        });
        document.body.appendChild(backdrop);

        const modal = document.createElement('div');
        modal.id = 'bigModal';
        modal.className = 'bb_bigModal';
        Object.assign(modal.style, {
            position: 'fixed',
            top: '50%',
            left: '50%',
            transform: 'translate(-50%, -50%)',
            backgroundColor: '#1a1a1a',
            color: 'white',
            padding: '1.5rem',
            borderRadius: '8px',
            zIndex: 2147483646,
            maxWidth: '90vw',
            maxHeight: '80vh',
            overflowY: 'auto',
            boxShadow: '0 0 10px black',
            fontFamily: '"Nunito", sans-serif',
            userSelect: 'none',
        });

        const title = document.createElement('div');
        title.className = 'bb_bigModalTitle';
        title.textContent = 'Games';
        title.style.fontSize = '1.6rem';
        title.style.fontWeight = 'bold';
        title.style.marginBottom = '0.5rem';
        modal.appendChild(title);

        const desc = document.createElement('div');
        desc.className = 'bb_bigModalDescription';
        desc.textContent = 'Choose a game to play:';
        desc.style.marginBottom = '1rem';
        modal.appendChild(desc);

        const games = [
            ['Play Chrome Dino Game', 'https://chromedino.com/'],
            ["Play Five Nights at Penguin's", 'https://fnap2tuff.glitch.me'],
            ['Play Slope', 'slope'],
            ['Play Minecraft Classic', 'https://classic.minecraft.net/'],
            ['Play Eaglercraft', 'https://eaglercraft.com'],
        ];

        for (const [text, url] of games) {
            const link = document.createElement('a');
            link.href = '#';
            link.textContent = text;
            link.style.display = 'block';
            link.style.color = '#6cf';
            link.style.margin = '0.5rem 0';
            link.onclick = (e) => {
                e.preventDefault();
                closeModal();
                if (url === 'slope') return launchSlopeGame();
                launchIframeGame(url);
            };
            modal.appendChild(link);
        }

        modal.appendChild(document.createElement('hr'));

        const closeBtn = document.createElement('div');
        closeBtn.className = 'styles__button___1_E-G-camelCase styles__button___3zpwV-camelCase';
        closeBtn.setAttribute('role', 'button');
        closeBtn.setAttribute('tabindex', '0');
        closeBtn.style.width = '30%';
        closeBtn.style.marginBottom = '1.5vh';
        closeBtn.style.cursor = 'pointer';

        const shadowDiv = document.createElement('div');
        shadowDiv.className = 'styles__shadow___3GMdH-camelCase';
        closeBtn.appendChild(shadowDiv);

        const edgeDiv = document.createElement('div');
        edgeDiv.className = 'styles__edge___3eWfq-camelCase';
        edgeDiv.style.backgroundColor = '#2f2f2f';
        closeBtn.appendChild(edgeDiv);

        const frontDiv = document.createElement('div');
        frontDiv.className = 'styles__front___vcvuy-camelCase styles__buttonInside___39vdp-camelCase';
        frontDiv.style.backgroundColor = '#2f2f2f';
        frontDiv.textContent = 'Close';
        closeBtn.appendChild(frontDiv);

        closeBtn.onclick = closeModal;
        modal.appendChild(closeBtn);

        document.body.appendChild(modal);
    }

    function closeModal() {
        const modal = document.getElementById('bigModal');
        const backdrop = document.getElementById('modalBackdrop');
        if (modal) modal.remove();
        if (backdrop) backdrop.remove();
    }

    function launchIframeGame(url) {
        document.body.innerHTML = '';
        const iframe = document.createElement('iframe');
        Object.assign(iframe.style, {
            position: 'fixed',
            top: 0,
            left: 0,
            width: '100vw',
            height: '100vh',
            border: 'none',
            zIndex: '9999'
        });
        iframe.src = url;
        document.body.appendChild(iframe);
        setTimeout(createOverlayX, 300);
    }

    function launchSlopeGame() {
        document.body.innerHTML = '';
        const canvas = document.createElement('canvas');
        canvas.id = 'slopeCanvas';
        Object.assign(canvas.style, {
            position: 'fixed',
            top: 0,
            left: 0,
            width: '100vw',
            height: '100vh',
            display: 'block',
            zIndex: '9999'
        });
        document.body.appendChild(canvas);

        const slopeScript = document.createElement('script');
        slopeScript.src = 'https://cdn.jsdelivr.net/gh/iygiyfg/assets/slope.js';
        document.body.appendChild(slopeScript);

        setTimeout(createOverlayX, 500);
    }

    function createOverlayX() {
        if (document.getElementById('x-overlay')) return;

        const font = document.createElement('link');
        font.href = 'https://fonts.googleapis.com/css2?family=Titan+One&display=swap';
        font.rel = 'stylesheet';
        document.head.appendChild(font);

        const overlay = document.createElement('div');
        overlay.id = 'x-overlay';
        Object.assign(overlay.style, {
            position: 'fixed',
            top: '0',
            left: '0',
            width: '100vw',
            height: '100vh',
            zIndex: '2147483647',
            pointerEvents: 'none'
        });

        const x = document.createElement('div');
        x.textContent = 'X';
        x.id = 'x';
        Object.assign(x.style, {
            position: 'absolute',
            top: '1vw',
            right: '1vw',
            fontSize: '2.5vw',
            color: 'red',
            fontFamily: '"Titan One", cursive',
            cursor: 'pointer',
            pointerEvents: 'auto'
        });
        x.onclick = () => location.reload();

        overlay.appendChild(x);
        document.body.appendChild(overlay);
    }

    // Wait for info panel to exist
    const observer = new MutationObserver(() => {
        if (document.querySelector('.styles__infoContainer___2uI-S-camelCase')) {
            observer.disconnect();
            addGamesPanel();
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });
})();