Enhanced Visuals: improves your visuals making the experience better!

Adds better Visuals to Sploop.io! Such Item effects, perfect hitbox, shadows, footsteps, weapon range, and more!

// ==UserScript==
// @name           Enhanced Visuals: improves your visuals making the experience better!
// @version        v-3.5
// @description    Adds better Visuals to Sploop.io! Such Item effects, perfect hitbox, shadows, footsteps, weapon range, and more!

// @namespace      EHD
// @license        All Rights Reserved
// @author         Cubic Flex [CF]
// @match          *://sploop.io/
// @grant          none
// @icon           https://cdn.glitch.global/499d2ba6-cd57-4e5f-8b56-5557baa5b3a0/EHD%20Visuals.png?v=1709777562902
// ==/UserScript==

/*!
 * Enhanced Visuals [*Free Version] v3.5.1
 * https://discord.gg/aZGuQmrm8z
 *
 * Auto save features
 * Mouse over for tooltips (feature description)
 * Hold click to settings menu
 *
 * More info at:
 * https://io-mods.glitch.me/
 *
 * Made By: Cubic Flex [CF] | 10/11/2024 (mmddyy)
 */

//[=]=> Util functions
class MouseManager {
    constructor() {
        this.x = 0;
        this.y = 0;
        this.resize();
    }

    listeners() {
        window.addEventListener('mousemove', this.move.bind(this));
        window.addEventListener('resize', this.resize.bind(this));
    }

    resize() {
        this.width = window.innerWidth;
        this.height = window.innerHeight;

        this.update();
    }

    move(e) {
        this.x = e.clientX;
        this.y = e.clientY;

        this.update();
    }

    update() {
        this.angle = Math.atan2(this.y - this.height / 2, this.x - this.width / 2);
    }
}

class Img extends Image {
    constructor(src, width = 150, height = 150) {
        super(width, height);

        this.src = src;
    }
}

class Utils {
    static distance(player1, player2) {
        return Math.sqrt(Math.pow(player2.y - player1.y, 2) +
                         Math.pow(player2.x - player1.x, 2));
    }

    static lerp(start, end, amt) {
        return start + (end - start) * amt;
    }

    static try_parse(STRING) {
        try {
            return JSON.parse(STRING);
        } catch {
            return 'Failed to PARSE'
        }
    }

    static ls_get(key) {
        const got = localStorage[key];

        return got ? this.try_parse(got) : false;
    }

    static ls_set(key, value) {
        localStorage[key] = typeof value === 'string' ? value : JSON.stringify(value);
    }
}

class Tooltip {
    static show(id, title) {
        const TIP = document.querySelector('#tooltip-menu');
        const feature = All_features[id];

        TIP.style.opacity = '1';
        TIP.innerHTML = title || feature.info;
        TIP.style.left = Mouse.x + 'px';
        TIP.style.top = Mouse.y + 'px';
    }

    static hide() {
        const TIP = document.querySelector('#tooltip-menu');

        TIP.style.opacity = '0';
    }
}

//[=]=> Variables def.
const server = {
    request_received: 17,
    entity_spawned: 32,
    items_upgrade: 2,
    items_count: 36,
    ping_update: 15,
    create_clan: 24,
    update_clan: 16,
    entity_chat: 30,
    leave_clan: 27,
    update_age: 8,
    item_hit: 29,
    upgrades: 14,
    spawned: 35,
    killed: 28,
    update: 20,
    died: 19
}

const All_features = {
    colored_hp: {
        name: 'Colored HP',
        info: 'Colors your health bar',
        icon: 'palette-fill',
        enabled: true
    },
    display_hp: {
        name: 'Display HP',
        info: 'Shows how many hp you have',
        icon: 'percent',
        enabled: true
    },
    smooth_hp: {
        name: 'Smooth HP',
        info: 'Makes the health bar smoother',
        icon: 'water',
        enabled: true
    },
    healing_effect: {
        name: 'Healing effect',
        info: 'Particles come out when heal',
        icon: 'apple',
        enabled: true
    },
    weapon_range: {
        name: 'Weapon range',
        info: 'Shows weapon range',
        icon: 'opencollective',
        enabled: true
    },
    hitbox: {
        name: 'Hitbox',
        info: 'Shows objects hitbox',
        icon: 'disc',
        enabled: false
    },
    tornado_particles: {
        name: 'Tornado particles',
        info: 'Adds particles to tornadoes',
        icon: 'tornado',
        enabled: true
    },
    footsteps: {
        name: 'Footsteps',
        info: 'Shows footsteps',
        icon: 'meta',
        enabled: true
    },
    hide_ads: {
        name: 'Hide ads',
        info: 'Hide ads from the game menu',
        icon: 'eye-slash-fill',
        enabled: true
    },
    night_mode: {
        name: 'Night mode',
        info: 'Night mode in sploop',
        icon: 'moon-stars-fill',
        enabled: false
    },
    name_changer: {
        name: 'Name changer',
        info: 'Changes the mob names',
        icon: 'marker-tip',
        enabled: false
    }
}

const Features = Utils.ls_get('ehd_features') || {
    colored_hp: true,
    display_hp: true,
    smooth_hp: true,
    healing_effect: true,
    weapon_range: true,
    hitbox: false,
    tornado_particles: true,
    footsteps: true,
    hide_ads: true,
    night_mode: false,
    name_changer: false
}

const Settings = Utils.ls_get('ehd_settings') || {
    colored_hp: {
        mine_health: '#611a80',
        enemy_health: '#ae6999'
    },
    weapon_range: {
        color: '#404040',
        cap: true
    },
    hitbox: {
        color: '#50C878'
    },
    footsteps: {
        land: false
    },
    name_changers: {
        Wolf: 'Dog',
        Dragon: 'Boss',
        Duck: 'Quack'
    }
}

for (const key in All_features) {
    if (All_features.hasOwnProperty(key)) {
        if (!Features.hasOwnProperty(key)) {
            Features[key] = All_features[key].enabled;
        }
    }
}

const Vars = {
    loaded: false,
    entities: [],
    steps: [],
    heals: [],
    health: false,
    images: {
        cookie: new Img('https://sploop.io/img/entity/cookie.png'),
        apple: new Img('https://sploop.io/img/entity/apple.png')
    },
    holds: {}
}

//[=]=> Menu functions
class MenuManager {
    static parseID(id) {
        const value = id.children[1].innerHTML;

        return value.replace(/ /g, '_').toLowerCase();
    }

    static parseSetting(element) {
        const value = element.parentElement.parentElement;
        const feature = value.parentElement.classList[1].replace(/settings\-/g, '');

        return {
            feature,
            id: value.classList[2]
        }
    }

    static removeNC(element) {
        const name = element.parentElement.children[1].children[0];
        const value = name.innerHTML;

        // Cleans the input values, adds it to the settings & close the "dropdown"
        delete Settings.name_changers[value];

        // Then append the replacers again lm4o
        this.appendReplacer()
    }

    static addNC(element) {
        const inputs = element.parentElement.children[1].children;
        const name = inputs[0];
        const replace = inputs[2];

        if (name.value.trim().length < 1) return name.focus();
        if (replace.value.trim().length < 1) return replace.focus();

        // Cleans the input values, adds it to the settings & close the "dropdown"
        Settings.name_changers[name.value] = replace.value;

        document.querySelector('.button-plus').click() //MenuManager.toggleNewNC(this);

        name.value = '';
        replace.value = '';

        // Then append the replacers again lm4o
        this.appendReplacer()
    }

    static appendReplacer() {
        // Appends each name changer
        let string = '';

        for (let name in Settings.name_changers) {
            const change = Settings.name_changers[name];

            string += `
                <div class="name-changer">
                    <i class="text bi bi-trash-fill" onclick="MenuManager.removeNC(this)"></i>

                    <div class="name-changes">
                        <span>${name}</span>
                        <i class="bi bi-arrow-left-right"></i>
                        <span> ${change} </span>
                    </div>
                </div>
            `;
        }

        document.querySelector('#name-changer-wrap').innerHTML = string;
    }

    static changeIcon(element, over, icon, remove) {
        setTimeout(() => {
            element.classList = `bi bi-${icon}`
        }, 1e3 / 60)
    }

    static toggleNewNC(element) {
        // Display / hide
        const edit = document.querySelectorAll('.edit');
        const display = edit[0].style.display === 'flex' ? 'none' : 'flex';
        const icon = edit[0].style.display === 'flex' ? 'bi bi-plus' : 'bi bi-dash';

        edit.forEach(edit => {
            edit.style.display = display;
        });

        // Focus the input
        const input = document.querySelector('.name-changes').children[0];
        input.focus();

        // Change this icon
        element.children[0].classList = icon;
    }

    static searchParent(element, parentClass) {
        function repeat(elem) {
            if (!elem || !elem.parentElement) {
                return null;
            }

            const contains = elem.parentElement.classList.contains(parentClass);

            if (contains) {
                return elem.parentElement;
            } else {
                return repeat(elem.parentElement);
            }
        }

        return repeat(element);
    }

    static enable(element, id, enabled, disabled) {
        const { feature } = this.parseSetting(element);
        const Setting = Settings[feature][id];

        Settings[feature][id] = element.checked;

        if (!enabled) return;

        const parent = this.searchParent(element, 'switch')
        const icon = parent.querySelector('i');

        icon.classList = `bi bi-${element.checked ? enabled : disabled}`
    }

    static changeColor(element) {
        // Remove all balls active class & add it to self
        const balls = element.parentElement.children;

        for (let ballID in balls) {
            const ball = balls[ballID];

            if (ball.classList?.contains('color-ball')) {
                ball.classList.remove('active');
            }
        }

        element.classList.add('active')

        // Now apply the color to the settings
        const { feature, id } = this.parseSetting(element);

        Settings[feature][id] = element.style.backgroundColor;
    }

    static colorPicker(element) {
        // First apply the color to the settings
        const { feature, id } = this.parseSetting(element);

        Settings[feature][id] = element.value;

        // Then change the color in the ball
        const balls = element.parentElement.parentElement.children[0].children;

        for (let ballID in balls) {
            const ball = balls[ballID];

            if (ball.classList?.contains('picker-div')) {
                ball.style.backgroundColor = element.value
                ball.classList.add('active')
            } else if (ball.classList?.contains('color-ball')) {
                ball.classList.remove('active')
            }
        }

        // Make this element active
    }

    static ToggleToolTip(raw_id, hovering) {
        const id = this.parseID(raw_id);

        if (!hovering) {
            Tooltip.hide()
            return;
        }

        Tooltip.show(id);
    }

    static display(menu, toggle, trigger) {
        menu.style.display = toggle ? 'block' : 'none';

        setTimeout(() => {
            trigger || this.s_opacity(menu, toggle, true);
        }, trigger ? 80 : 0);
    }

    static s_opacity(menu, toggle, trigger) {
        menu.style.opacity = toggle ? '1' : '0';

        setTimeout(() => {
            trigger || this.display(menu, toggle, true);
        }, trigger ? 0 : 400);
    }

    static toggleSelector() {
        // frist change the text to select feture
        document.querySelector('.settings-icon').classList = `bi bi-sliders2 settings-icon`;
        document.querySelector('.settings-name').innerHTML = 'Select a feature';

        // THEN open the selector andclose body
        document.querySelector('.settings-selector').style.display = 'flex';
        document.querySelector('.settings-body').style.display = 'none';
    }

    static toggleSettings(raw_id, toggle) {
        const id = toggle && this.parseID(raw_id);
        const menu = document.querySelector('#settings-menu');

        toggle ? this.display(menu, toggle) : this.s_opacity(menu, toggle);

        if (!toggle) return;
        // ok if its opening then: append the name and info to the menu
        const { icon, name } = All_features[id];
        document.querySelector('.settings-icon').classList = `bi bi-${icon} settings-icon`;
        document.querySelector('.settings-name').innerHTML = name;

        // First closes "all feature settings" div then open the settings div
        document.querySelector('.settings-selector').style.display = 'none';
        document.querySelector('.settings-body').style.display = 'block';

        // After open the div card, if it has a card then open the card if not open the error card kk
        const setting_divs = document.querySelectorAll('.setting');
        const error = document.querySelector('.settings-undefined');

        setting_divs.forEach(div => {
            div.style.display = 'none'; // also clsoes all the opened cards
        })

        const setting = document.querySelector(`.settings-${id}`);
        (setting || error).style.display = 'block';
    }

    static ToggleFeature(raw_id, holding) {
        if (holding) {
            Vars.holds[raw_id] = Date.now();
            return;
        }

        // Handle MouseUp
        const date = Date.now() - Vars.holds[raw_id];

        if (date > 200) { // Holding
            this.toggleSettings(raw_id, true)
            return;
        }

        const id = this.parseID(raw_id);

        Features[id] = !Features[id];

        // Add the active class
        const setting = document.querySelector(`.setting-div-${id}`);
        const toggle = Features[id] ? 'add' : 'remove';

        raw_id.classList[toggle]('active')
        setting.classList[toggle]('active')
    }

    static minimize(element) {
        const menu = document.querySelector('#ehd-menu');
        const minimized = menu.style.width === '4.6vw';

        element.style.rotate = !minimized ? '0deg' : '180deg'; // rotate the arrow
        menu.style.width = minimized ? '16vw' : '4.6vw'; // adjust width

        menu.classList[minimized ? 'remove' : 'add']('minimized'); // then just add / remove the minimized class
    }

    static opacity(element) {
        const checked = element.checked;
        const color = checked ? 'rgb(255 255 255 / .25)' : 'transparent';

        document.querySelector('#ehd-menu').style.opacity = checked ? '.6' : '1';
        document.querySelector('#transparency').parentElement.style.backgroundColor = color;
    }
}

//[=]=> Css !
const CSS = document.createElement('style');
      CSS.innerHTML = `
          @import url("https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css");

          :root {
              --main: #242527;
              --softer: #3a3b3d;
              --color: #dedee0;
              --gray: #a6a7a9;

              --light-gray: #3a3b3d;

              --text: url(img/ui/cursor-text.png) 16 0, text;
              --default: url(img/ui/cursor-default.png) 2 0, default;
              --pointer: url(img/ui/cursor-pointer.png) 6 0, pointer;
              --index: 100000000;
          }

          * {
              transition: all 0.4s ease;
              transition-duration: .4s /* lmao=? */
          }

          @keyframes glow {
              0% {
                  box-shadow: 0 0 20px -1.1vw rgba(255, 255, 255, 0.9);
              }

              50% {
                  box-shadow: 0 0 40px -1.1vw rgba(255, 255, 255, 0.9);
              }

              100% {
                  box-shadow: 0 0 20px -1.1vw rgba(255, 255, 255, 0.9);
              }
          }

          @keyframes rotate {
              0% {
                  transform: scale(1) rotateY(0deg)
              }

              50% {
                  transform: scale(1.15) rotateY(180deg)
              }

              100% {
                  transform: scale(1) rotateY(0deg)
              }
          }

          @keyframes rotateDeg {
              0% {
                  rotate: 0deg
              }

              50% {
                  rotate: 360deg
              }

              100% {
                  rotate: 0deg
              }
          }

          .ehd_scrollBar::-webkit-scrollbar,
          .ehd_scrollBar *::-webkit-scrollbar {
              height: 7px;
              width: 7px;
          }

          .ehd_scrollBar::-webkit-scrollbar-track,
          .ehd_scrollBar *::-webkit-scrollbar-track {
              border-radius: 5px;
              background-color: transparent;
          }

          .ehd_scrollBar::-webkit-scrollbar-track:hover,
          .ehd_scrollBar *::-webkit-scrollbar-track:hover {
              background-color: #B8C0C2;
          }

          .ehd_scrollBar::-webkit-scrollbar-track:active,
          .ehd_scrollBar *::-webkit-scrollbar-track:active {
              background-color: #B8C0C2;
          }

          .ehd_scrollBar::-webkit-scrollbar-thumb,
          .ehd_scrollBar *::-webkit-scrollbar-thumb {
              border-radius: 5px;
              background-color: #5E5E5E;
          }

          .ehd_scrollBar::-webkit-scrollbar-thumb:hover,
          .ehd_scrollBar *::-webkit-scrollbar-thumb:hover {
              background-color: #474747;
          }

          .ehd_scrollBar::-webkit-scrollbar-thumb:active,
          .ehd_scrollBar *::-webkit-scrollbar-thumb:active {
              background-color: #7F7F7F;
          }

          #ehd-menu {
              overflow: hidden;
              background-color: var(--main);
              z-index: var(--index);
              position: fixed;
              left: 1.5vw;
              top: 1.5vw;
              width: 16vw;
              height: 32vw;
              border-radius: .7vw;
              display: flex;
              flex-direction: column;
              box-shadow: 0px 0px 6px 0px black
          }

          #ehd-menu.minimized .body {
              overflow: hidden /* idk, why can you scroll while minimized? no sense ig */
          }

          #ehd-menu.minimized .checkbox,
          #ehd-menu.minimized span {
              font-size: 0vw;
              width: 0vw !important
          }

          #ehd-menu.minimized .menu-size {
              margin-left: 2.8vw
          }

          #ehd-menu div {
              width: 100%;
          }

          #ehd-menu .header {
              height: 16%;
              padding: 1vw;
              display: flex;
              flex-direction: row;
              justify-content: flex-start;
              align-items: center;
          }

          #ehd-menu .body {
              padding: 1vw;
              height: 60%;
              overflow: scroll;
              overflow-x: hidden
          }

          #ehd-menu .footer {
              border-top: 1px solid #47484a;
              padding: 1vw;
              height: max-content
          }

          .header img {
              width: 2.8vw;
              margin-right: .8vw;
              border-radius: 0.4vw
          }

          .header span {
              color: var(--color);
          }

          .header-holder {
              display: flex;
              flex-direction: column
          }

          .header-holder span {
              font-weight: 700;
              font-size: .9vw
          }

          .description {
              color: var(--gray) !important;
              font-size: .8vw !important
          }

          .menu-button {
              margin-bottom: .3vw;
              height: max-content;
              padding: 0.7vw;
              display: flex;
              flex-direction: row;
              align-items: center;
              text-align: left;
              color: var(--color);
              border-radius: 0.4vw;
              overflow: hidden
          }

          .menu-button:hover {
              background: rgb(255 255 255 / .05);
          }

          .menu-button.active {
              background: rgb(255 255 255 / .15);
          }

          .menu-button i,
          .menu-button span {
              margin-right: .7vw;
              font-weight: 600;
              font-size: 1.2vw
          }

          .menu-button span {
              font-size: 0.9vw
          }

          .menu-button,
          .menu-button * {
              cursor: var(--pointer);
          }

          .separator {
              display: flex;
              align-items: center;
          }

          .switch {
              display: flex;
              min-width: 2vw;
              justify-content: space-between;
          }

          .switch * {
              cursor: var(--pointer)
          }

          .switch input[type="checkbox"] {
              opacity: 0;
              position: fixed
          }

          .checkbox {
              display: block;
              width: 2.5vw !important;
              height: 1vw;
              border-radius: 20vw;
              background-color: white;
          }

          .switch .checkbox::before {
              content: '';
              display: block;
              width: 0.8vw;
              height: 0.8vw;
              border-radius: 50%;
              margin: .1vw;
              background-color: var(--main);
              transition: margin-left 0.3s ease
          }

          .switch input[type="checkbox"]:checked + .checkbox::before {
              margin-left: 1.15vw
          }

          .menu-size {
              background-color: var(--light-gray);
              position: fixed;
              border-radius: 50%;
              width: 1.7vw !important;
              height: 1.7vw;
              margin-left: 14vw;
              display: flex;
              flex-direction: row;
              align-items: center;
              justify-content: center;
              font-weight: bolder;
              font-size: 1vw;
              cursor: var(--pointer);
              text-shadow: 0px 0px 1px white;
              box-shadow: 0px 0px 2px black;
              rotate: 180deg
          }

          .menu-size i {
              cursor: var(--pointer);
              color: white;
          }

          #tooltip-menu {
              position: fixed;
              top: 100px;
              left: 220px;
              pointer-events: none;
              background-color: #1d1e1f;
              color: white;
              font-family: 'Baloo Paaji';
              font-weight: 300;
              z-index: calc(var(--index) + 10);
              border-radius: 0.4vw;
              height: 2.8vw;
              padding: 0.4vw 1vw;
              box-shadow: 0px 0px 6px var(--main);
          }

          #settings-menu,
          .night-card {
              position: fixed;
              top: 0;
              left: 0;
              width: 100%;
              height: 100%;
              background: radial-gradient(transparent, rgb(0 0 0 / .6));
              pointer-events: none;
              z-index: calc(var(--index) - 1);
          }

          #settings-menu {
              display: none;
              opacity: 0;
              background: none;
              background-color: rgb(0 0 0 / .4);
              z-index: calc(var(--index) + 2);
              pointer-events: all
          }

          #settings-menu .container {
              display: flex;
              flex-direction: column;
              width: 30%;
              height: 60%;
              margin: 10% auto;
              background: var(--main);
              border-radius: .7vw;
              padding: 1.5vw;
              box-shadow: 0px 0px 6px 0px var(--main)
          }

          #main-content {
              width: max-content
          }

          .settings-header {
              display: flex;
              flex-direction: row;
              justify-content: space-between;
              margin-bottom: 0.5vw
          }

          .settings-header * {
              font-size: 2.7vw;
              font-weight: 700;
              color: var(--color);
          }

          .feature-container {
              display: flex;
              flex-direction: column;
              justify-content: center;
          }

          .feature-container * {
              font-size: 1.3vw;
          }

          .settings-button {
              cursor: var(--pointer)
          }

          .settings-button:hover {
              animation: rotateDeg 1.5s ease forwards
          }

          .actual-feature { /* Same as desc but diff font size */
              color: var(--gray) !important;
              font-size: 1vw !important
          }

          .settings-body,
          .settings-selector {
              width: 100%;
              height: 100%;
              background: #1d1d1d;
              padding: 1vw;
              border-radius: 0.4vw;
              overflow: scroll;
              overflow-x: hidden
          }

          .settings-body *,
          .settings-selector * {
              color: var(--color);
              font-weight: 600;
              font-size: 1.175vw;
          }

          .settings-selector {
              flex-direction: row;
              flex-wrap: wrap;
              justify-content: center;
              align-content: flex-start;
          }

          .settings-item {
              width: 4vw;
              height: 4vw;
              background: rgb(255 255 255 / .025);
              display: grid;
              align-items: center;
              justify-content: center;
              border-radius: 1vw;
              cursor: var(--pointer);
              margin: 1vw;
          }

          .settings-item:hover {
              background: rgb(255 255 255 / .25);
              border-radius: .6vw;
          }

          .settings-item.active {
              background: rgb(255 255 255 / .15);
          }

          .settings-item * {
              cursor: var(--pointer);
              font-size: 2vw
          }

          .color-ball {
              width: 1.5vw;
              height: 1.5vw;
              border-radius: 50%;
              margin: 0vw 0.6vw;
              cursor: var(--pointer);
          }

          .color-ball:hover {
              filter: brightness(.7);
              border-radius: 30%
          }

          .color-ball.active::before {
              transition: all 0.4s ease;
              content: '';
              display: flex;
              width: 109%;
              height: 110%;
              border: 0.15vw solid rgb(255 255 255 / 0.25);
              border-radius: 50%;
              margin: -.22vw;
          }

          .color-ball.active:hover::before {
              filter: brightness(.7);
              border-radius: 30%
          }

          .picker-holder input[type="color"] {
              opacity: 0;
              position: fixed
          }

          .picker-color {
              cursor: var(--pointer);
              font-size: 1.5vw;
              margin-left: 1vw
          }

          .picker-text {
              color: var(--gray) !important;
              font-size: 1vw !important;
          }

          .color-picker {
              display: flex;
              justify-content: space-between;
          }

          .settings-hr {
              margin: 1vw 0vw;
              border: .025vw solid var(--main);
          }

          .checkbox-wrapper {
              flex-direction: row;
              justify-content: space-between;
              align-items: center;
          }

          .checkbox-wrapper i {
              margin-right: 1.5vw;
              font-size: 2.3vw;
          }

          .info-holder {
              display: flex;
              flex-direction: column;
          }

          .info-holder * {
              font-size: 1vw
          }

          .dropdown-div {
              display: flex;
              justify-content: space-between
          }

          .dropdown-div i {
              margin-right: .6vw;
              font-size: 1vw !important;
              color: var(--gray) !important;
          }

          .button-plus {
              cursor: var(--pointer);
              background-color: rgb(255 255 255 / .25););
              border-radius: 50%;
              display: flex;
              flex-direction: row;
              justify-content: center;
              align-items: center;
              width: 1.5vw;
              height: 1.5vw;
          }

          .button-plus:hover {
              filter: opacity(0.7)
          }

          .button-plus:active {
              filter: opacity(1.2)
          }

          .button-plus i {
              cursor: var(--pointer);
              margin: 0px !important;
              color: white !important;
              font-size: 1.3vw;
          }

          .name-changer {
              display: flex;
              flex-direction: row;
              justify-content: space-between;
              align-items: center;
              margin-bottom: 1vw
          }

          .name-changer .text {
              font-size: 2.1vw;
              color: var(--gray) !important;
              cursor: var(--pointer);
              margin-right: 1vw
          }

          .name-changes {
              justify-content: space-between;
              display: flex;
              width: 100%;
              background: #161616;
              padding: 0.6vw 1vw;
              border-radius: 0.4vw;
              flex-direction: row;
              justify-content: center;
              text-align: center;
          }

          .name-changes i {
              margin: 0vw 1vw
          }

          .name-changes > :first-child {
              width: 45%;
          }

          .name-changes > :nth-child(2) {
              width: 10%;
          }

          .name-changes > :nth-child(3) {
              width: 45%;
          }

          .name-edit {
              text-align: center;
              outline: none;
              user-select: none;
              background-color: inherit;
              border: 0px;
              cursor: var(--text);
          }

          .edit {
              margin-bottom: 1vw;
              display: none
          }

          .edit .name-changes {
              animation: glow 1s forwards;
              box-shadow: 0 0 20px -1.1vw rgb(255 255 255 / .9)
          }

          .edit span {
              font-size: 0.8vw;
              margin-bottom: 1vw
          }

          .risk {
              margin-right: .5vw;
              color: #E74C3C
          }

          .icon-change:hover {
              animation: rotate 1s infinite
          }

          .icon-change {
              animation: rotate 1s forwards
          }

          .name-changer i:hover {
              filter: opacity(.5)
          }
      `;

//[=]=> Menu append & title
const HUD = document.createElement('div');
      HUD.id = 'ehd-menu';
      HUD.classList = 'ehd_scrollBar';
      HUD.innerHTML = `
        <div class="header">
            <img src="https://cdn.glitch.global/499d2ba6-cd57-4e5f-8b56-5557baa5b3a0/EHD%20Visuals.png" alt="EHD Mod Icon" draggable="false">

            <div class="header-holder">
                <span> EHD [Free Version] </span>
                <span class="description header-info"> Settings </span>
            </div>

            <div class="menu-size" onclick="MenuManager.minimize(this)">
                <i class="bi bi-chevron-right"></i>
            </div>
        </div>

        <div class="body"></div>

        <div class="footer">
            <div class="menu-button" role="button" onclick="window.open('https://discord.gg/aZGuQmrm8z', '_blank')"
                 onmouseover="Tooltip.show(void 0, 'Join our Discord to share your feedback and discover more mods!')"
                 onmouseout="Tooltip.hide()">
                <i class="bi bi-discord"></i>
                <span> Discord </span>
            </div>

            <label class="menu-button switch">
                <div class="separator" id="transparency">
                    <i class="bi bi-transparency"></i>
                    <span> Transparency </span>
                </div>

                <input type="checkbox" onchange="MenuManager.opacity(this)">
                <div class="checkbox"></div>
            </label>
        </div>
      `;

const TIP = document.createElement('div');
      TIP.id = 'tooltip-menu';
      TIP.style = 'opacity: 0';
      TIP.innerHTML = ` Enhanced Visuals `

const NIGHT = document.createElement('div');
      NIGHT.classList = 'night-card';
      NIGHT.style = 'opacity: 0';

const SETTINGS = document.createElement('div');
      SETTINGS.id = 'settings-menu';
      SETTINGS.innerHTML = `
          <div class="container">
              <div class="settings-header">
                  <div class="separator"> <!-- Separate the flex -->
                      <i class="bi bi-sliders2 settings-icon" style="margin-right: 1vw"></i>

                      <div class="feature-container">
                          <span> Settings </span>
                          <span class="actual-feature settings-name"> Tornado particles </span>
                      </div>
                  </div>

                  <div class="separator">
                      <i class="bi bi-arrow-90deg-left settings-button" style="font-size: 1.2vw; color: var(--gray)" onclick="MenuManager.toggleSelector()"></i>
                      <i class="bi bi-x settings-button" onclick="MenuManager.toggleSettings('', false)"></i>
                  </div>
              </div>

              <div class="settings-selector ehd_scrollBar"> </div>

              <div class="settings-body ehd_scrollBar">
                  <div class="setting settings-colored_hp">
                      Health bar color

                      <div class="separator color-picker mine_health" style="margin-top: 0.6vw">
                          <div class="separator">
                              <div class="color-ball" style="background-color: #801a1a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #bacb29" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #269a23" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #23629a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball active picker-div" onclick="MenuManager.changeColor(this)" style="background-color: #611a80"></div>
                          </div>

                          <label class="picker-holder separator">
                              <input type="color" value="#611a80" onchange="MenuManager.colorPicker(this)"/>
                              <span class="picker-text"> Color picker </span>
                              <i class="bi bi-brush-fill picker-color"></i>
                          </label>
                      </div>

                      <hr class="settings-hr">

                      Enemy bar color

                      <div class="separator color-picker enemy_health" style="margin-top: 0.6vw">
                          <div class="separator">
                              <div class="color-ball" style="background-color: #801a1a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #bacb29" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #269a23" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #23629a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball active picker-div" onclick="MenuManager.changeColor(this)" style="background-color: #ae6999"></div>
                          </div>

                          <label class="picker-holder separator">
                              <input type="color" value="#ae6999" onchange="MenuManager.colorPicker(this)"/>
                              <span class="picker-text"> Color picker </span>
                              <i class="bi bi-brush-fill picker-color"></i>
                          </label>
                      </div>
                  </div>

                  <div class="setting settings-weapon_range">
                      <div class="switch separator checkbox-wrapper">
                          <div class="separator">
                              <i class="bi bi-slash-circle-fill"></i>

                              <div class="info-holder">
                                  <span> Round Cap </span>
                                  <span class="description"> Rounds the line cap to smooth </span>
                              </div>
                          </div>

                          <label class="separator" style="width: 2.1vw">
                              <input type="checkbox" checked onchange="MenuManager.enable(this, 'cap', 'slash-circle-fill', 'slash-square-fill')">
                              <div class="checkbox"></div>
                          </label>
                      </div>

                      <hr class="settings-hr">

                      Draw color

                      <div class="separator color-picker color" style="margin-top: 0.6vw">
                          <div class="separator">
                              <div class="color-ball" style="background-color: #801a1a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #bacb29" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #269a23" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #23629a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball active picker-div" onclick="MenuManager.changeColor(this)" style="background-color: #404040"></div>
                          </div>

                          <label class="picker-holder separator">
                              <input type="color" value="#404040" onchange="MenuManager.colorPicker(this)"/>
                              <span class="picker-text"> Color picker </span>
                              <i class="bi bi-brush-fill picker-color"></i>
                          </label>
                      </div>
                  </div>

                  <div class="setting settings-hitbox">
                      Draw color

                      <div class="separator color-picker color" style="margin-top: 0.6vw">
                          <div class="separator">
                              <div class="color-ball" style="background-color: #801a1a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #bacb29" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #269a23" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball" style="background-color: #23629a" onclick="MenuManager.changeColor(this)"></div>
                              <div class="color-ball active picker-div" onclick="MenuManager.changeColor(this)" style="background-color: #50C878"></div>
                          </div>

                          <label class="picker-holder separator">
                              <input type="color" value="#50C878" onchange="MenuManager.colorPicker(this)"/>
                              <span class="picker-text"> Color picker </span>
                              <i class="bi bi-brush-fill picker-color"></i>
                          </label>
                      </div>
                  </div>

                  <div class="setting settings-footsteps">
                      <div class="switch separator checkbox-wrapper">
                          <div class="separator">
                              <i class="bi bi-meta"></i>

                              <div class="info-holder">
                                  <span> Land steps </span>
                                  <span class="description"> Draw steps when walking on land </span>
                              </div>
                          </div>

                          <label class="separator" style="width: 2.1vw">
                              <input type="checkbox" checked onchange="MenuManager.enable(this, 'land')">
                              <div class="checkbox"></div>
                          </label>
                      </div>
                  </div>

                  <div class="setting settings-name_changer">
                      <div class="dropdown-div">
                          <div class="separator">
                              <i class="bi bi-pencil-fill"></i>
                              <span> New Name Changer </span>
                          </div>

                          <div class="button-plus" onclick="MenuManager.toggleNewNC(this)">
                              <i class="bi bi-plus"></i>
                          </div>
                      </div>

                      <hr class="settings-hr">

                      <div class="name-changer-holder">
                          <div class="name-changer edit">
                              <i class="bi bi-pencil-square text icon-change"
                                 onclick="MenuManager.addNC(this)"
                                 onmouseover="MenuManager.changeIcon(this, 1, 'bookmark-plus text icon-change')"
                                 onmouseout="MenuManager.changeIcon(this, 0, 'pencil-square text icon-change')">
                              </i>

                              <div class="name-changes">
                                  <input type="text" placeholder="Wolf" class="name-edit"/>
                                  <i class="bi bi-arrows"></i>
                                  <input type="text" placeholder="Dog" class="name-edit"/>
                              </div>
                          </div>

                          <span class="edit">
                              <span class="risk">*</span>
                              <span> NOTE: The name will be replaced ONCE entity is displayed on screen </span>
                          </span>

                          <div id="name-changer-wrap"></div>
                      </div>
                  </div>

                  <div class="setting settings-undefined" style="display: none">
                      <span> No settings available for this feature. </span>
                  </div>
              </div>
          </div>
      `

document.head.appendChild(CSS);
document.body.appendChild(HUD);
document.body.appendChild(TIP);
document.body.appendChild(NIGHT);
document.body.appendChild(SETTINGS);

document.title = 'Sploop.io - EHD';

//[=]=> WebSocket overrider & functions
class PlayerManager {
    constructor() {
        this.alive = false;
        this.clan = [];
        this.age = 0;
        this.old_weapon = 0;
    }

    update() {
        const velocity = !Vars.steps.length && Player.velocity > 18;

        if (velocity) {
            const land = Settings.footsteps.land;

            const platform = Vars.entities.find(entity => entity && entity.type === 9 && Utils.distance(Player, entity) <= 65);
            const bed = Vars.entities.find(entity => entity && entity.type === 15 && Utils.distance(Player, entity) <= 65);

            const { x, y } = Player;
            const color = bed ? '#474747' : platform ? '#69482a' : y < 2485 ? '#b9b5ad' : y < 7485 ? '#51603a' : y < 8000 ? '#beb387' : y < 9000 ? '#1e6774' : '#86613d'

            if (!land && y < 7485) return;

            Vars.steps.push({ x, y, color, size: 10 });
        }
    }
}

class Packets {
    static init(ws) {
        const url = ws.url;

        ws.addEventListener('message', this.message.bind(this));

        Object.assign(this, { ws, url })
    }

    static message(event) {
        const message = event.data;
        const type = typeof message;
        const data = type === 'string' ? JSON.parse(message) : new Uint8Array(message);
        data.type = data[0];

        if (data.type === server.items_upgrade) {
            if (data.byteLength > 1) {
                Player.items = [];

                for (let index = 1; index < data.byteLength; index++) {
                    Player.items.push(data[index])
                };
            }
        }

        if (data.type === server.spawned) {
            const id = data[1],
                  items = data[4],
                  alive = true;

            Object.assign(Player, { id, items, alive });
        }

        if (data.type === server.died) Player.alive = false;

        if (data.type === server.update) {
            Vars.enemy = null;

            for (let index = 1; index < data.length; index += 19) {
                const broke = data[index + 8];

                const type = data[index + 0];
                const sid = data[index + 1];
                const id = data[index + 2] | data[index + 3] << 8;
                const x = data[index + 4] | data[index + 5] << 8;
                const y = data[index + 6] | data[index + 7] << 8;
                const dir = data[index + 9] / 255 * 6.283185307179586 - Math.PI;
                const weapon = data[index + 10];
                const hat = data[index + 11];
                const team = data[index + 12];
                const health = data[index + 13] / 255 * 100;

                if (2 & broke) {
                    Vars.entities[id] = null;
                } else {
                    const entity = Vars.entities[id] || {};
                    Object.assign(entity, { type, sid, id, x, y, weapon, hat, health, team, dir });

                    Vars.entities[id] = entity;

                    if (id === Player.id) {
                        Player.velocity = Math.hypot(y - Player.y, x - Player.x);

                        Player.update();
                        Object.assign(Player, entity);
                    }

                    const clan = (!Player.team || team != Player.team);
                    if (type === 0 && Player.id !== id && clan) {
                        const enemy = Vars.enemy;
                        const newDist = Math.hypot(Player.y - y, Player.x - x);
                        const oldDist = Vars.enemy ? Math.hypot(Player.y - enemy.y, Player.x - enemy.x) : null;

                        if (enemy) {
                            if (newDist < oldDist) {
                                Vars.enemy = entity;
                            }
                        } else {
                            Vars.enemy = entity;
                        }
                    }
                }
            }
        }
    }
}

WebSocket.prototype.send_ = WebSocket.prototype.send;

WebSocket.prototype.send = function(data) {
    const url = Packets.ws?.url !== this.url;
    if (!Packets.ws || url) {
        Packets.init(this);
    }

    this.send_(data);
};

//[=]=> Canvas drawing functions
const particlesArray = []
class Functions {
    static footsteps(canvas, args) {
        Vars.steps.forEach((step, index) => {
            const { x, y, size, color } = step;

            canvas.save()
            canvas.beginPath()

            canvas.globalAlpha = Math.max(0, 1 - step.size / 30)
            canvas.fillStyle = color
            canvas.arc(x, y, size, 0, Math.PI * 2)

            canvas.fill()
            canvas.restore()

            step.size *= 1.05

            if (step.size > 100) {
                Vars.steps.splice(index, 1);
            }
        })
    }

    static heal_effect(canvas, args) {
        const [ x, y, hp ] = args;

        Vars.heals.forEach((healed, index) => {
            const { plus, type, dir, rot, x, y } = healed;
            const speed = .01;

            healed.alpha -= speed * 2;
            healed.plus += speed * rot;

            canvas.save();
            canvas.translate(x, y);
            canvas.rotate(dir + plus);

            canvas.globalAlpha = healed.alpha;
            canvas.drawImage(type, 0, 0, 80, 80);

            canvas.restore();

            if (healed.alpha < .06) {
                Vars.heals.splice(index, 1);
            }
        })
    }

    static health_bar(canvas) {
        const colors = Settings.colored_hp;
        const color = canvas.fillStyle === '#a4cc4f' ? colors.mine_health : colors.enemy_health;

        canvas.fillStyle = color
    }

    static display_hp(canvas, args) {
        const [ x, y, hp ] = args
        const health = Math.round(hp + 5)

        const content = `${health}%`
        const { width } = canvas.measureText(content)
        const text = [content, x + 30 - (health > 99 ? 2 : 0), y + 30]

        canvas.font = '20px Baloo Paaji'
        canvas.fillStyle = 'white'
        canvas.strokeStyle = '#404040';

        canvas.lineWidth = 6.5

        canvas.strokeText(...text)
        canvas.fillText(...text)
    }

    static weaponRange(canvas, range) {
        const width = Math.min(4, canvas.lineWidth);

        canvas.save()
        canvas.beginPath()
        canvas.strokeStyle = Settings.weapon_range.color || '#404040'
        canvas.globalAlpha = .5

        canvas.lineCap = Settings.weapon_range.cap ? 'round' : 'square';

        canvas.rotate(-Math.PI / 2) // left

        canvas.arc(0, 0, range - width, 0, Math.PI)

        canvas.stroke()
        canvas.restore()
    }

    static hitbox(canvas, radius, object, x = 0, y = 0, width = 0, height = 0) {
        canvas.save()
        canvas.beginPath()
        canvas.strokeStyle = Settings.hitbox.color || '#50C878';
        canvas.globalAlpha = object === 'trap' ? 1 : .6

        canvas.arc(x + width / 2, y + height / 2, radius, 0, Math.PI * 2)

        canvas.stroke()
        canvas.restore()
    }

    static particles(canvas) {
        const particleCount = 20
        const arcRadius = 5

        if (particlesArray.length === 0) {
            for (let i = 0; i < particleCount; i++) {
                const x = Math.random() * 440
                const y = Math.random() * 440

                particlesArray.push({
                    x: -220 + x,
                    y: -220 + y,
                    alpha: 1,
                    lifespan: Math.random() * 100 + 50
                })
            }
        }

        for (let i = particlesArray.length - 1; i >= 0; i--) {
            const particle = particlesArray[i]

            particle.alpha -= 1 / particle.lifespan
            if (particle.alpha <= 0) {
                particle.x = -220 + Math.random() * 400
                particle.y = -220 + Math.random() * 400
                particle.alpha = 1
                particle.lifespan = Math.random() * 100 + 50
            }

            // Draw particle
            canvas.beginPath()
            canvas.arc(particle.x, particle.y, arcRadius, 0, Math.PI * 2, false)
            canvas.fillStyle = `rgba(154, 113, 53, ${particle.alpha})`
            canvas.fill()
            canvas.closePath()
        }
    }
}

// [=]=> Ctx override
function getWeaponRange(src) {
    let range = 0

    weapons.forEach(weapon => {
        if (src.search(weapon) > 0) {
            const index = weapons.indexOf(weapon)

            range = ranges[index]
        }
    })

    return range;
}

const weapons = [ 'hammer', 'sword', 'spear', 'axe', 'shield', 'stick', 'katana', 'naginata', 'bat', 'chillrend', 'dagger', 'staff', 'secret', 'scythe' ];
const ranges = [ 80, 135, 160, 90, 55, 100, 140, 165, 115, 140, 80, 140, 115, 160 ]
const item_radius = {
    trap: 40,
    spike: 45,
    hard_spike: 45,
    big_spike: 42,
    boost: 40,
    wall: 45
}

const drawImage = CanvasRenderingContext2D.prototype.drawImage;
CanvasRenderingContext2D.prototype.drawImage = function (image, x, y, width, height) {
    const canvas = this;
    const check = image.src && image.src.search('inv') < 0;

    const isWeapon = check && weapons.some(item => image.src.search(item) > 0);

    if (isWeapon && Features.weapon_range) {
        const range = getWeaponRange(image.src);

        Functions.weaponRange(canvas, range);
    }

    if (!isWeapon && check && Features.hitbox) {
        const object = image.src.split('/')[5].split('.')[0]
        const radius = item_radius[object]

        const holding = image.src.includes('item');
        const args = holding ? [x, y, width, height] : [];

        if (radius) Functions.hitbox(canvas, radius, object, ...args);
    }

    if (!isWeapon && check && image.src.search('tornado') > 0 && Features.tornado_particles) {
        Functions.particles(canvas)
    }

    return drawImage.apply(this, arguments)
};

const strokeText = CanvasRenderingContext2D.prototype.strokeText;
CanvasRenderingContext2D.prototype.strokeText = function (text, x, y, maxWidth) { // name changer
    const name = Settings.name_changers[text]

    if (Features.name_changer && name) {
        arguments[0] = name;
    }

    return strokeText.apply(this, arguments)
}

const fillText = CanvasRenderingContext2D.prototype.fillText;
CanvasRenderingContext2D.prototype.fillText = function (text, x, y, maxWidth) {
    const canvas = this;

    // Healing effect!
    if (canvas.fillStyle === '#8ecc51' && Features.healing_effect) {
        const type = Player?.items?.includes(12) ? Vars.images.cookie : Vars.images.apple;
        const { x, y } = Player;

        const rot = Vars.rot || -1;
        Vars.rot ? delete Vars.rot : (Vars.rot = 1);

        const dir = Mouse.angle + (rot === -1 ? -.9 : 0);

        Vars.heals.push({ type, dir, rot, x, y, plus: 0, alpha: 1 });
    }

    // Name changer
    const name = Settings.name_changers[text]

    if (Features.name_changer && name) {
        arguments[0] = name;
    }

    return fillText.apply(this, arguments)
};

const fillRect = CanvasRenderingContext2D.prototype.fillRect;
CanvasRenderingContext2D.prototype.fillRect = function (x, y, width, height) {
    const canvas = this;
    const isBar = ['#a4cc4f', '#cc5151'].includes(canvas.fillStyle);

    if (canvas.fillStyle === '#a4cc4f') {
        // Makes hp bar smoother
        if (Features.smooth_hp) {
            const old = Vars.health || width;
            const smooth = Utils.lerp(old, width, .1)

            width = smooth

            Vars.health = smooth
        }

        // Heal effect disp ck
        Features.healing_effect && Functions.heal_effect(canvas, arguments);

        // Footsteps disp
        Features.footsteps && Functions.footsteps(canvas, arguments);
    }

    if (isBar) {
        // Change bar colors
        Features.colored_hp && Functions.health_bar(canvas);
        fillRect.apply(canvas, arguments);

        // Then display HP
        Features.display_hp && Functions.display_hp(canvas, arguments);
        return;
    }

    return fillRect.apply(this, arguments)
};

//[=]=> Apply window values
window.Tooltip = Tooltip;
window.MenuManager = MenuManager;
window.Settings = Settings;

const Player = new PlayerManager();
const Mouse = new MouseManager();

window.addEventListener('beforeunload', function () {
    Utils.ls_set('ehd_features', Features);
    Utils.ls_set('ehd_settings', Settings);
});

window.addEventListener('click', function (event) {
    const { target } = event;

    if (target.id === 'settings-menu') MenuManager.toggleSettings('', false);
});

//[=]=> Event listeners, dom load, etc
(function load() {
    if (Vars.loaded) return;
    Vars.loaded = true;

    Mouse.listeners();
    MenuManager.appendReplacer();

    // Appends each button to the menu
    let string = '';

    for (let featureID in Features) {
        const Feature = Features[featureID];
        const { name, icon, info } = All_features[featureID] || {};

        name && (string += `
            <div class="menu-button ${ Feature ? 'active' : '' }" role="button"
                 onmouseover="MenuManager.ToggleToolTip(this, 1)"
                 onmouseout="MenuManager.ToggleToolTip(this, 0)"
                 onmousedown="MenuManager.ToggleFeature(this, 1)"
                 onmouseup="MenuManager.ToggleFeature(this, 0)">
                <i class="bi bi-${icon}"></i>
                <span>${name}</span>
            </div>
        `);
    }

    document.querySelector('.body').innerHTML = string;

    // Appends features but to the setting selector
    string = '';

    for (let featureID in Features) {
        const Feature = Features[featureID];
        const { name, icon } = All_features[featureID] || {};

        name && (string += `
            <div class="settings-item setting-div-${featureID} ${Feature ? 'active' : ''}"
                 onmouseover="MenuManager.ToggleToolTip(this, 1)"
                 onmouseout="MenuManager.ToggleToolTip(this, 0)"
                 onclick="MenuManager.toggleSettings(this, true)">
                <i class="bi bi-${icon}"></i>
                <span style="display: none">${name}</span>
            </div>
        `);
    }

    document.querySelector('.settings-selector').innerHTML = string;

    function update() {
        // Hide ads, sry
        const rightAd = document.querySelector('#game-right-content-main');
        const leftAd = document.querySelector('#game-left-content-main');
        const downAd = document.querySelector('#game-bottom-content');

        const display = Features.hide_ads ? 'none' : 'block';

        rightAd.style.display = display;
        leftAd.style.display = display;
        downAd.style.display = display;

        // Night mode !
        const condition = Features.night_mode && Player.alive;
        const night = document.querySelector('.night-card');

        night.style.opacity = condition ? '1' : '0';

        setTimeout(() => {
            requestAnimationFrame(update);
        }, 1e2);
    }

    requestAnimationFrame(update);
})();

//yb!
//sry for unsemantic html!