Cube Engine Uptaded New Options

The ultimate enhancement for your Drawaria.online experience. Redefining possibilities!

当前为 2025-07-05 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Cube Engine Uptaded New Options
// @version      7.0.0
// @description  The ultimate enhancement for your Drawaria.online experience. Redefining possibilities!
// @namespace    drawaria.modded.fullspec
// @homepage     https://drawaria.online/profile/?uid=63196790-c7da-11ec-8266-c399f90709b7
// @author       ≺ᴄᴜʙᴇ³≻ And YouTubeDrawaria
// @match        https://drawaria.online/
// @match        https://drawaria.online/test
// @match        https://drawaria.online/room/*
// @icon         https://drawaria.online/avatar/cache/e53693c0-18b1-11ec-b633-b7649fa52d3f.jpg
// @grant        none
// @license      GNU GPLv3
// @run-at       document-end
// ==/UserScript==

(function () {
  (function CodeMaid(callback) {
    class TypeChecker {
      constructor() {}
      isArray(value) {
        return this.isA("Array", value);
      }
      isObject(value) {
        return !this.isUndefined(value) && value !== null && this.isA("Object", value);
      }
      isString(value) {
        return this.isA("String", value);
      }
      isNumber(value) {
        return this.isA("Number", value);
      }
      isFunction(value) {
        return this.isA("Function", value);
      }
      isAsyncFunction(value) {
        return this.isA("AsyncFunction", value);
      }
      isGeneratorFunction(value) {
        return this.isA("GeneratorFunction", value);
      }
      isTypedArray(value) {
        return (
          this.isA("Float32Array", value) ||
          this.isA("Float64Array", value) ||
          this.isA("Int16Array", value) ||
          this.isA("Int32Array", value) ||
          this.isA("Int8Array", value) ||
          this.isA("Uint16Array", value) ||
          this.isA("Uint32Array", value) ||
          this.isA("Uint8Array", value) ||
          this.isA("Uint8ClampedArray", value)
        );
      }
      isA(typeName, value) {
        return this.getType(value) === "[object " + typeName + "]";
      }
      isError(value) {
        if (!value) {
          return false;
        }

        if (value instanceof Error) {
          return true;
        }

        return typeof value.stack === "string" && typeof value.message === "string";
      }
      isUndefined(obj) {
        return obj === void 0;
      }
      getType(value) {
        return Object.prototype.toString.apply(value);
      }
    }

    class DOMCreate {
      #validate;
      constructor() {
        this.#validate = new TypeChecker();
      }
      exportNodeTree(node = document.createElement("div")) {
        let referenceTolocalThis = this;

        let json = {
          nodeName: node.nodeName,
          attributes: {},
          children: [],
        };

        Array.from(node.attributes).forEach(function (attribute) {
          json.attributes[attribute.name] = attribute.value;
        });

        if (node.children.length <= 0) {
          json.children.push(node.textContent.replaceAll("\t", ""));
          return json;
        }

        Array.from(node.children).forEach(function (childNode) {
          json.children.push(referenceTolocalThis.exportNodeTree(childNode));
        });

        return json;
      }

      importNodeTree(json = { nodeName: "", attributes: {}, children: [] }) {
        let referenceTolocalThis = this;

        if (referenceTolocalThis.#validate.isString(json)) {
          return this.TextNode(json);
        }

        let node = this.Tree(json.nodeName, json.attributes);

        json.children.forEach(function (child) {
          node.appendChild(referenceTolocalThis.importNodeTree(child));
        });

        return node;
      }

      Element() {
        return document.createElement.apply(document, arguments);
      }
      TextNode() {
        return document.createTextNode.apply(document, arguments);
      }
      Tree(type, attrs, childrenArrayOrVarArgs) {
        const el = this.Element(type);
        let children;
        if (this.#validate.isArray(childrenArrayOrVarArgs)) {
          children = childrenArrayOrVarArgs;
        } else {
          children = [];

          for (let i = 2; i < arguments.length; i++) {
            children.push(arguments[i]);
          }
        }

        for (let i = 0; i < children.length; i++) {
          const child = children[i];

          if (typeof child === "string") {
            el.appendChild(this.TextNode(child));
          } else {
            if (child) {
              el.appendChild(child);
            }
          }
        }
        for (const attr in attrs) {
          if (attr == "className") {
            el[attr] = attrs[attr];
          } else {
            el.setAttribute(attr, attrs[attr]);
          }
        }

        el.appendAll = function (...nodes) {
          nodes.forEach((node) => {
            el.appendChild(node);
          });
        };

        return el;
      }
    }

    class CookieManager {
      constructor() {}
      set(name, value = "") {
        document.cookie =
          name + "=" + value + "; expires=" + new Date("01/01/2024").toUTCString().replace("GMT", "UTC") + "; path=/";
      }
      get(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(";");
        for (var i = 0; i < ca.length; i++) {
          var c = ca[i];
          while (c.charAt(0) == " ") c = c.substring(1, c.length);
          if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
        }
        return null;
      }
      clear(name) {
        document.cookie = name + "=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;";
      }
    }

    class DocumentCleaner {
      document;
      constructor() {
        this.document = new DOMCreate();
      }
      scripts(remove = true) {
        try {
          let array = document.querySelectorAll('script[src]:not([data-codemaid="ignore"])');
          array.forEach((script) => {
            if (script.src != "") document.head.appendChild(script);
          });
        } catch (error) {
          console.error(error);
        }

        try {
          let unifiedScript = this.document.Tree("script");

          let scripts = document.querySelectorAll('script:not([src]):not([data-codemaid="ignore"])');
          let unifiedScriptContent = "";
          scripts.forEach((script) => {
            let content = script.textContent; //.replaceAll(/\s/g, '');

            unifiedScriptContent += `try{${content}}catch(e){console.warn(e);}`;
            script.remove();
          });

          unifiedScript.textContent = unifiedScriptContent;

          if (!remove) document.head.appendChild(unifiedScript);
        } catch (error) {
          console.error(error);
        }
      }
      styles(remove = false) {
        try {
          let unifiedStyles = this.document.Tree("style");
          unifiedStyles.textContet = "";

          let styles = document.querySelectorAll('style:not([data-codemaid="ignore"])');
          styles.forEach((style) => {
            unifiedStyles.textContent += style.textContent;
            style.remove();
          });
          if (!remove) document.head.appendChild(unifiedStyles);
        } catch (error) {
          console.error(error);
        }
      }
      embeds() {
        try {
          let array = document.querySelectorAll("iframe");
          array.forEach((iframe) => {
            iframe.remove();
          });
        } catch (error) {
          console.error(error);
        }
      }
    }

    class CustomGenerator {
      constructor() {}
      uuidv4() {
        return crypto.randomUUID();
      }
    }

    globalThis.typecheck = new TypeChecker();
    globalThis.cookies = new CookieManager();
    globalThis.domMake = new DOMCreate();
    globalThis.domClear = new DocumentCleaner();
    globalThis.generate = new CustomGenerator();

    if (window.location.pathname === "/") window.location.assign("/test");
  })();

  (function CubicEngine() {
    domMake.Button = function (content) {
      let btn = domMake.Tree("button", { class: "btn btn-outline-secondary" });
      btn.innerHTML = content;
      return btn;
    };
    domMake.Row = function () {
      return domMake.Tree("div", { class: "_row" });
    };
    domMake.IconList = function () {
      return domMake.Tree("div", { class: "icon-list" });
    };

    const sockets = [];
    const originalSend = WebSocket.prototype.send;
    WebSocket.prototype.send = function (...args) {
      let socket = this;
      if (sockets.indexOf(socket) === -1) {
        sockets.push(socket);
      }
      socket.addEventListener("close", function () {
        const pos = sockets.indexOf(socket);
        if (~pos) sockets.splice(pos, 1);
      });
      return originalSend.call(socket, ...args);
    };

    const identifier = "🧊";

    class Stylizer {
      constructor() {
        this.element = domMake.Tree("style", { "data-codemaid": "ignore" }, []);
        document.head.appendChild(this.element);
        this.initialize();
      }

      initialize() {
        this.addRules([
          `body * {margin: 0; padding: 0; box-sizing: border-box; line-height: normal;}`,
          `#${identifier} {--CE-bg_color: var(--light); --CE-color: var(--dark); line-height: 2rem; font-size: 1rem;}`,
          `#${identifier}>details {position:relative; overflow:visible; z-index: 999; background-color: var(--CE-bg_color); border: var(--CE-color) 1px solid; border-radius: .25rem;}`,
          `#${identifier} details>summary::marker {content:"📘";}`,
          `#${identifier} details[open]>summary::marker {content:"📖";}`,
          `#${identifier} details details {margin: 1px 0; border-top: var(--CE-color) 1px solid;}`,
          `#${identifier} input.toggle[name][hidden]:not(:checked) + * {display: none !important;}`,
          `#${identifier} header>.icon {margin: 1px;}`,
          `#${identifier} header>.icon.active {color: var(--success);}`,
          `#${identifier} header>.icon:not(.active) {color:var(--danger); opacity:.6;}`,
          `#${identifier} header:not(:has([title='Unselect'] + *)) > [title='Unselect'] {display:none;}`,
          `#${identifier} .btn {padding: 0;}`,
          `#${identifier} .icon-list {display: flex; flex-flow: wrap;}`,
          `#${identifier} .nowrap {overflow-x: scroll; padding-bottom: 12px; flex-flow: nowrap;}`,
          `#${identifier} .icon {display: flex; flex: 0 0 auto; max-width: 1.6rem; min-width: 1.6rem; height: 1.6rem; border-radius: .25rem; border: 1px solid var(--CE-color); aspect-ratio: 1/1;}`,
          `#${identifier} .icon > * {margin: auto; text-align: center; max-height: 100%; max-width: 100%;}`,
          `#${identifier} .itext {text-align: center; -webkit-appearance: none; -moz-appearance: textfield;}`,
          `#${identifier} ._row {display: flex; width: 100%;}`,
          `#${identifier} ._row > * {width: 100%;}`,
          `hr {margin: 5px 0;}`,
          `.playerlist-row::after {content: attr(data-playerid); position: relative; float: right; top: -20px;}`,
          `[hidden] {display: none !important;}`,
          `.noselect {-webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; user-select: none;}`,
        ]);
      }

      addRules(rules = []) {
        let reference = this;
        rules.forEach(function (rule) {
          reference.addRule(rule);
        });
      }
      addRule(rule) {
        let TextNode = domMake.TextNode(rule);
        this.element.appendChild(TextNode);
      }
    }

    class ModBase {
      static globalListOfExtensions = [];
      static localListOfExtensions = [];
      static Styles = new Stylizer();

      static register = function (extension) {
        extension.localListOfExtensions = [];
        ModBase.globalListOfExtensions.push(extension);
        return ModBase;
      };
      static bind = function (extension, target) {
        let parent;
        if (typecheck.isFunction(target)) parent = target;
        else if (typecheck.isString(target))
          parent = ModBase.globalListOfExtensions.find((entry) => entry.name === target);
        else if (typecheck.isObject(target)) parent = target.constructor;
        else {
          console.log(typecheck.getType(target));
        }
        if (!parent) return new Error(`${parent}`);

        parent.localListOfExtensions.push(extension);
        parent.autostart = true;

        return parent;
      };
      static findGlobal = function (extensionName) {
        return ModBase.globalListOfExtensions.find((entry) => entry.name === extensionName);
      };

      #id;
      #name;
      #icon;

      htmlElements;
      children;
      parent;

      constructor(name, icon) {
        this.#id = generate.uuidv4();
        this.#name = this.constructor.name;
        this.#icon = "📦";
        this.children = [];
        this.htmlElements = {};

        this.#onStartup();

        this.setName(name || this.#name);
        this.setIcon(icon || this.#icon);
      }

      #onStartup() {
        this.#loadInterface();

        if (this.constructor.autostart)
          this.constructor.localListOfExtensions.forEach((extension) => {
            this.loadExtension(extension);
          });
      }

      #loadInterface() {
        this.htmlElements.details = domMake.Tree("details", {
          class: "noselect",
          open: false, // Changed from true to false to make it closed by default
          "data-reference": this.constructor.name,
        });
        this.htmlElements.summary = domMake.Tree("summary");
        this.htmlElements.header = domMake.Tree("header", { class: "icon-list" });
        this.htmlElements.section = domMake.Tree("section");
        this.htmlElements.children = domMake.Tree("section");

        this.htmlElements.details.appendChild(this.htmlElements.summary);
        this.htmlElements.details.appendChild(this.htmlElements.header);
        this.htmlElements.details.appendChild(this.htmlElements.section);
        this.htmlElements.details.appendChild(this.htmlElements.children);

        this.htmlElements.input = domMake.Tree(
          "input",
          { type: "radio", id: this.#id, name: "QBit", class: "toggle", hidden: true, title: this.#name },
          [this.#name]
        );
        this.htmlElements.label = domMake.Tree("label", { for: this.#id, class: "icon" });

        {
          const input = this.htmlElements.input;
          const label = this.htmlElements.label;

          input.addEventListener("change", (event) => {
            this.parent?.children.forEach((child) => {
              child.htmlElements.label.classList.remove("active");
            });

            label.classList[input.checked ? "add" : "remove"]("active");
          });

          label.classList[input.checked ? "add" : "remove"]("active");
        }
        {
          const resetImageSelectionLabel = domMake.Tree("div", { class: "icon", title: "Unselect" }, [
            domMake.Tree("i", { class: "fas fa-chevron-left" }),
          ]);
          resetImageSelectionLabel.addEventListener("click", () => {
            this.children.forEach((child) => {
              child.htmlElements.label.classList.remove("active");
              child.htmlElements.input.checked = !1;
            });
          });
          this.htmlElements.header.appendChild(resetImageSelectionLabel);
        }
      }

      loadExtension(extension, referenceHandler) {
        let activeExtension = new extension();
        activeExtension.parent = this;

        activeExtension.htmlElements.input.name = this.getName();

        if (referenceHandler) referenceHandler(activeExtension);
        else this.children.push(activeExtension);

        if (!extension.siblings) extension.siblings = [];
        extension.siblings.push(activeExtension);

        if (extension.isFavorite) {
          activeExtension.htmlElements.input.click();
          if (activeExtension.enable) activeExtension.enable();
        }

        this.htmlElements.header.appendChild(activeExtension.htmlElements.label);
        this.htmlElements.children.appendChild(activeExtension.htmlElements.input);
        this.htmlElements.children.appendChild(activeExtension.htmlElements.details);

        return activeExtension;
      }

      notify(level, message) {
        if (typeof message != "string") {
          try {
            message = JSON.stringify(message);
          } catch (error) {
            throw error;
          }
        }

        let color = "";
        if ([5, "error"].includes(level)) {
          color = "#dc3545";
        } else if ([4, "warning"].includes(level)) {
          color = "#ffc107";
        } else if ([3, "info"].includes(level)) {
          color = "#17a2b8";
        } else if ([2, "success"].includes(level)) {
          color = "#28a745";
        } else if ([1, "log"].includes(level)) {
          color = "#6c757d";
        } else if ([0, "debug"].includes(level)) {
          color = "purple";
        }

        console.log(`%c${this.#name}: ${message}`, `color: ${color}`);
        let chatmessage = domMake.Tree(
          "div",
          { class: `chatmessage systemchatmessage5`, "data-ts": Date.now(), style: `color: ${color}` },
          [`${this.#name}: ${message}`]
        );

        let loggingContainer = document.getElementById("chatbox_messages");
        if (!loggingContainer) loggingContainer = document.body;
        loggingContainer.appendChild(chatmessage);
      }

      findGlobal(extensionName) {
        return this.referenceToBase.findGlobal(extensionName);
      }

      findLocal(extensionName) {
        return this.children.filter((child) => child.constructor.name === extensionName);
      }

      setName(name) {
        if (!name) return;

        this.#name = name;
        this.htmlElements.label.title = name;

        this.htmlElements.summary.childNodes.forEach((child) => child.remove());

        if (typecheck.isString(name)) {
          if (name.startsWith("<")) return (this.htmlElements.summary.innerHTML = name);
          name = domMake.TextNode(name);
        }

        this.htmlElements.summary.appendChild(name);
      }

      getName() {
        return this.#name;
      }

      setIcon(icon) {
        if (!icon) return;

        this.#icon = icon;

        this.htmlElements.label.childNodes.forEach((child) => child.remove());

        if (typecheck.isString(icon)) {
          if (icon.startsWith("<")) return (this.htmlElements.label.innerHTML = icon);
          icon = domMake.TextNode(icon);
        }

        this.htmlElements.label.appendChild(icon);
      }

      getIcon() {
        return this.#icon;
      }

      get referenceToBase() {
        return this.constructor.dummy1;
      }
      get referenceToMaster() {
        return this.constructor.dummy2;
      }

      _EXP_destroy(youSure = false) {
        if (!youSure) return;

        this.children.forEach((child) => {
          child._EXP_destroy(youSure);
          delete [child];
        });
        this.children = null;

        let pos = this.parent.children.indexOf(this);
        if (~pos) {
          this.parent.children.splice(pos, 1);
        }

        this.htmlElements.children.remove();
        this.htmlElements.section.remove();
        this.htmlElements.header.remove();
        this.htmlElements.summary.remove();
        this.htmlElements.details.remove();
        this.htmlElements.input.remove();
        this.htmlElements.label.remove();

        this.htmlElements = null;

        let pos2 = this.constructor.siblings.indexOf(this);
        if (~pos2) {
          this.constructor.siblings.splice(pos2, 1);
        }
      }
    }

    class CubeEngine extends ModBase {
      static dummy1 = ModBase.register(this);

      constructor() {
        super("CubeEngine");
      }
    }

    class Await {
      static dummy1 = ModBase.register(this);

      #interval;
      #handler;
      #callback;
      constructor(callback, interval) {
        this.#interval = interval;
        this.#callback = callback;
      }

      call() {
        const localThis = this;
        clearTimeout(this.#handler);

        this.#handler = setTimeout(function () {
          localThis.#callback();
        }, this.#interval);
      }
    }

    globalThis[arguments[0]] = ModBase;

    return function (when = "load") {
      setTimeout(() => {
        const ModMenu = new CubeEngine();
        ModMenu.htmlElements.details.open = false; // This line is now redundant as it's set in ModBase
        const target = document.getElementById("accountbox");
        const container = domMake.Tree("div", { id: identifier, style: "height: 1.6rem; flex: 0 0 auto;" });
        container.appendChild(ModMenu.htmlElements.details);
        target.after(container);
        target.after(domMake.Tree("hr"));

        globalThis["CubeEngine"] = ModMenu;
        globalThis["sockets"] = sockets;

        domClear.embeds();
        domClear.scripts();
        domClear.styles();
        console.clear();
      }, 200);
    };
  })("QBit")();

  (function BotClient() {
    const QBit = globalThis[arguments[0]];

    function parseServerUrl(any) {
      var prefix = String(any).length == 1 ? `sv${any}.` : "";
      return `wss://${prefix}drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`;
    }

    function parseRoomId(any) {
      return String(any).match(/([a-f0-9.-]+?)$/gi)[0];
    }

    function parseSocketIOEvent(prefix_length, event_data) {
      try {
        return JSON.parse(event_data.slice(prefix_length));
      } catch (error) {}
    }

    function parseAvatarURL(arr = []) {
      return `https://drawaria.online/avatar/cache/${arr.length > 0 ? arr.join(".") : "default"}.jpg`;
    }

    // class BotClient extends QBit {
    class BotClient {
      static dummy1 = QBit.register(this);

      // constructor(name = '', avatar = []) {
      constructor(name = "JavaScript", avatar = ["cf19b8f0-cf31-11ed-9ece-d584b24f60dc", "1680377222354"]) {
        // super(name, `<img src="${parseAvatarURL(avatar)}">`);

        this.name = name;
        this.avatar = avatar;
        this.attributes = { spawned: false, rounded: false, status: false };

        this.url = "";
        this.socket = null;
        this.interval_id = 0;
        this.interval_ms = 25000;

        this.room = {
          id: null,
          config: null,
          type: 2,
          players: [],
        };

        this.customObservers = [
          {
            event: "mc_roomplayerschange",
            callback: (data) => {
              this.room.players = data[2];
            },
          },
        ];
      }

      getReadyState() {
        const localThis = this;
        if (!localThis.socket) return false;
        return localThis.socket.readyState == localThis.socket.OPEN;
      }

      connect(url) {
        const localThis = this;
        // if (localThis.getReadyState()) localThis.disconnect();
        if (localThis.getReadyState()) return;

        if (!url) return localThis.enterRoom(document.querySelector("#invurl").value);
        localThis.socket = new WebSocket(parseServerUrl(url));

        localThis.socket.addEventListener("open", function (event) {
          localThis.interval_id = setInterval(function () {
            if (!localThis.getReadyState()) return clearInterval(localThis.interval_id);
            localThis.send(2);
          }, localThis.interval_ms);
        });

        localThis.socket.addEventListener("message", function (message_event) {
          var prefix = String(message_event.data).match(/(^\d+)/gi)[0] || "";
          if (prefix == "40") {
            localThis.send(emits.startplay(localThis.room, localThis.name, localThis.avatar));
          }

          var data = parseSocketIOEvent(prefix.length, message_event.data) || [];
          if (data && data.length == 1) {
            if (data[0].players) localThis.room.players = data[0].players;
          }
          if (data && data.length > 1) {
            var event = data.shift();

            localThis.customObservers.forEach((listener) => {
              if (listener.event === event) if (listener.callback) listener.callback(data);
            });
          }
        });
      }

      disconnect() {
        if (!this.getReadyState()) return;
        this.socket.close();
      }

      reconnect() {
        this.send(41);
        this.send(40);
      }

      enterRoom(roomid) {
        this.room.id = parseRoomId(roomid);
        if (!this.getReadyState()) this.connect(this.room.id.includes(".") ? this.room.id.slice(-1) : "");
        this.reconnect();
      }

      leaveRoom() {
        this.send(41);
      }

      switchRoom() {
        this.emit("pgswtichroom");
        // this.send(emits['pgswtichroom']());
      }

      addEventListener(eventname, callback) {
        this.customObservers.push({ event: eventname, callback });
      }

      send(data) {
        if (!this.getReadyState()) return /*console.warn(data)*/;
        this.socket.send(data);
      }

      emit(event, ...data) {
        // data = data.length > 0 ? data : null;
        var emitter = emits[event];
        if (emitter) this.send(emitter(...data));
      }
    }

    const emits = {
      chatmsg: function (message) {
        // 42["chatmsg","a"]
        let data = ["chatmsg", message];
        return `${42}${JSON.stringify(data)}`;
      },
      passturn: function () {
        // 42["passturn"]
        let data = ["passturn"];
        return `${42}${JSON.stringify(data)}`;
      },
      pgdrawvote: function (playerid) {
        // 42["pgdrawvote",2,0]
        let data = ["pgdrawvote", playerid, 0];
        return `${42}${JSON.stringify(data)}`;
      },
      pgswtichroom: function () {
        // 42["pgswtichroom"]
        let data = ["pgswtichroom"];
        return `${42}${JSON.stringify(data)}`;
      },
      playerafk: function () {
        // 42["playerafk"]
        let data = ["playerafk"];
        return `${42}${JSON.stringify(data)}`;
      },
      playerrated: function () {
        // 42["playerrated"]
        let data = ["playerrated"];
        return `${42}${JSON.stringify(data)}`;
      },
      sendgesture: function (gestureid) {
        // 42["sendgesture",16]
        let data = ["sendgesture", gestureid];
        return `${42}${JSON.stringify(data)}`;
      },
      sendvote: function () {
        // 42["sendvote"]
        let data = ["sendvote"];
        return `${42}${JSON.stringify(data)}`;
      },
      sendvotekick: function (playerid) {
        // 42["sendvotekick",93]
        let data = ["sendvotekick", playerid];
        return `${42}${JSON.stringify(data)}`;
      },
      wordselected: function (wordid) {
        // 42["wordselected",0]
        let data = ["sendvotekick", wordid];
        return `${42}${JSON.stringify(data)}`;
      },
      activateitem: function (itemid, isactive) {
        let data = ["clientcmd", 12, [itemid, isactive]];
        return `${42}${JSON.stringify(data)}`;
      },
      buyitem: function (itemid) {
        let data = ["clientcmd", 11, [itemid]];
        return `${42}${JSON.stringify(data)}`;
      },
      canvasobj_changeattr: function (itemid, target, value) {
        // target = zindex || shared
        let data = ["clientcmd", 234, [itemid, target, value]];
        return `${42}${JSON.stringify(data)}`;
      },
      canvasobj_getobjects: function () {
        let data = ["clientcmd", 233];
        return `${42}${JSON.stringify(data)}`;
      },
      canvasobj_remove: function (itemid) {
        let data = ["clientcmd", 232, [itemid]];
        return `${42}${JSON.stringify(data)}`;
      },
      canvasobj_setposition: function (itemid, positionX, positionY, speed) {
        let data = ["clientcmd", 230, [itemid, 100 / positionX, 100 / positionY, { movespeed: speed }]];
        return `${42}${JSON.stringify(data)}`;
      },
      canvasobj_setrotation: function (itemid, rotation) {
        let data = ["clientcmd", 231, [itemid, rotation]];
        return `${42}${JSON.stringify(data)}`;
      },
      customvoting_setvote: function (value) {
        let data = ["clientcmd", 301, [value]];
        return `${42}${JSON.stringify(data)}`;
      },
      getfpid: function (value) {
        let data = ["clientcmd", 901, [value]];
        return `${42}${JSON.stringify(data)}`;
      },
      getinventory: function () {
        let data = ["clientcmd", 10, [true]];
        return `${42}${JSON.stringify(data)}`;
      },
      getspawnsstate: function () {
        let data = ["clientcmd", 102];
        return `${42}${JSON.stringify(data)}`;
      },
      moveavatar: function (positionX, positionY) {
        let data = [
          "clientcmd",
          103,
          [1e4 * Math.floor((positionX / 100) * 1e4) + Math.floor((positionY / 100) * 1e4), false],
        ];
        return `${42}${JSON.stringify(data)}`;
      },
      setavatarprop: function () {
        let data = ["clientcmd", 115];
        return `${42}${JSON.stringify(data)}`;
      },
      setstatusflag: function (flagid, isactive) {
        let data = ["clientcmd", 3, [flagid, isactive]];
        return `${42}${JSON.stringify(data)}`;
      },
      settoken: function (playerid, tokenid) {
        let data = ["clientcmd", 2, [playerid, tokenid]];
        return `${42}${JSON.stringify(data)}`;
      },
      snapchatmessage: function (playerid, value) {
        let data = ["clientcmd", 330, [playerid, value]];
        return `${42}${JSON.stringify(data)}`;
      },
      spawnavatar: function () {
        let data = ["clientcmd", 101];
        return `${42}${JSON.stringify(data)}`;
      },
      startrollbackvoting: function () {
        let data = ["clientcmd", 320];
        return `${42}${JSON.stringify(data)}`;
      },
      trackforwardvoting: function () {
        let data = ["clientcmd", 321];
        return `${42}${JSON.stringify(data)}`;
      },
      startplay: function (room, name, avatar) {
        let data = `${420}${JSON.stringify([
          "startplay",
          name,
          room.type,
          "en",
          room.id,
          null,
          [null, "https://drawaria.online/", 1000, 1000, [null, avatar[0], avatar[1]], null],
        ])}`;
        return data;
      },
      votetrack: function (trackid) {
        let data = ["clientcmd", 1, [trackid]];
        return `${42}${JSON.stringify(data)}`;
      },
      requestcanvas: function (playerid) {
        let data = ["clientnotify", playerid, 10001];
        return `${42}${JSON.stringify(data)}`;
      },
      respondcanvas: function (playerid, base64) {
        let data = ["clientnotify", playerid, 10002, [base64]];
        return `${42}${JSON.stringify(data)}`;
      },
      galleryupload: function (playerid, imageid) {
        let data = ["clientnotify", playerid, 11, [imageid]];
        return `${42}${JSON.stringify(data)}`;
      },
      warning: function (playerid, type) {
        let data = ["clientnotify", playerid, 100, [type]];
        return `${42}${JSON.stringify(data)}`;
      },
      mute: function (playerid, targetname, mute = 0) {
        let data = ["clientnotify", playerid, 1, [mute, targetname]];
        return `${42}${JSON.stringify(data)}`;
      },
      hide: function (playerid, targetname, hide = 0) {
        let data = ["clientnotify", playerid, 3, [hide, targetname]];
        return `${42}${JSON.stringify(data)}`;
      },
      report: function (playerid, reason, targetname) {
        let data = ["clientnotify", playerid, 2, [targetname, reason]];
        return `${42}${JSON.stringify(data)}`;
      },
      line: function (playerid, lastx, lasty, x, y, isactive, size, color, ispixel) {
        let data = [
          "drawcmd",
          0,
          [lastx / 100, lasty / 100, x / 100, y / 100, isactive, -size, color, playerid, ispixel],
        ];
        return `${42}${JSON.stringify(data)}`;
      },
      erase: function (playerid, lastx, lasty, x, y, isactive, size, color) {
        let data = ["drawcmd", 1, [lastx / 100, lasty / 100, x / 100, y / 100, isactive, -size, color, playerid]];
        return `${42}${JSON.stringify(data)}`;
      },
      flood: function (x, y, color, size, r, g, b, a) {
        // 42["drawcmd",2,[x, y,color,{"0":r,"1":g,"2":b,"3":a},size]]
        let data = ["drawcmd", 2, [x / 100, y / 100, color, { 0: r, 1: g, 2: b, 3: a }, size]];
        return `${42}${JSON.stringify(data)}`;
      },
      undo: function (playerid) {
        // 42["drawcmd",3,[playerid]]
        let data = ["drawcmd", 3, [playerid]];
        return `${42}${JSON.stringify(data)}`;
      },
      clear: function () {
        // 42["drawcmd",4,[]]
        let data = ["drawcmd", 4, []];
        return `${42}${JSON.stringify(data)}`;
      },
      noop: function () {
        // 42["drawcmd",5,[0.44882022129015975,0.3157894736842105,0.44882022129015975,0.3157894736842105,true,-12,"#000000",playerid]]
      },
    };
    const events = {
      bc_announcement: function (data) {
        //
      },
      bc_chatmessage: function (data) {
        // 42["bc_chatmessage",3,"playername","a"]
      },
      bc_clearcanvasobj: function (data) {
        //
      },
      bc_clientnotify: function (data) {
        // 42["bc_clientnotify",playerid,"playername",code,null]
      },
      bc_createcanvasobj: function (data) {
        // 42["bc_createcanvasobj","1",[3,63001,0.5,0.5,0,1,null,"1",true]]
      },
      bc_customvoting_abort: function (data) {
        //
      },
      bc_customvoting_error: function (data) {
        // 42["bc_customvoting_error","rollbackcanvas"]
      },
      bc_customvoting_results: function (data) {
        // 42["bc_customvoting_results",[2],true,0]
      },
      bc_customvoting_start: function (data) {
        // 42["bc_customvoting_start",{"type":321,"secs":20,"acceptratios":[0.51],"pgdrawallow":true,"voteoptions":["YES","NO"]},1]
      },
      bc_customvoting_vote: function (data) {
        // 42["bc_customvoting_vote",1,0,[2,1,[1]]]
      },
      bc_exp: function (data) {
        // 42["bc_exp",29,4357]
      },
      bc_extannouncement: function (data) {
        //
      },
      bc_freedrawsession_reset: function (data) {
        // 42["bc_freedrawsession_reset",-1,{"votingtype":2,"currentvotes":0,"neededvotes":2,"votingtimeout":null}null]
      },
      bc_gesture: function (data) {
        // 42["bc_gesture",3,31]
      },
      bc_musicbox_play: function (data) {
        // 42["bc_musicbox_play",[30394,1,"37678185",252386,1661295694733,"Sony Masterworks - Smooth Criminal","2cellos/smooth-criminal"]]
      },
      bc_musicbox_vote: function (data) {
        // 42["bc_musicbox_vote",[[30394,1]],3,30394]
      },
      bc_pgdrawallow_results: function (data) {
        // 42["bc_pgdrawallow_results",2,true,true]
      },
      bc_pgdrawallow_startvoting: function (data) {
        // 42["bc_pgdrawallow_startvoting",2,1,false]
      },
      bc_pgdrawallow_vote: function (data) {
        // 42["bc_pgdrawallow_vote",2,1,0,false,[1,0]]
      },
      bc_playerafk: function (data) {
        // 42["bc_playerafk",28,"Jinx"]
      },
      bc_playerrated: function (data) {
        // 42["bc_playerrated",1,29,"lil cute girl",28,"Jinx",[1]]
      },
      bc_removecanvasobj: function (data) {
        // 42["bc_removecanvasobj",3,"1",null]
      },
      bc_resetplayername: function (data) {
        //
      },
      bc_round_results: function (data) {
        // 42["bc_round_results",[[5,"Jinx",15,61937,3,"63196790-c7da-11ec-8266-c399f90709b7",0],[4,"ツ♡thick mojo ♡ツ",15,65464,3,"018cdc20-47a4-11ec-b5b5-6bdacecdd51e",1]]]
      },
      bc_setavatarprop: function (data) {
        // 42["bc_setavatarprop",3]
      },
      bc_setobjattr: function (data) {
        // 42["bc_setobjattr","1","shared",false]
      },
      bc_setstatusflag: function (data) {
        // 42["bc_setstatusflag",3,3,true]
      },
      bc_spawnavatar: function (data) {
        // 42["bc_spawnavatar",3,true]
      },
      bc_startinground: function (data) {
        // 42["bc_startinground",200000,[],{"votingtype":0,"currentvotes":0,"neededvotes":2,"votingtimeout":null}]
      },
      bc_token: function (data) {
        // 42["bc_token",1,3,0]
      },
      bc_turn_abort: function (data) {
        // 42["bc_turn_abort","pass","lil cute girl","2c276aa0-dc5e-11ec-9fd3-c3a00b129da4","hammer",null]
      },
      bc_turn_fastout: function (data) {
        // 42["bc_turn_fastout",15000]
      },
      bc_turn_results: function (data) {
        // 42["bc_turn_results",[[1,"Jinx",2,2,"63196790-c7da-11ec-8266-c399f90709b7",0,0],[2,"vale",3,3,"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx.xxxxxxxxxxxxx",9248]],"cavern"]
      },
      bc_turn_waitplayers: function (data) {
        // 42["bc_turn_waitplayers",true,-1,6]
      },
      bc_uc_freedrawsession_changedroom: function (data) {
        // console.log(data[2], data[3])
        // 42["bc_uc_freedrawsession_changedroom",[list of drawlines not !important]]
      },
      bc_uc_freedrawsession_start: function (data) {
        //
      },
      bc_votekick: function (data) {
        // 42["bc_votekick","Jinx",22,true]
      },
      bc_votingtimeout: function (data) {
        // 42["bc_votingtimeout",{"votingtype":2,"currentvotes":0,"neededvotes":2,"votingtimeout":null}]
      },
      bcmc_playervote: function (data) {
        // 42["bcmc_playervote","playername",{"votingtype":3,"currentvotes":1,"neededvotes":2,"votingtimeout":1661296731309}]
      },
      bcuc_getfpid: function (data) {
        // 42["bcuc_getfpid"]
        // 42["clientcmd",901,[{"visitorId":"a8923f0870050d4a4e771cd26679ab6e"}]]
      },
      bcuc_itemactivated: function (data) {
        // 42["bcuc_itemactivated",3,63001,[2,[0.5,0.5],0,1,null],1]
      },
      bcuc_itemactivationabort: function (data) {
        //
      },
      bcuc_moderatormsg: function (data) {
        // 42["bcuc_moderatormsg","Kick Player",true]
      },
      bcuc_snapchatmessage: function (data) {
        // 42["uc_snapshot","1671740010120.1.28028"]
        // https://drawaria.online/snapshot/save
      },
      mc_drawcommand: function (data) {
        // 42["mc_drawcommand",0,[0.2958167330677291,0.24970131421744324,0.2958167330677291,0.24970131421744324,true,-12,"#000000",3]]
      },
      mc_moveavatar: function (data) {
        // 42["mc_moveavatar",3,36081456,true]
      },
      mc_moveobj: function (data) {
        // 42["mc_moveobj","1",0.8266237186146181,0.24248391556470414,3,{"movespeed":500}]
      },
      mc_roomplayerschange: function (data) {
        // console.log(data[2])
        // 42["mc_roomplayerschange","join","playername",[{"id":1,"name":"ᴮᴱᴺᴵᴹᴬᴿᵠ","turnscore":0,"roundscore":0,"roundguesstime":0,"avatarid":"81253f20-ff93-11ec-9fd3-c3a00b129da4.1661276848726","account_stats":null,"from":"TR","medals":0,"turnstarcount":0,"statusflags":[]}{"id":3,"name":"playername","turnscore":0,"roundscore":0,"roundguesstime":0,"avatarid":"81253f20-ff93-11ec-9fd3-c3a00b129da4.1661276848726","account_stats":null,"from":"GB","medals":0,"turnstarcount":0,"statusflags":[]}],{"votingtype":2,"currentvotes":0,"neededvotes":0,"votingtimeout":null}false,3]
      },
      mc_rotateobj: function (data) {
        // 42["mc_rotateobj","1",0.2617993877991494,3]
      },
      mc_turn_guessdraw: function (data) {
        // 42["mc_turn_guessdraw",90000,[],"ÆŽÌµÍ’Í‘ÍŠÍ Í–Í“EÌµÌ”Í Í˜ÍœÌ Ì¼",{"votingtype":1,"currentvotes":0,"neededvotes":2,"votingtimeout":null}false]
      },
      mc_turn_tip: function (data) {
        // 42["mc_turn_tip","_a_m__"]
      },
      mc_turn_waitselectword: function (data) {
        // 42["mc_turn_waitselectword",11000,"ÆŽÌµÍ’Í‘ÍŠÍ Í–Í“EÌµÌ”Í Í˜ÍœÌ Ì¼",6,"c46de8f0-f493-11ec-9fd3-c3a00b129da4",2,5,false]
      },
      mc_turn_wordguessed: function (data) {
        // 42["mc_turn_wordguessed","vale",[[2,3,3,9248],[1,2,2,0]]]
      },
      uc_avatarspawninfo: function (data) {
        // 42["uc_avatarspawninfo","9a2ab5b2-b81e-4690-9af7-475d870d6e20",[[38,75059625,0]]]
      },
      uc_buyitemerror: function (data) {
        //
      },
      uc_canvasobjs: function (data) {
        // 42["uc_canvasobjs","9a2ab5b2-b81e-4690-9af7-475d870d6e20",{}]
      },
      uc_chatmuted: function (data) {
        // 42["uc_chatmuted"]
      },
      uc_coins: function (data) {
        // 42["uc_coins",-50,43]
      },
      uc_inventoryitems: function (data) {
        // 42["uc_inventoryitems",[[100,99,null],[63000,null,null],[86000,null,null]],false,false] list
      },
      uc_resetavatar: function (data) {
        //
      },
      uc_serverserstart: function (data) {
        //
      },
      uc_snapshot: function (data) {
        //
      },
      uc_tokenerror: function (data) {
        // 42["uc_tokenerror",2]
      },
      uc_turn_begindraw: function (data) {
        // 42["uc_turn_begindraw",90000,"arrow"]
      },
      uc_turn_selectword: function (data) {
        // 42["uc_turn_selectword",11000,["vase","cellar","rain"],1,7,false]
      },
      uc_turn_selectword_refreshlist: function (data) {
        // 42["uc_turn_selectword_refreshlist",["crayons","trade","team"]]
      },
      uc_turn_wordguessedlocalThis: function (data) {
        // 42["uc_turn_wordguessedlocalThis","stage",3,[[2,3,3,53938],[1,2,2,0]]]
      },
    };

    globalThis["_io"] = { events, emits };
  })("QBit");

  (function BiggerBrush() {
    const QBit = globalThis[arguments[0]];

    class BiggerBrush extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "CubeEngine");

      active;
      constructor() {
        super("BiggerBrush", '<i class="fas fa-brush"></i>');
        this.active = false;
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
        this.drawwidthrangeSlider = document.querySelector("#drawwidthrange");
        // this.enable();
      }

      #loadInterface() {
        this.#row1();
      }

      #row1() {
        const row = domMake.Row();
        {
          const enableButton = domMake.Button("Enable");

          enableButton.addEventListener("click", (event) => {
            this.active ? this.disable() : this.enable();
          });
          row.appendChild(enableButton);
          this.htmlElements.toggleStatusButton = enableButton;
        }
        this.htmlElements.section.appendChild(row);
      }

      enable() {
        document.querySelectorAll(".drawcontrols-button").forEach((n) => {
          n.classList.remove("drawcontrols-disabled");
        });
        this.active = true;

        this.htmlElements.toggleStatusButton.classList.add("active");
        this.htmlElements.toggleStatusButton.textContent = "Active";

        this.drawwidthrangeSlider.parentElement.previousElementSibling.lastElementChild.click();
        this.drawwidthrangeSlider.parentElement.style.display = "flex";
        this.drawwidthrangeSlider.max = 48;
        this.drawwidthrangeSlider.min = -2000;

        this.notify("success", `enabled`);
      }

      disable() {
        this.active = false;

        this.htmlElements.toggleStatusButton.classList.remove("active");
        this.htmlElements.toggleStatusButton.textContent = "Inactive";

        this.drawwidthrangeSlider.max = 45;
        this.drawwidthrangeSlider.min = -100;

        this.notify("warning", `disabled`);
      }
    }
  })("QBit");

  (function BetterBrush() {
    const QBit = globalThis[arguments[0]];

    class BetterBrush extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "CubeEngine");

      constructor() {
        super("BetterBrush", '<i class="fas fa-magic"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();

        {
          const target = document.querySelector(".drawcontrols-popuplist");

          const visibilityOvserver = new MutationObserver((mutations) => {
            if (this.active)
              if (mutations[0].target.style != "display:none") {
                mutations[0].target.querySelectorAll("div").forEach((n) => {
                  n.removeAttribute("style");
                });
              }
          });

          visibilityOvserver.observe(target, {
            attributes: true,
          });
        }
      }

      #loadInterface() {
        this.#row1();
      }

      #row1() {
        const row = domMake.Row();
        {
          const enableButton = domMake.Button("Enable");

          enableButton.addEventListener("click", (event) => {
            this.active ? this.disable() : this.enable();
          });

          row.appendChild(enableButton);
          this.htmlElements.toggleStatusButton = enableButton;
        }
        this.htmlElements.section.appendChild(row);
      }

      enable() {
        this.active = true;

        this.htmlElements.toggleStatusButton.classList.add("active");
        this.htmlElements.toggleStatusButton.textContent = "Active";

        this.notify("success", `enabled`);
      }

      disable() {
        this.active = false;

        this.htmlElements.toggleStatusButton.classList.remove("active");
        this.htmlElements.toggleStatusButton.textContent = "Inactive";

        this.notify("warning", `disabled`);
      }
    }
  })("QBit");

  (function BiggerStencil() {
    const QBit = globalThis[arguments[0]];

    class BiggerStencil extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "CubeEngine");

      active;

      constructor() {
        super("BiggerStencil", '<i class="fas fa-parachute-box"></i>');
        this.active = false;
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();

        {
          const target = document.querySelector(".fa-parachute-box").parentElement;
          const accessabilityObserver = new MutationObserver((mutations) => {
            if (this.active)
              if (mutations[0].target.disabled) {
                mutations[0].target.disabled = "";
              }
          });

          accessabilityObserver.observe(target, {
            attributes: true,
          });
        }
      }

      #loadInterface() {
        this.#row1();
      }

      #row1() {
        const row = domMake.Row();
        {
          const enableButton = domMake.Button("Enable");

          enableButton.addEventListener("click", (event) => {
            this.active ? this.disable() : this.enable();
          });
          row.appendChild(enableButton);
          this.htmlElements.toggleStatusButton = enableButton;
        }
        this.htmlElements.section.appendChild(row);
      }

      enable() {
        this.active = true;

        this.htmlElements.toggleStatusButton.classList.add("active");
        this.htmlElements.toggleStatusButton.textContent = "Active";

        this.notify("success", `enabled`);
      }

      disable() {
        this.active = false;

        this.htmlElements.toggleStatusButton.classList.remove("active");
        this.htmlElements.toggleStatusButton.textContent = "Inactive";

        this.notify("warning", `disabled`);
      }
    }
  })("QBit");

  (function GhostCanvas() {
    const QBit = globalThis[arguments[0]];
    const Await = QBit.findGlobal("Await");

    QBit.Styles.addRule(
      ".ghostimage { position:fixed; top:50%; left:50%; opacity:.6; box-shadow: 0 0 1px 1px cornflowerblue inset; }"
    );

    function getBoundingClientRect(htmlElement) {
      let { top, right, bottom, left, width, height, x, y } = htmlElement.getBoundingClientRect();

      top = Number(top).toFixed();
      right = Number(right).toFixed();
      bottom = Number(bottom).toFixed();
      left = Number(left).toFixed();
      width = Number(width).toFixed();
      height = Number(height).toFixed();
      x = Number(x).toFixed();
      y = Number(y).toFixed();

      return { top, right, bottom, left, width, height, x, y };
    }

    function makeDragable(draggableElement, update) {
      var pos1 = 0,
        pos2 = 0,
        pos3 = 0,
        pos4 = 0;
      draggableElement.onmousedown = dragMouseDown;

      function dragMouseDown(e) {
        e = e || window.event;
        e.preventDefault();
        // get the mouse cursor position at startup:
        pos3 = e.clientX;
        pos4 = e.clientY;
        document.onmouseup = closeDragElement;
        // call a function whenever the cursor moves:
        document.onmousemove = elementDrag;
      }

      function elementDrag(e) {
        e = e || window.event;
        e.preventDefault();
        // calculate the new cursor position:
        pos1 = pos3 - e.clientX;
        pos2 = pos4 - e.clientY;
        pos3 = e.clientX;
        pos4 = e.clientY;
        // set the element's new position:
        draggableElement.style.top = Number(draggableElement.offsetTop - pos2).toFixed() + "px";
        draggableElement.style.left = Number(draggableElement.offsetLeft - pos1).toFixed() + "px";
        update();
      }

      function closeDragElement() {
        /* stop moving when mouse button is released:*/
        document.onmouseup = null;
        document.onmousemove = null;
      }
    }

    const radios = [];

    class GhostCanvas extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "CubeEngine");
      static isFavorite = true;

      GameCanvas;
      DrawCanvas;
      DrawCanvasContext;
      DrawCanvasRect;
      loadedImages;
      drawingManager;

      constructor() {
        super("GhostCanvas", '<i class="fas fa-images"></i>');
        this.GameCanvas = document.body.querySelector("canvas#canvas");
        this.DrawCanvas = document.createElement("canvas");
        this.DrawCanvasRect = {};
        this.loadedImages = [];
        this.DrawCanvasContext = this.DrawCanvas.getContext("2d");
        this.drawingManager = new TaskManager(this);

        this.#onStartup();
        this.resetAllSettings();
      }

      #onStartup() {
        this.#loadInterface();
        this.DrawCanvas.width = this.GameCanvas.width;
        this.DrawCanvas.height = this.GameCanvas.height;
        this.DrawCanvas.style =
          "position:fixed; opacity:.6; box-shadow: 0 0 1px 1px firebrick inset; pointer-events: none;";

        const onResize = new Await(this.alignDrawCanvas.bind(this), 500);
        window.addEventListener("resize", (event) => {
          onResize.call();
        });

        this.htmlElements.input.addEventListener("change", (event) => {
          if (this.htmlElements.input.checked) this.alignDrawCanvas();
        });
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
        this.#row3();
        this.#row4();
        this.#row5();
      }

      #row1() {
        const row = domMake.Row();
        {
          const resetSettingsButton = domMake.Button("Reset");
          const showCanvasInput = domMake.Tree("input", { type: "checkbox", title: "Toggle Canvas", class: "icon" });
          const clearCanvasButton = domMake.Button("Clear");

          resetSettingsButton.title = "Reset Settings";
          clearCanvasButton.title = "Clear GameCanvas";

          resetSettingsButton.addEventListener("click", (event) => {
            this.resetAllSettings();
          });

          showCanvasInput.addEventListener("change", () => {
            this.DrawCanvas.style.display = showCanvasInput.checked ? "block" : "none";
          });

          clearCanvasButton.addEventListener("click", (event) => {
            let data = ["drawcmd", 0, [0.5, 0.5, 0.5, 0.5, !0, -2000, "#FFFFFF", -1, !1]];
            this.findGlobal("BotClientInterface").siblings[0].bot.send(`${42}${JSON.stringify(data)}`);
          });

          document.body.appendChild(this.DrawCanvas);
          row.appendAll(resetSettingsButton, showCanvasInput, clearCanvasButton);
        }
        this.htmlElements.section.appendChild(row);
      }

      #row2() {
        const row = domMake.Row();
        {
          const loadPixelDataButton = domMake.Button("Load");
          const pixelsLeftToDraw = domMake.Tree("input", {
            type: "text",
            readonly: true,
            style: "text-align: center;",
            value: "0",
          });
          const clearPixelListButton = domMake.Button("Clear");

          this.htmlElements.pixelsLeftToDraw = pixelsLeftToDraw;
          loadPixelDataButton.title = "Load Pixels to draw";
          clearPixelListButton.title = "Clear Pixels to draw";

          loadPixelDataButton.addEventListener("click", (event) => {
            this.saveCanvas();
          });

          clearPixelListButton.addEventListener("click", (event) => {
            this.setPixelList([]);
          });

          row.appendAll(loadPixelDataButton, pixelsLeftToDraw, clearPixelListButton);
        }
        this.htmlElements.section.appendChild(row);
      }

      #row3() {
        const row = domMake.Row();
        {
          const startDrawingButton = domMake.Button("Start");
          const stopDrawingButton = domMake.Button("Stop");

          startDrawingButton.addEventListener("click", (event) => {
            this.drawingManager.startDrawing();
          });
          stopDrawingButton.addEventListener("click", (event) => {
            this.drawingManager.stopDrawing();
          });

          row.appendAll(startDrawingButton, stopDrawingButton);
        }
        this.htmlElements.section.appendChild(row);
      }

      #row4() {
        const row = domMake.Row();
        {
          const brushSizeInput = domMake.Tree("input", { type: "number", min: 2, value: 2, max: 200, step: 1 });
          const singleColorModeInput = domMake.Tree("input", { type: "checkbox", class: "icon" });
          const brushColorInput = domMake.Tree("input", { type: "text", value: "blue" });

          brushSizeInput.addEventListener("change", (event) => {
            this.drawingManager.brushSize = Number(brushSizeInput.value);
          });
          singleColorModeInput.addEventListener("change", (event) => {
            this.drawingManager.singleColor = Boolean(singleColorModeInput.checked);
          });
          brushColorInput.addEventListener("change", (event) => {
            this.drawingManager.brushColor = brushColorInput;
          });

          row.appendAll(brushSizeInput, singleColorModeInput, brushColorInput);
        }
        this.htmlElements.section.appendChild(row);
      }

      #row5() {
        const row = domMake.IconList();
        {
          const id = generate.uuidv4();
          const chooseGhostlyImageInput = domMake.Tree("input", { type: "file", id: id, hidden: true });
          const chooseGhostlyImageLabel = domMake.Tree("label", { for: id, class: "icon", title: "Add Image" }, [
            domMake.Tree("i", { class: "fas fa-plus" }),
          ]);

          const localThis = this;
          function onChange() {
            if (!this.files || !this.files[0]) return;
            const myFileReader = new FileReader();
            myFileReader.addEventListener("load", (event) => {
              const base64 = event.target.result.replace("image/gif", "image/png");
              localThis.createGhostImage(base64, row);
            });
            myFileReader.readAsDataURL(this.files[0]);
          }
          chooseGhostlyImageInput.addEventListener("change", onChange);

          row.appendAll(chooseGhostlyImageLabel, chooseGhostlyImageInput);
        }
        {
          const resetImageSelectionLabel = domMake.Tree("div", { class: "icon", title: "Unselect" }, [
            domMake.Tree("i", { class: "fas fa-chevron-left" }),
          ]);
          resetImageSelectionLabel.addEventListener("click", () => {
            document.body.querySelectorAll('input[name="ghostimage"]').forEach((node) => {
              node.checked = false;
            });
          });
          row.appendChild(resetImageSelectionLabel);
        }
        this.htmlElements.section.appendChild(row);
      }

      createGhostImage(imageSource, row) {
        this.alignDrawCanvas();
        const image = this.loadExtension(GhostImage, (reference) => {
          this.loadedImages.push(reference);
        });
        row.appendChild(image.htmlElements.label);
        image.setImageSource(imageSource);
      }

      clearCanvas() {
        this.DrawCanvasContext.clearRect(0, 0, this.DrawCanvas.width, this.DrawCanvas.height);
      }

      saveCanvas() {
        this.getAllPixels();
      }

      resetAllSettings() {
        this.clearCanvas();
        this.loadedImages.forEach((image, index) => {
          setTimeout(() => {
            image.reduceToAtoms();
          }, 10 * index);
        });
        this.drawingManager.stopDrawing();
        this.setPixelList([]);
        this.alignDrawCanvas(true);
      }

      alignDrawCanvas() {
        if (arguments[0]) {
          this.DrawCanvas.width = this.GameCanvas.width;
          this.DrawCanvas.height = this.GameCanvas.height;
        }

        const GameCanvasRect = getBoundingClientRect(this.GameCanvas);

        this.DrawCanvas.style.top = `${GameCanvasRect.top}px`;
        this.DrawCanvas.style.left = `${GameCanvasRect.left}px`;
        this.DrawCanvas.style.width = `${GameCanvasRect.width}px`;
        this.DrawCanvas.style.height = `${GameCanvasRect.height}px`;

        const DrawCanvasRect = getBoundingClientRect(this.DrawCanvas);

        if (DrawCanvasRect.width <= 0 || DrawCanvasRect.height <= 0)
          return Object.assign(this.DrawCanvasRect, DrawCanvasRect);
        // DrawCanvasRect.alignModifierX = Number(this.DrawCanvas.width / DrawCanvasRect.width).toFixed(2);
        // DrawCanvasRect.alignModifierY = Number(this.DrawCanvas.height / DrawCanvasRect.height).toFixed(2);

        DrawCanvasRect.drawModifierX = 100 / DrawCanvasRect.width;
        DrawCanvasRect.drawModifierY = 100 / DrawCanvasRect.height;
        Object.assign(this.DrawCanvasRect, DrawCanvasRect);
      }

      getAllPixels() {
        const image = this.DrawCanvasContext.getImageData(
          0,
          0,
          this.DrawCanvasContext.canvas.width,
          this.DrawCanvasContext.canvas.height
        );
        const pixels = [];

        for (let index = 0; index < image.data.length; index += 4) {
          // const x = (index * 0.25) % image.width;
          // const y = Math.floor((index * 0.25) / image.width);
          const x = (index * 0.25) % image.width;
          const y = Math.floor((index * 0.25) / image.width);

          const r = image.data[index + 0];
          const g = image.data[index + 1];
          const b = image.data[index + 2];
          const a = image.data[index + 3];
          // const color = rgbaArrayToHex([r, g, b, a]);
          const color = [r, g, b, a];
          pixels.push({ x1: x, y1: y, x2: x, y2: y, color });
        }

        this.setPixelList(pixels);
      }

      getNoneTransparentPixels() {
        this.getAllPixels();

        const newPixelArray = this.drawingManager.pixelList.filter((pixel) => {
          return pixel.color !== "#000000";
          // return /^#0[0-8]0[0-8]0[0-8]$/g.test(pixel.color);
        });

        this.setPixelList(newPixelArray);
      }

      setPixelList(pixelArray) {
        this.drawingManager.pixelList = pixelArray;
        this.htmlElements.pixelsLeftToDraw.value = pixelArray.length;
      }
    }

    class GhostImage extends QBit {
      image;
      rect;

      constructor() {
        super("GhostImage", '<i class="fas fa-image-polaroid"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();

        this.image = domMake.Tree("img", { class: "ghostimage" });
        this.image.addEventListener("mousedown", (event) => {
          this.htmlElements.label.click();
        });

        this.htmlElements.input.type = "radio";
        this.htmlElements.input.name = "ghostimage";

        radios.push(this.htmlElements.input);
        this.htmlElements.input.addEventListener("change", (event) => {
          radios.forEach(function (radio) {
            document.body.querySelector(`label[for="${radio.id}"]`).classList.remove("active");
          });
          this.htmlElements.label.classList.add("active");
        });

        document.body.appendChild(this.image);
        makeDragable(this.image, this.updatePosition.bind(this));
        this.updatePosition();
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
      }

      #row1() {
        const row = domMake.Row();
        {
          const paintCanvasButton = domMake.Button("Place");

          paintCanvasButton.addEventListener("click", (event) => {
            this.drawImage();
          });

          row.appendAll(paintCanvasButton);
        }
        {
          const enableButton = domMake.Button("Delete");

          enableButton.addEventListener("click", (event) => {
            this.reduceToAtoms();
          });
          row.appendChild(enableButton);
          this.htmlElements.toggleStatusButton = enableButton;
        }
        this.htmlElements.section.appendChild(row);
      }

      #row2() {
        const row = domMake.Row();
        {
          const scaleInput = domMake.Tree("input", {
            type: "number",
            title: "rotation",
            min: 0.1,
            max: 10,
            value: 1,
            step: 0.02,
          });

          scaleInput.addEventListener("change", () => {
            this.image.style.scale = scaleInput.value;
          });

          this.htmlElements.scaleInput = scaleInput;

          row.appendAll(scaleInput);
        }
        {
          const rotationInput = domMake.Tree("input", { type: "number", title: "rotation", value: 0, step: 1 });

          rotationInput.addEventListener("change", () => {
            this.image.style.rotate = `${rotationInput.value}deg`;
          });

          this.htmlElements.rotationInput = rotationInput;

          row.appendChild(rotationInput);
        }
        this.htmlElements.section.appendChild(row);
      }

      drawImage() {
        this.updatePosition();
        const ctx = this.parent.DrawCanvasContext;

        const offsetTop = Number(this.rect.top) - Number(this.parent.DrawCanvasRect.top);
        const offsetLeft = Number(this.rect.left) - Number(this.parent.DrawCanvasRect.left);

        // const multiX = Number(this.parent.DrawCanvasRect.alignModifierX);
        // const multiY = Number(this.parent.DrawCanvasRect.alignModifierY);

        const angle = (Math.PI / 180) * Number(this.htmlElements.rotationInput.value);
        const scale = Number(this.htmlElements.scaleInput.value);

        const imageWidth = this.image.width * scale;
        const imageHeight = this.image.height * scale;
        const imgHalfWidth = imageWidth * 0.5;
        const imgHalfHeight = imageHeight * 0.5;

        ctx.save();
        ctx.translate(offsetLeft + imgHalfWidth, offsetTop + imgHalfHeight);
        ctx.rotate(angle);
        ctx.translate(-imgHalfWidth, -imgHalfHeight);
        ctx.drawImage(this.image, 0, 0, imageWidth, imageHeight);
        ctx.restore();
      }

      setImageSource(imageSource) {
        this.image.src = imageSource;
        this.setIcon(`<img src="${this.image.src}">`);
      }

      updatePosition() {
        this.rect = getBoundingClientRect(this.image);
      }

      reduceToAtoms() {
        this.image.remove();
        const pos = radios.indexOf(this.htmlElements.input);
        if (~pos) radios.splice(pos, 1);

        let pos2 = this.parent.loadedImages.indexOf(this);
        if (~pos2) {
          this.parent.loadedImages.splice(pos2, 1);
        }
        this._EXP_destroy(!0);
      }
    }

    class TaskManager {
      isRunning;
      pixelList;
      parent;
      BotClientManager;
      singleColor;
      brushColor;
      brushSize;

      constructor(parent) {
        this.pixelList = [];
        this.singleColor = !1;
        this.brushColor = "blue";
        this.brushSize = 2;
        this.parent = parent;
      }

      startDrawing() {
        this.BotClientManager = this.parent.findGlobal("BotClientManager")?.siblings[0];
        this.isRunning = true;
        this.doTasks();
        this.parent.notify("info", "Started");
      }

      stopDrawing() {
        this.isRunning = false;
      }

      doTasks() {
        if (!this.BotClientManager || this.BotClientManager.children.length <= 0) this.stopDrawing();
        if (!this.isRunning) return this.parent.notify("info", "Stopped");

        this.BotClientManager.children.forEach((botClientInterface, index) => {
          this.parseAndSendPixel(botClientInterface, index);
        });

        setTimeout(() => {
          this.doTasks();
        }, 1);
      }

      parseAndSendPixel(botClientInterface, index) {
        if (this.pixelList.length <= 0) return this.stopDrawing();
        if (!botClientInterface.bot || !botClientInterface.bot.getReadyState()) return;

        const task = index % 2 == 0 ? this.pixelList.shift() : this.pixelList.pop();
        botClientInterface.bot.send(this.convertTasks(task));
        this.parent.htmlElements.pixelsLeftToDraw.value = this.pixelList.length;
      }

      convertTasks(pixel) {
        const playerid = -1;
        const lastx = pixel.x1 * this.parent.DrawCanvasRect.drawModifierX;
        const lasty = pixel.y1 * this.parent.DrawCanvasRect.drawModifierY;
        const x = pixel.x2 * this.parent.DrawCanvasRect.drawModifierX;
        const y = pixel.y2 * this.parent.DrawCanvasRect.drawModifierY;
        const isactive = !0;
        const size = pixel.size ?? this.brushSize;
        const pxColor = pixel.color;
        const color = this.singleColor
          ? this.brushColor
          : `rgba(${pxColor[0]},${pxColor[1]},${pxColor[2]},${parseFloat(pxColor[3] * 0.390625).toFixed(2)})`;
        const ispixel = !1;

        let data = [
          "drawcmd",
          0,
          [lastx * 0.01, lasty * 0.01, x * 0.01, y * 0.01, isactive, -size, color, playerid, ispixel],
        ];

        return `${42}${JSON.stringify(data)}`;
      }
    }
  })("QBit");

  (function GhostCanvasAlgorithms() {
    const QBit = globalThis[arguments[0]];

    function sortByColor(pixel1, pixel2) {
      const color1 = rgbaArrayToHex(pixel1.color);
      const color2 = rgbaArrayToHex(pixel2.color);
      if (color1 < color2) {
        return -1;
      }
      if (color1 > color2) {
        return 1;
      }
      return 0;
    }

    function intToHex(number) {
      return number.toString(16).padStart(2, "0");
    }

    function rgbaArrayToHex(rgbaArray) {
      const r = intToHex(rgbaArray[0]);
      const g = intToHex(rgbaArray[1]);
      const b = intToHex(rgbaArray[2]);
      const a = intToHex(rgbaArray[3]);
      return "#" + r + g + b + a;
    }

    function areSameColor(colorArray1, colorArray2, allowedDifference = 8) {
      var red = colorArray1[0] - colorArray2[0];
      var green = colorArray1[1] - colorArray2[1];
      var blue = colorArray1[2] - colorArray2[2];

      if (red < 0) red = red * -1;
      if (green < 0) green = green * -1;
      if (blue < 0) blue = blue * -1;

      if (blue > allowedDifference || green > allowedDifference || red > allowedDifference) return false;
      return true;
    }

    class GhostCanvasMinify extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "GhostCanvas");

      constructor() {
        super("Minify", '<i class="fas fa-compress-arrows-alt"></i>');
        this.minOpacity = 20;
        this.maxFuzzyness = 32;
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
        this.#row3();
        this.#row4();
      }

      #row1() {
        const row = domMake.Row();
        {
          const fuzzynessInput = domMake.Tree("input", {
            type: "number",
            title: "Fuzzyness",
            step: 1,
            min: 0,
            max: 255,
            value: 1,
          });
          const opacityInput = domMake.Tree("input", {
            type: "number",
            title: "Opacity",
            step: 1,
            min: 0,
            max: 255,
            value: 0,
          });

          fuzzynessInput.addEventListener("change", () => {
            this.maxFuzzyness = Number(fuzzynessInput.value);
          });

          opacityInput.addEventListener("change", () => {
            this.minOpacity = Number(opacityInput.value);
          });

          row.appendAll(fuzzynessInput, opacityInput);
        }
        this.htmlElements.section.appendChild(row);
      }
      #row2() {
        const row = domMake.Row();
        {
          const minifyPixelsArrayButton = domMake.Button("Minify");

          minifyPixelsArrayButton.addEventListener("click", (event) => {
            this.minifyPixelsArray();
          });

          row.appendAll(minifyPixelsArrayButton);
        }
        this.htmlElements.section.appendChild(row);
      }
      #row3() {}
      #row4() {}

      minifyPixelsArray() {
        const pixelArray = this.parent.drawingManager.pixelList;
        const newPixelArray = [];

        let currentPixel = pixelArray[0];
        let lastPixel = currentPixel;
        let currentLine = currentPixel;

        for (let index = 0; index < pixelArray.length; index++) {
          currentPixel = pixelArray[index];

          if (lastPixel.color[3] < 10 && currentPixel.color[3] >= 10) {
            // From Transparent To Solid

            currentLine = currentPixel;
          } else if (lastPixel.color[3] >= 10 && currentPixel.color[3] < 10) {
            // From Solid To Transparent

            currentLine.x2 = lastPixel.x2;
            newPixelArray.push(currentLine);
            currentLine = currentPixel;
          } else if (currentPixel.color[3] >= 10 && lastPixel.color[3] >= 10) {
            // From Solid To Solid

            if (
              currentLine.y1 !== currentPixel.y1 ||
              lastPixel.x2 !== currentPixel.x1 - 1 ||
              !areSameColor(lastPixel.color, currentPixel.color, this.maxFuzzyness)
            ) {
              currentLine.x2 = lastPixel.x2;
              newPixelArray.push(currentLine);
              currentLine = currentPixel;
            }
          } else {
            // From Transparent To Transparent
          }

          lastPixel = currentPixel;
        }
        // if (currentLine.color[3] >= 10) newPixelArray.push(currentLine);

        this.parent.setPixelList(newPixelArray);
      }

      minifyPixelsArray_alt() {
        const pixelArray = this.parent.drawingManager.pixelList;
        const newPixelArray = [];
        var lastPixel = pixelArray[0];
        var currentLine = lastPixel;
        const stepsize = this.parent.stepsize ?? 1;

        for (let i = 0; i < pixelArray.length; i += stepsize) {
          const currentPixel = pixelArray[i];

          if (currentPixel.y1 !== currentLine.y1 || currentPixel.color !== lastPixel.color) {
            currentLine.x2 = lastPixel.x2;
            if (!/^#[0-9a-fA-F]{6}[0-4]{2}$/.test(lastPixel.color)) newPixelArray.push(currentLine);
            currentLine = currentPixel;
          }

          lastPixel = currentPixel;
        }
        newPixelArray.push(currentLine);

        this.parent.setPixelList(newPixelArray);
      }
    }

    class GhostCanvasSort extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "GhostCanvas");

      constructor() {
        super("Sort", '<i class="fas fa-sort-numeric-down"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
        this.#row3();
        this.#row4();
      }

      #row1() {
        const row = domMake.Row();
        {
          const sortPixelsArrayButton = domMake.Button("Sort");

          sortPixelsArrayButton.addEventListener("click", (event) => {
            this.sortPixelsArray();
          });

          row.appendAll(sortPixelsArrayButton);
        }
        this.htmlElements.section.appendChild(row);
      }
      #row2() {}
      #row3() {}
      #row4() {}

      sortPixelsArray() {
        const pixelArray = this.parent.drawingManager.pixelList;

        const newPixelArray = [...pixelArray].sort(sortByColor);

        this.parent.setPixelList(newPixelArray);
      }
    }
  })("QBit");

  (function BotClientInterface() {
    const QBit = globalThis[arguments[0]];
    const BotClient = QBit.findGlobal("BotClient");

    let botcount = 0;
    const radios = [];

    function getMasterId() {
      return document.querySelector(".playerlist-name-self")?.parentElement.dataset.playerid || 0;
    }

    function parseAvatarURL(arr = []) {
      return `https://drawaria.online/avatar/cache/${arr.length > 0 ? arr.join(".") : "default"}.jpg`;
    }

    class BotClientManager extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "CubeEngine");

      constructor() {
        super(`BotClientManager`, '<i class="fas fa-robot"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
      }

      #loadInterface() {
        this.#row1();
      }

      #row1() {
        const row = domMake.IconList();
        {
          const id = generate.uuidv4();
          const createBotClientInterfaceInput = domMake.Tree("input", { type: "button", id: id, hidden: true });
          const createBotClientInterfaceLabel = domMake.Tree("label", { for: id, class: "icon", title: "Add Image" }, [
            domMake.Tree("i", { class: "fas fa-plus" }),
          ]);

          createBotClientInterfaceInput.addEventListener("click", () => {
            this.createBotClientInterface();
          });

          row.appendAll(createBotClientInterfaceLabel);
          row.appendAll(createBotClientInterfaceInput);
        }
        {
          const id = generate.uuidv4();
          const removeBotClientInterfaceInput = domMake.Tree("input", { type: "button", id: id, hidden: true });
          const removeBotClientInterfaceLabel = domMake.Tree("label", { for: id, class: "icon", title: "Add Image" }, [
            domMake.Tree("i", { class: "fas fa-minus" }),
          ]);

          removeBotClientInterfaceInput.addEventListener("click", () => {
            this.deleteBotClientInterface();
          });

          row.appendAll(removeBotClientInterfaceLabel);
          row.appendAll(removeBotClientInterfaceInput);
        }
        this.htmlElements.header.before(row);
      }

      createBotClientInterface() {
        const instance = this.loadExtension(BotClientInterface);
        instance.htmlElements.input.type = "radio";
        instance.htmlElements.input.name = "botClient";

        radios.push(instance.htmlElements.input);
        instance.htmlElements.input.addEventListener("change", (event) => {
          radios.forEach(function (radio) {
            document.body.querySelector(`label[for="${radio.id}"]`).classList.remove("active");
          });
          instance.htmlElements.label.classList.add("active");
        });

        return instance;
      }

      deleteBotClientInterface() {
        const input = document.body.querySelector(`input[name="botClient"]:checked`);

        const matches = this.children.filter((child) => {
          return child.htmlElements.input === input;
        });
        if (matches.length <= 0) return;

        const instance = matches[0];

        instance.bot.disconnect();

        const labelPos = radios.indexOf(instance.htmlElements.input);
        if (~labelPos) radios.splice(labelPos, 1);

        instance._EXP_destroy(!0);
      }
    }

    class BotClientInterface extends QBit {
      static dummy1 = QBit.register(this);
      // static dummy2 = QBit.bind(this, 'CubeEngine');
      // static dummy3 = QBit.bind(this, 'CubeEngine');

      constructor() {
        super(`Bot${botcount}`, '<i class="fas fa-robot"></i>');
        this.bot = new BotClient();
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
        this.setClientName(this.bot.name);
        this.setClientIcon(this.bot.avatar);
      }

      #loadInterface() {
        this.#row1();
      }

      #row1() {
        const row = domMake.Row();
        {
          let join_button = domMake.Button("Enter");
          let leave_button = domMake.Button("Leave");

          join_button.addEventListener("click", (event) => {
            this.bot.enterRoom(document.querySelector("#invurl").value);
          });

          leave_button.addEventListener("click", (event) => {
            this.bot.disconnect();
          });

          row.appendAll(join_button, leave_button);
        }
        this.htmlElements.section.appendChild(row);
      }

      setClientName(name) {
        this.setName(name);
        this.bot.name = name;
      }

      setClientIcon(icon) {
        this.setIcon(`<img src="${parseAvatarURL(this.bot.avatar)}">`);
        this.bot.avatar = icon;
      }
    }
  })("QBit");

  (function BotClientInteractions() {
    const QBit = globalThis[arguments[0]];

    class BotPersonality extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "BotClientInterface");

      constructor() {
        super("Personality", '<i class="fas fa-user-cog"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
      }

      #row1() {
        const row = domMake.Row();
        {
          let botName = domMake.Tree("input", { type: "text", placeholder: "Your Bots name" });
          let botNameAccept = domMake.Tree("button", { class: "icon" }, [domMake.Tree("i", { class: "fas fa-check" })]);

          botNameAccept.addEventListener("click", (event) => {
            this.parent.setClientName(botName.value);
          });

          row.appendAll(botName, botNameAccept);
        }
        this.htmlElements.section.appendChild(row);
      }

      #row2() {
        let id = generate.uuidv4();
        const row = domMake.Row();
        {
          let botAvatarUpload = domMake.Tree("input", { type: "file", id: id, hidden: true });
          let botAvatarAccept = domMake.Tree("label", { for: id, class: "btn btn-outline-secondary" }, [
            "Upload BotAvatar",
          ]);

          const localThis = this;
          function onChange() {
            if (!this.files || !this.files[0]) return;
            let myFileReader = new FileReader();
            myFileReader.addEventListener("load", (e) => {
              let a = e.target.result.replace("image/gif", "image/png");
              fetch("https://drawaria.online/uploadavatarimage", {
                method: "POST",
                body: "imagedata=" + encodeURIComponent(a) + "&fromeditor=true",
                headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
              }).then((res) =>
                res.text().then((body) => {
                  localThis.parent.setClientIcon(body.split("."));
                })
              );
            });
            myFileReader.readAsDataURL(this.files[0]);
          }
          botAvatarUpload.addEventListener("change", onChange);

          row.appendAll(botAvatarUpload, botAvatarAccept);
        }
        this.htmlElements.section.appendChild(row);
      }
    }

    class BotSozials extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "BotClientInterface");

      constructor() {
        super("Socialize", '<i class="fas fa-comment-dots"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
      }

      #row1() {
        const row = domMake.Row();
        {
          let messageClear_button = domMake.Button('<i class="fas fa-strikethrough"></i>');
          let messageSend_button = domMake.Button('<i class="fas fa-paper-plane"></i>');
          let message_input = domMake.Tree("input", { type: "text", placeholder: "message..." });

          messageClear_button.classList.add("icon");
          messageSend_button.classList.add("icon");

          messageClear_button.addEventListener("click", (event) => {
            message_input.value = "";
          });

          messageSend_button.addEventListener("click", (event) => {
            this.parent.bot.emit("chatmsg", message_input.value);
          });

          message_input.addEventListener("keypress", (event) => {
            if (event.keyCode != 13) return;
            this.parent.bot.emit("chatmsg", message_input.value);
          });

          row.appendAll(messageClear_button, message_input, messageSend_button);
        }
        this.htmlElements.section.appendChild(row);
      }

      #row2() {
        const row = domMake.IconList();
        // row.classList.add('nowrap');
        {
          document
            .querySelectorAll("#gesturespickerselector .gesturespicker-container .gesturespicker-item")
            .forEach((node, index) => {
              let clone = node.cloneNode(true);
              clone.classList.add("icon");
              clone.addEventListener("click", (event) => {
                this.parent.bot.emit("sendgesture", index);
              });
              row.appendChild(clone);
            });
        }
        this.htmlElements.section.appendChild(row);
      }
    }

    class BotTokenGiver extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "BotClientInterface");

      constructor() {
        super("Tokken", '<i class="fas fa-thumbs-up"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
      }

      #row1() {
        const row = domMake.IconList();
        // row.classList.add('nowrap');
        {
          let listOfTokens = [
            '<i class="fas fa-thumbs-up"></i>',
            '<i class="fas fa-heart"></i>',
            '<i class="fas fa-paint-brush"></i>',
            '<i class="fas fa-cocktail"></i>',
            '<i class="fas fa-hand-peace"></i>',
            '<i class="fas fa-feather-alt"></i>',
            '<i class="fas fa-trophy"></i>',
            '<i class="fas fa-mug-hot"></i>',
            '<i class="fas fa-gift"></i>',
          ];
          listOfTokens.forEach((token, index) => {
            let tokenSend_button = domMake.Button(token);
            tokenSend_button.classList.add("icon");
            tokenSend_button.addEventListener("click", () => {
              this.parent.bot.room.players.forEach((player) => {
                this.parent.bot.emit("settoken", player.id, index);
              });
            });
            row.appendChild(tokenSend_button);
          });
        }
        this.htmlElements.section.appendChild(row);
      }

      #row2() {
        const row = domMake.Row();
        {
          let toggleStatus_button = domMake.Button("Toggle Status");
          toggleStatus_button.addEventListener("click", () => {
            this.parent.bot.attributes.status = !this.parent.bot.attributes.status;
            let status = this.parent.bot.attributes.status;
            toggleStatus_button.classList[status ? "add" : "remove"]("active");
            this.parent.bot.emit("setstatusflag", 0, status);
            this.parent.bot.emit("setstatusflag", 1, status);
            this.parent.bot.emit("setstatusflag", 2, status);
            this.parent.bot.emit("setstatusflag", 3, status);
            this.parent.bot.emit("setstatusflag", 4, status);
          });
          row.appendChild(toggleStatus_button);
        }
        this.htmlElements.section.appendChild(row);
      }
    }

    class BotCanvasAvatar extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "BotClientInterface");

      constructor() {
        super("SpawnAvatar", '<i class="fas fa-user-circle"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();
      }

      #loadInterface() {
        this.#row1();
      }

      #row1() {
        const row = domMake.Row();
        {
          // Spawn && Move Avatar
          let avatarPosition = { x: 0, y: 0 };

          let avatarSpawn_button = domMake.Button('<i class="fas fa-exchange-alt"></i>');
          let avatarChange_button = domMake.Button('<i class="fas fa-retweet"></i>');
          let avatarPositionX_button = domMake.Tree("input", {
            type: "number",
            value: 2,
            min: 2,
            max: 98,
            title: "Left",
          });
          let avatarPositionY_button = domMake.Tree("input", {
            type: "number",
            value: 2,
            min: 2,
            max: 98,
            title: "Top",
          });

          avatarSpawn_button.addEventListener("click", (event) => {
            this.parent.bot.emit("spawnavatar");
            this.parent.bot.attributes.spawned = !this.parent.bot.attributes.spawned;
          });

          avatarChange_button.addEventListener("click", (event) => {
            this.parent.bot.emit("setavatarprop");
            this.parent.bot.attributes.rounded = !this.parent.bot.attributes.rounded;
          });

          avatarPositionX_button.addEventListener("change", (event) => {
            avatarPosition.x = avatarPositionX_button.value;
            this.parent.bot.emit("moveavatar", avatarPosition.x, avatarPosition.y);
          });

          avatarPositionY_button.addEventListener("change", (event) => {
            avatarPosition.y = avatarPositionY_button.value;
            this.parent.bot.emit("moveavatar", avatarPosition.x, avatarPosition.y);
          });

          avatarSpawn_button.title = "Spawn Avatar";
          avatarChange_button.title = "Toggle Round Avatar";

          row.appendAll(avatarSpawn_button, avatarPositionX_button, avatarPositionY_button, avatarChange_button);
        }
        this.htmlElements.section.appendChild(row);
      }
    }

    function getMyId() {
      return document.querySelector(".playerlist-name-self")?.parentElement.dataset.playerid || 0;
    }

    function parseAvatarURL(arr = []) {
      return `https://drawaria.online/avatar/cache/${arr.length > 0 ? arr.join(".") : "default"}.jpg`;
    }
  })("QBit");

  (function AutoTranslate() {
    const QBit = globalThis[arguments[0]];

    const unicodeLanguagePatterns = new Map();
    unicodeLanguagePatterns.set("Common", /\p{Script=Common}+/u); // CommonPattern
    unicodeLanguagePatterns.set("Arabic", /\p{Script=Arabic}+/u); // ArabicPattern
    unicodeLanguagePatterns.set("Armenian", /\p{Script=Armenian}+/u); // ArmenianPattern
    unicodeLanguagePatterns.set("Bengali", /\p{Script=Bengali}+/u); // BengaliPattern
    unicodeLanguagePatterns.set("Bopomofo", /\p{Script=Bopomofo}+/u); // BopomofoPattern
    unicodeLanguagePatterns.set("Braille", /\p{Script=Braille}+/u); // BraillePattern
    unicodeLanguagePatterns.set("Buhid", /\p{Script=Buhid}+/u); // BuhidPattern
    unicodeLanguagePatterns.set("Canadian_Aboriginal", /\p{Script=Canadian_Aboriginal}+/u); // Canadian_AboriginalPattern
    unicodeLanguagePatterns.set("Cherokee", /\p{Script=Cherokee}+/u); // CherokeePattern
    unicodeLanguagePatterns.set("Cyrillic", /\p{Script=Cyrillic}+/u); // CyrillicPattern
    unicodeLanguagePatterns.set("Devanagari", /\p{Script=Devanagari}+/u); // DevanagariPattern
    unicodeLanguagePatterns.set("Ethiopic", /\p{Script=Ethiopic}+/u); // EthiopicPattern
    unicodeLanguagePatterns.set("Georgian", /\p{Script=Georgian}+/u); // GeorgianPattern
    unicodeLanguagePatterns.set("Greek", /\p{Script=Greek}+/u); // GreekPattern
    unicodeLanguagePatterns.set("Gujarati", /\p{Script=Gujarati}+/u); // GujaratiPattern
    unicodeLanguagePatterns.set("Gurmukhi", /\p{Script=Gurmukhi}+/u); // GurmukhiPattern
    unicodeLanguagePatterns.set("Han", /\p{Script=Han}+/u); // HanPattern
    unicodeLanguagePatterns.set("Hangul", /\p{Script=Hangul}+/u); // HangulPattern
    unicodeLanguagePatterns.set("Hanunoo", /\p{Script=Hanunoo}+/u); // HanunooPattern
    unicodeLanguagePatterns.set("Hebrew", /\p{Script=Hebrew}+/u); // HebrewPattern
    unicodeLanguagePatterns.set("Hiragana", /\p{Script=Hiragana}+/u); // HiraganaPattern
    unicodeLanguagePatterns.set("Inherited", /\p{Script=Inherited}+/u); // InheritedPattern
    unicodeLanguagePatterns.set("Kannada", /\p{Script=Kannada}+/u); // KannadaPattern
    unicodeLanguagePatterns.set("Katakana", /\p{Script=Katakana}+/u); // KatakanaPattern
    unicodeLanguagePatterns.set("Khmer", /\p{Script=Khmer}+/u); // KhmerPattern
    unicodeLanguagePatterns.set("Lao", /\p{Script=Lao}+/u); // LaoPattern
    unicodeLanguagePatterns.set("Latin", /\p{Script=Latin}+/u); // LatinPattern
    unicodeLanguagePatterns.set("Limbu", /\p{Script=Limbu}+/u); // LimbuPattern
    unicodeLanguagePatterns.set("Malayalam", /\p{Script=Malayalam}+/u); // MalayalamPattern
    unicodeLanguagePatterns.set("Mongolian", /\p{Script=Mongolian}+/u); // MongolianPattern
    unicodeLanguagePatterns.set("Myanmar", /\p{Script=Myanmar}+/u); // MyanmarPattern
    unicodeLanguagePatterns.set("Ogham", /\p{Script=Ogham}+/u); // OghamPattern
    unicodeLanguagePatterns.set("Oriya", /\p{Script=Oriya}+/u); // OriyaPattern
    unicodeLanguagePatterns.set("Runic", /\p{Script=Runic}+/u); // RunicPattern
    unicodeLanguagePatterns.set("Sinhala", /\p{Script=Sinhala}+/u); // SinhalaPattern
    unicodeLanguagePatterns.set("Syriac", /\p{Script=Syriac}+/u); // SyriacPattern
    unicodeLanguagePatterns.set("Tagalog", /\p{Script=Tagalog}+/u); // TagalogPattern
    unicodeLanguagePatterns.set("Tagbanwa", /\p{Script=Tagbanwa}+/u); // TagbanwaPattern
    unicodeLanguagePatterns.set("Tamil", /\p{Script=Tamil}+/u); // TamilPattern
    unicodeLanguagePatterns.set("Telugu", /\p{Script=Telugu}+/u); // TeluguPattern
    unicodeLanguagePatterns.set("Thaana", /\p{Script=Thaana}+/u); // ThaanaPattern
    unicodeLanguagePatterns.set("Thai", /\p{Script=Thai}+/u); // ThaiPattern
    unicodeLanguagePatterns.set("Tibetan", /\p{Script=Tibetan}+/u); // TibetanPattern
    unicodeLanguagePatterns.set("Yi", /\p{Script=Yi}+/u); // YiPattern

    const observeDOM = (function () {
      const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
      /**
       * @param {HTMLElement} nodeToObserve
       * @param {Function} callback
       */
      return function (nodeToObserve, callback) {
        if (!nodeToObserve || nodeToObserve.nodeType !== 1) return;

        if (MutationObserver) {
          // define a new observer
          var mutationObserver = new MutationObserver(callback);

          // have the observer observe for changes in children
          mutationObserver.observe(nodeToObserve, { childList: true, subtree: !1 });
          return mutationObserver;
        }

        // browser support fallback
        else if (window.addEventListener) {
          nodeToObserve.addEventListener("DOMNodeInserted", callback, false);
          nodeToObserve.addEventListener("DOMNodeRemoved", callback, false);
        }
      };
    })();

    class AutoTranslate extends QBit {
      static dummy1 = QBit.register(this);
      static dummy2 = QBit.bind(this, "CubeEngine");

      active;

      constructor() {
        super("AutoTranslate", '<i class="fas fa-language"></i>');
        this.#onStartup();
      }

      #onStartup() {
        this.#loadInterface();

        this.active = false;

        const observable = document.querySelector("#chatbox_messages");

        observeDOM(observable, (mutation) => {
          if (!this.active) return;

          const addedNodes = [];
          const removedNodes = [];

          mutation.forEach((record) => record.addedNodes.length & addedNodes.push(...record.addedNodes));
          mutation.forEach((record) => record.removedNodes.length & removedNodes.push(...record.removedNodes));

          // console.log('Added:', addedNodes, 'Removed:', removedNodes);

          addedNodes.forEach((node) => {
            if (node.classList.contains("systemchatmessage5")) return;
            if (node.querySelector(".playerchatmessage-selfname")) return;
            if (!node.querySelector(".playerchatmessage-text")) return;

            // console.log(node);
            const message = node.querySelector(".playerchatmessage-text");
            const text = message.textContent;
            const language = this.detectLanguage(text);

            if (language)
              this.translate(text, language, "en", (translation) => {
                applyTitleToChatMessage(translation, message);
              });
          });

          function applyTitleToChatMessage(text, node) {
            node.title = text;
          }
        });
      }

      #loadInterface() {
        this.#row1();
        this.#row2();
      }

      #row1() {
        const row = domMake.Row();
        {
          const enableButton = domMake.Button("Enable");

          enableButton.addEventListener("click", (event) => {
            this.active ? this.disable() : this.enable();
          });
          row.appendChild(enableButton);
          this.htmlElements.toggleStatusButton = enableButton;
        }
        this.htmlElements.section.appendChild(row);
      }

      #row2() {}

      enable() {
        this.active = true;

        this.htmlElements.toggleStatusButton.classList.add("active");
        this.htmlElements.toggleStatusButton.textContent = "Active";

        this.notify("success", `enabled`);
      }

      disable() {
        this.active = false;

        this.htmlElements.toggleStatusButton.classList.remove("active");
        this.htmlElements.toggleStatusButton.textContent = "Inactive";

        this.notify("warning", `disabled`);
      }

      detectLanguage(text) {
        if (unicodeLanguagePatterns.get("Cyrillic").test(text)) return "ru";
        if (unicodeLanguagePatterns.get("Arabic").test(text)) return "ar";
        if (unicodeLanguagePatterns.get("Greek").test(text)) return "el";
      }

      translate(textToTranslate, from = "ru", to = "en", callback) {
        const sourceText = textToTranslate;
        const sourceLang = from;
        const targetLang = to;

        const url =
          "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" +
          sourceLang +
          "&tl=" +
          targetLang +
          "&dt=t&q=" +
          encodeURI(sourceText);

        xhrGetJson(url, log);

        function log(data) {
          callback(data[0][0][0]);
        }
      }
    }

    function xhrGetJson(url, callback) {
      const req = new XMLHttpRequest();

      req.onload = (e) => {
        const response = req.response; // not responseText
        if (!callback) return;
        try {
          callback(JSON.parse(response));
        } catch (error) {
          console.log(error);
        }
      };
      req.open("GET", url);
      req.send();
    }
  })("QBit");

  // --- NEW FUNCTIONALITIES START HERE ---

(function GlobalUndo() {
    const QBit = globalThis[arguments[0]];

    class GlobalUndo extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        constructor() {
            super("Undo Last Draw", '<i class="fas fa-undo"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            const row = domMake.Row();
            {
                const undoButton = domMake.Button("Undo");
                undoButton.title = "Undoes the last drawing action. (Requires drawing turn)";
                undoButton.addEventListener("click", () => {
                    const myPlayerIdElement = document.querySelector(".playerlist-name-self")?.parentElement;
                    const playerId = myPlayerIdElement ? myPlayerIdElement.dataset.playerid : "-1"; // Use -1 for global if no specific player, or get current player's ID
                    if (globalThis.sockets && globalThis.sockets.length > 0) {
                        const data = _io.emits.undo(parseInt(playerId));
                        globalThis.sockets[0].send(data);
                        this.notify("info", `Undo command sent for player ID: ${playerId}.`);
                    } else {
                        this.notify("warning", "No active WebSocket connection found.");
                    }
                });
                row.appendChild(undoButton);
            }
            this.htmlElements.section.appendChild(row);
        }
    }
})("QBit");

(function PassTurn() {
    const QBit = globalThis[arguments[0]];

    class PassTurn extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        constructor() {
            super("Pass Turn", '<i class="fas fa-forward"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            const row = domMake.Row();
            {
                const passTurnButton = domMake.Button("Pass Turn");
                passTurnButton.title = "Passes the current drawing turn.";
                passTurnButton.addEventListener("click", () => {
                    if (globalThis.sockets && globalThis.sockets.length > 0) {
                        const data = _io.emits.passturn();
                        globalThis.sockets[0].send(data);
                        this.notify("info", "Pass turn command sent.");
                    } else {
                        this.notify("warning", "No active WebSocket connection found.");
                    }
                });
                row.appendChild(passTurnButton);
            }
            this.htmlElements.section.appendChild(row);
        }
    }
})("QBit");

(function PlayerVoteKick() {
    const QBit = globalThis[arguments[0]];

    class PlayerVoteKick extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #playerListContainer;
        constructor() {
            super("Vote Kick", '<i class="fas fa-gavel"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.updatePlayerList();
            // MutationObserver to update player list when players change (join/leave)
            const playerListElement = document.getElementById("playerlist");
            if (playerListElement) {
                const observer = new MutationObserver(() => this.updatePlayerList());
                observer.observe(playerListElement, { childList: true, subtree: true });
            }
        }

        #loadInterface() {
            const row = domMake.Row();
            this.#playerListContainer = domMake.IconList();
            row.appendChild(this.#playerListContainer);
            this.htmlElements.section.appendChild(row);
        }

        updatePlayerList() {
            this.#playerListContainer.innerHTML = ''; // Clear existing buttons
            const playerRows = document.querySelectorAll("#playerlist .playerlist-row");
            playerRows.forEach(playerRow => {
                const playerId = playerRow.dataset.playerid;
                const playerName = playerRow.querySelector(".playerlist-name a")?.textContent || `Player ${playerId}`;
                // Avoid self-kick button
                const myPlayerIdElement = document.querySelector(".playerlist-name-self")?.parentElement;
                const myPlayerId = myPlayerIdElement ? myPlayerIdElement.dataset.playerid : null;
                if (playerId === myPlayerId) {
                    return;
                }

                const playerButton = domMake.Button(playerName);
                playerButton.title = `Vote to kick ${playerName}`;
                playerButton.addEventListener("click", () => {
                    if (globalThis.sockets && globalThis.sockets.length > 0) {
                        const data = _io.emits.sendvotekick(parseInt(playerId));
                        globalThis.sockets[0].send(data);
                        this.notify("info", `Vote kick command sent for ${playerName} (ID: ${playerId}).`);
                    } else {
                        this.notify("warning", "No active WebSocket connection found.");
                    }
                });
                this.#playerListContainer.appendChild(playerButton);
            });
            if (playerRows.length <= 1) { // Only self or no players
                const noPlayersMessage = domMake.Tree("span", {}, ["No other players to kick."]);
                this.#playerListContainer.appendChild(noPlayersMessage);
            }
        }
    }
})("QBit");

(function CustomChatMessage() {
    const QBit = globalThis[arguments[0]];

    class CustomChatMessage extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #messageInput;
        constructor() {
            super("Custom Chat", '<i class="fas fa-comments"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            const row = domMake.Row();
            {
                this.#messageInput = domMake.Tree("input", { type: "text", placeholder: "Your message..." });
                const sendButton = domMake.Button('<i class="fas fa-paper-plane"></i>');
                sendButton.classList.add("icon");
                sendButton.addEventListener("click", () => {
                    this.sendMessage(this.#messageInput.value);
                    this.#messageInput.value = '';
                });
                this.#messageInput.addEventListener("keypress", (event) => {
                    if (event.keyCode === 13) { // Enter key
                        this.sendMessage(this.#messageInput.value);
                        this.#messageInput.value = '';
                    }
                });
                row.appendAll(this.#messageInput, sendButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        sendMessage(message) {
            if (!message.trim()) return; // Don't send empty messages
            if (globalThis.sockets && globalThis.sockets.length > 0) {
                const data = _io.emits.chatmsg(message);
                globalThis.sockets[0].send(data);
                this.notify("info", `Message sent: "${message}"`);
            } else {
                this.notify("warning", "No active WebSocket connection found.");
            }
        }
    }
})("QBit");


(function ToggleAFK() {
    const QBit = globalThis[arguments[0]];

    class ToggleAFK extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        active;
        constructor() {
            super("Toggle AFK", '<i class="fas fa-mug-hot"></i>');
            this.active = false; // Initial state
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            const row = domMake.Row();
            {
                const toggleButton = domMake.Button("Toggle AFK");
                toggleButton.addEventListener("click", () => {
                    this.active = !this.active;
                    if (globalThis.sockets && globalThis.sockets.length > 0) {
                        const data = _io.emits.playerafk(); // playerafk() toggles AFK state
                        globalThis.sockets[0].send(data);
                        toggleButton.classList[this.active ? "add" : "remove"]("active");
                        toggleButton.textContent = this.active ? "AFK Active" : "AFK Inactive";
                        this.notify("info", `AFK status toggled to: ${this.active}`);
                    } else {
                        this.notify("warning", "No active WebSocket connection found.");
                    }
                });
                row.appendChild(toggleButton);
            }
            this.htmlElements.section.appendChild(row);
        }
    }
})("QBit");

(function PlayerMovement() {
    const QBit = globalThis[arguments[0]];

    class PlayerMovement extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #posXInput;
        #posYInput;
        constructor() {
            super("Move Avatar", '<i class="fas fa-arrows-alt"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            const row = domMake.Row();
            {
                this.#posXInput = domMake.Tree("input", { type: "number", min: 0, max: 100, value: 50, step: 1, title: "X Position (0-100)" });
                this.#posYInput = domMake.Tree("input", { type: "number", min: 0, max: 100, value: 50, step: 1, title: "Y Position (0-100)" });
                const moveButton = domMake.Button('<i class="fas fa-location-arrow"></i>');
                moveButton.classList.add("icon");

                moveButton.addEventListener("click", () => {
                    this.moveAvatar();
                });
                this.#posXInput.addEventListener("change", () => this.moveAvatar());
                this.#posYInput.addEventListener("change", () => this.moveAvatar());

                row.appendAll(this.#posXInput, this.#posYInput, moveButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        moveAvatar() {
            const posX = parseFloat(this.#posXInput.value);
            const posY = parseFloat(this.#posYInput.value);

            if (isNaN(posX) || isNaN(posY) || posX < 0 || posX > 100 || posY < 0 || posY > 100) {
                this.notify("warning", "Invalid X or Y position. Must be between 0 and 100.");
                return;
            }

            if (globalThis.sockets && globalThis.sockets.length > 0) {
                const data = _io.emits.moveavatar(posX, posY);
                globalThis.sockets[0].send(data);
                this.notify("info", `Avatar moved to X:${posX}, Y:${posY}.`);
            } else {
                this.notify("warning", "No active WebSocket connection found.");
            }
        }
    }
})("QBit");

(function GlobalTokenGiver() {
    const QBit = globalThis[arguments[0]];

    class GlobalTokenGiver extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #playerList = []; // To store player IDs and names
        #tokenButtons = []; // Store references to token buttons

        constructor() {
            super("Give Tokens", '<i class="fas fa-hand-holding-heart"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.updatePlayerList();
            // Observer for player list changes
            const playerListElement = document.getElementById("playerlist");
            if (playerListElement) {
                const observer = new MutationObserver(() => this.updatePlayerList());
                observer.observe(playerListElement, { childList: true, subtree: true });
            }
        }

        #loadInterface() {
            const row = domMake.IconList();
            {
                const tokens = [
                    { id: 0, icon: '<i class="fas fa-thumbs-up"></i>' }, // Thumbs Up
                    { id: 1, icon: '<i class="fas fa-heart"></i>' },     // Heart
                    { id: 2, icon: '<i class="fas fa-paint-brush"></i>' }, // Paint Brush
                    { id: 3, icon: '<i class="fas fa-cocktail"></i>' },    // Cocktail
                    { id: 4, icon: '<i class="fas fa-hand-peace"></i>' },  // Hand Peace
                    { id: 5, icon: '<i class="fas fa-feather-alt"></i>' }, // Feather
                    { id: 6, icon: '<i class="fas fa-trophy"></i>' },      // Trophy
                    { id: 7, icon: '<i class="fas fa-mug-hot"></i>' },     // Mug
                    { id: 8, icon: '<i class="fas fa-gift"></i>' }         // Gift
                ];

                tokens.forEach(token => {
                    const tokenButton = domMake.Button(token.icon);
                    tokenButton.classList.add("icon");
                    tokenButton.title = `Give Token ${token.id}`;
                    tokenButton.addEventListener("click", () => {
                        this.giveToken(token.id);
                    });
                    row.appendChild(tokenButton);
                    this.#tokenButtons.push(tokenButton);
                });
            }
            this.htmlElements.section.appendChild(row);
        }

        updatePlayerList() {
            this.#playerList = [];
            const playerRows = document.querySelectorAll("#playerlist .playerlist-row");
            playerRows.forEach(playerRow => {
                const playerId = playerRow.dataset.playerid;
                const playerName = playerRow.querySelector(".playerlist-name a")?.textContent || `Player ${playerId}`;
                this.#playerList.push({ id: parseInt(playerId), name: playerName });
            });
            // You might want to enable/disable token buttons based on player count or drawing status
        }

        giveToken(tokenId) {
            if (globalThis.sockets && globalThis.sockets.length > 0) {
                if (this.#playerList.length > 0) {
                    this.#playerList.forEach(player => {
                        const data = _io.emits.settoken(player.id, tokenId);
                        globalThis.sockets[0].send(data);
                        this.notify("info", `Token ${tokenId} sent to ${player.name} (ID: ${player.id}).`);
                    });
                } else {
                    this.notify("warning", "No players found in the room to give tokens to.");
                }
            } else {
                this.notify("warning", "No active WebSocket connection found.");
            }
        }
    }
})("QBit");

(function SetStatusFlag() {
    const QBit = globalThis[arguments[0]];

    class SetStatusFlag extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        constructor() {
            super("Set Status", '<i class="fas fa-flag"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            const flags = [
                { id: 0, name: "Music Enabled", icon: '<i class="fas fa-music"></i>' },
                { id: 1, name: "AFK 1", icon: '<i class="fas fa-bed"></i>' },
                { id: 2, name: "AFK 2", icon: '<i class="fas fa-couch"></i>' },
                { id: 3, name: "Inventory Open", icon: '<i class="fas fa-box-open"></i>' },
                { id: 4, name: "Friendlist Open", icon: '<i class="fas fa-user-friends"></i>' }
            ];

            flags.forEach(flag => {
                const row = domMake.Row();
                const toggleButton = domMake.Button(flag.icon + " " + flag.name);
                toggleButton.classList.add("status-flag-button");
                toggleButton.dataset.flagId = flag.id;
                toggleButton.dataset.isActive = "false"; // Initial state

                toggleButton.addEventListener("click", () => {
                    const isActive = toggleButton.dataset.isActive === "true";
                    const newActiveState = !isActive;
                    toggleButton.dataset.isActive = newActiveState;
                    toggleButton.classList[newActiveState ? "add" : "remove"]("active");

                    if (globalThis.sockets && globalThis.sockets.length > 0) {
                        const data = _io.emits.setstatusflag(flag.id, newActiveState);
                        globalThis.sockets[0].send(data);
                        this.notify("info", `Status flag '${flag.name}' toggled to: ${newActiveState}`);
                    } else {
                        this.notify("warning", "No active WebSocket connection found.");
                    }
                });
                row.appendChild(toggleButton);
                this.htmlElements.section.appendChild(row);
            });
        }
    }
})("QBit");

(function ReportPlayer() {
    const QBit = globalThis[arguments[0]];

    class ReportPlayer extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #playerSelect;
        #reasonSelect;
        #reasonInput;

        constructor() {
            super("Report Player", '<i class="fas fa-flag-checkered"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.updatePlayerList();
            const playerListElement = document.getElementById("playerlist");
            if (playerListElement) {
                const observer = new MutationObserver(() => this.updatePlayerList());
                observer.observe(playerListElement, { childList: true, subtree: true });
            }
        }

        #loadInterface() {
            // Player Selection Row
            const playerRow = domMake.Row();
            const playerLabel = domMake.Tree("label", {}, ["Player: "]);
            this.#playerSelect = domMake.Tree("select", { class: "form-control" });
            playerRow.appendAll(playerLabel, this.#playerSelect);
            this.htmlElements.section.appendChild(playerRow);

            // Reason Selection Row
            const reasonRow = domMake.Row();
            const reasonLabel = domMake.Tree("label", {}, ["Reason: "]);
            this.#reasonSelect = domMake.Tree("select", { class: "form-control" });
            const reasons = [
                { value: "hack", text: "Hack / Exploits" },
                { value: "bot", text: "Bot" },
                { value: "spam", text: "Spamming" },
                { value: "content", text: "Inappropriate drawings / Offensive content" },
                { value: "other", text: "Other" }
            ];
            reasons.forEach(reason => {
                const option = domMake.Tree("option", { value: reason.value }, [reason.text]);
                this.#reasonSelect.appendChild(option);
            });
            reasonRow.appendAll(reasonLabel, this.#reasonSelect);
            this.htmlElements.section.appendChild(reasonRow);

            // Additional Reason Input
            const reasonInputRow = domMake.Row();
            const reasonInputLabel = domMake.Tree("label", {}, ["Additional Comments: "]);
            this.#reasonInput = domMake.Tree("textarea", { rows: 2, placeholder: "Optional details..." });
            reasonInputRow.appendAll(reasonInputLabel, this.#reasonInput);
            this.htmlElements.section.appendChild(reasonInputRow);

            // Send Report Button
            const sendRow = domMake.Row();
            const sendButton = domMake.Button("Send Report");
            sendButton.addEventListener("click", () => this.sendReport());
            sendRow.appendChild(sendButton);
            this.htmlElements.section.appendChild(sendRow);
        }

        updatePlayerList() {
            this.#playerSelect.innerHTML = ''; // Clear existing options
            const defaultOption = domMake.Tree("option", { value: "" }, ["-- Select Player --"]);
            this.#playerSelect.appendChild(defaultOption);

            const playerRows = document.querySelectorAll("#playerlist .playerlist-row");
            playerRows.forEach(playerRow => {
                const playerId = playerRow.dataset.playerid;
                const playerName = playerRow.querySelector(".playerlist-name a")?.textContent || `Player ${playerId}`;
                const myPlayerIdElement = document.querySelector(".playerlist-name-self")?.parentElement;
                const myPlayerId = myPlayerIdElement ? myPlayerIdElement.dataset.playerid : null;
                if (playerId === myPlayerId) {
                    return; // Don't allow reporting self
                }
                const option = domMake.Tree("option", { value: playerName, "data-playerid": playerId }, [playerName]);
                this.#playerSelect.appendChild(option);
            });
        }

        sendReport() {
            const selectedPlayerOption = this.#playerSelect.options[this.#playerSelect.selectedIndex];
            const targetPlayerId = selectedPlayerOption.dataset.playerid;
            const targetPlayerName = selectedPlayerOption.value;
            const reason = this.#reasonSelect.value;
            const additionalReason = this.#reasonInput.value.trim();

            if (!targetPlayerId || !reason) {
                this.notify("warning", "Please select a player and a reason.");
                return;
            }

            const fullReason = additionalReason ? `${reason}: ${additionalReason}` : reason;

            if (globalThis.sockets && globalThis.sockets.length > 0) {
                const data = _io.emits.report(parseInt(targetPlayerId), fullReason, targetPlayerName);
                globalThis.sockets[0].send(data);
                this.notify("success", `Report sent for ${targetPlayerName} (Reason: ${fullReason}).`);
                this.#playerSelect.value = "";
                this.#reasonSelect.value = reasons[0].value;
                this.#reasonInput.value = "";
            } else {
                this.notify("warning", "No active WebSocket connection found.");
            }
        }
    }
})("QBit");

(function ClientCommandSender() {
    const QBit = globalThis[arguments[0]];

    class ClientCommandSender extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #cmdIdInput;
        #param1Input;
        #param2Input;
        #param3Input;

        constructor() {
            super("Client Cmd", '<i class="fas fa-terminal"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            const row1 = domMake.Row();
            this.#cmdIdInput = domMake.Tree("input", { type: "number", placeholder: "Command ID (e.g., 10)" });
            row1.appendChild(this.#cmdIdInput);
            this.htmlElements.section.appendChild(row1);

            const row2 = domMake.Row();
            this.#param1Input = domMake.Tree("input", { type: "text", placeholder: "Param 1 (e.g., true)" });
            this.#param2Input = domMake.Tree("input", { type: "text", placeholder: "Param 2 (e.g., 1)" });
            row2.appendAll(this.#param1Input, this.#param2Input);
            this.htmlElements.section.appendChild(row2);

            const row3 = domMake.Row();
            this.#param3Input = domMake.Tree("input", { type: "text", placeholder: "Param 3 (e.g., 'text')" });
            const sendButton = domMake.Button("Send CMD");
            sendButton.addEventListener("click", () => this.sendCommand());
            row3.appendAll(this.#param3Input, sendButton);
            this.htmlElements.section.appendChild(row3);
        }

        parseParam(paramStr) {
            if (paramStr.toLowerCase() === 'true') return true;
            if (paramStr.toLowerCase() === 'false') return false;
            if (!isNaN(paramStr) && paramStr.trim() !== '') return Number(paramStr);
            if (paramStr.startsWith('[') && paramStr.endsWith(']')) {
                try {
                    return JSON.parse(paramStr); // For arrays
                } catch (e) {
                    return paramStr;
                }
            }
            if (paramStr.startsWith('{') && paramStr.endsWith('}')) {
                try {
                    return JSON.parse(paramStr); // For objects
                } catch (e) {
                    return paramStr;
                }
            }
            return paramStr; // Default to string
        }

        sendCommand() {
            const cmdId = parseInt(this.#cmdIdInput.value);
            if (isNaN(cmdId)) {
                this.notify("warning", "Command ID must be a number.");
                return;
            }

            const params = [];
            const param1 = this.#param1Input.value.trim();
            const param2 = this.#param2Input.value.trim();
            const param3 = this.#param3Input.value.trim();

            if (param1) params.push(this.parseParam(param1));
            if (param2) params.push(this.parseParam(param2));
            if (param3) params.push(this.parseParam(param3));

            if (globalThis.sockets && globalThis.sockets.length > 0) {
                const payload = ["clientcmd", cmdId, params];
                const dataToSend = `${42}${JSON.stringify(payload)}`;

                globalThis.sockets[0].send(dataToSend);
                this.notify("info", `Custom clientcmd ${cmdId} sent with params: ${JSON.stringify(params)}.`);
            } else {
                this.notify("warning", "No active WebSocket connection found.");
            }
        }
    }
})("QBit");

(function RequestPlayerCanvas() {
    const QBit = globalThis[arguments[0]];

    class RequestPlayerCanvas extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #playerSelect;
        constructor() {
            super("Req/Res Canvas", '<i class="fas fa-paint-roller"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.updatePlayerList();
            const playerListElement = document.getElementById("playerlist");
            if (playerListElement) {
                const observer = new MutationObserver(() => this.updatePlayerList());
                observer.observe(playerListElement, { childList: true, subtree: true });
            }
        }

        #loadInterface() {
            const playerRow = domMake.Row();
            const playerLabel = domMake.Tree("label", {}, ["Player: "]);
            this.#playerSelect = domMake.Tree("select", { class: "form-control" });
            playerRow.appendAll(playerLabel, this.#playerSelect);
            this.htmlElements.section.appendChild(playerRow);

            const buttonsRow = domMake.Row();
            const requestButton = domMake.Button("Request Canvas");
            requestButton.addEventListener("click", () => this.requestCanvas());
            const respondButton = domMake.Button("Respond Canvas (Your Current Canvas)");
            respondButton.addEventListener("click", () => this.respondCanvas());
            buttonsRow.appendAll(requestButton, respondButton);
            this.htmlElements.section.appendChild(buttonsRow);
        }

        updatePlayerList() {
            this.#playerSelect.innerHTML = '';
            const defaultOption = domMake.Tree("option", { value: "" }, ["-- Select Player --"]);
            this.#playerSelect.appendChild(defaultOption);

            const playerRows = document.querySelectorAll("#playerlist .playerlist-row");
            playerRows.forEach(playerRow => {
                const playerId = playerRow.dataset.playerid;
                const playerName = playerRow.querySelector(".playerlist-name a")?.textContent || `Player ${playerId}`;
                const myPlayerIdElement = document.querySelector(".playerlist-name-self")?.parentElement;
                const myPlayerId = myPlayerIdElement ? myPlayerIdElement.dataset.playerid : null;
                if (playerId === myPlayerId) {
                    return; // Don't request/respond to self via this tool
                }
                const option = domMake.Tree("option", { value: playerId, "data-playername": playerName }, [playerName]);
                this.#playerSelect.appendChild(option);
            });
        }

        requestCanvas() {
            const selectedPlayerId = this.#playerSelect.value;
            const selectedPlayerName = this.#playerSelect.options[this.#playerSelect.selectedIndex]?.dataset.playername;

            if (!selectedPlayerId) {
                this.notify("warning", "Please select a player.");
                return;
            }

            if (globalThis.sockets && globalThis.sockets.length > 0) {
                const data = _io.emits.requestcanvas(parseInt(selectedPlayerId));
                globalThis.sockets[0].send(data);
                this.notify("info", `Canvas request sent to ${selectedPlayerName} (ID: ${selectedPlayerId}).`);
            } else {
                this.notify("warning", "No active WebSocket connection found.");
            }
        }

        respondCanvas() {
            const myPlayerIdElement = document.querySelector(".playerlist-name-self")?.parentElement;
            const myPlayerId = myPlayerIdElement ? parseInt(myPlayerIdElement.dataset.playerid) : null;
            if (!myPlayerId) {
                this.notify("warning", "Could not determine your player ID.");
                return;
            }

            const gameCanvas = document.body.querySelector("canvas#canvas");
            if (!gameCanvas) {
                this.notify("error", "Game canvas not found to capture image.");
                return;
            }

            try {
                const base64Image = gameCanvas.toDataURL("image/png");
                const selectedPlayerId = this.#playerSelect.value;
                if (!selectedPlayerId) {
                    this.notify("warning", "Please select a player to respond to.");
                    return;
                }

                if (globalThis.sockets && globalThis.sockets.length > 0) {
                    const data = _io.emits.respondcanvas(parseInt(selectedPlayerId), base64Image);
                    globalThis.sockets[0].send(data);
                    this.notify("success", `Your canvas sent to ID: ${selectedPlayerId}.`);
                } else {
                    this.notify("warning", "No active WebSocket connection found.");
                }
            } catch (e) {
                this.notify("error", `Failed to capture canvas or send: ${e.message}`);
                console.error("Canvas capture error:", e);
            }
        }
    }
})("QBit");

(function IntelligentArtist() {
    const QBit = globalThis[arguments[0]];

    // --- BASE DE DATOS DE BOCETOS DETALLADOS (50 PALABRAS) ---
    // (X, Y son porcentajes del 0 al 100)
    // Cada boceto está diseñado para ser reconocible y compuesto por múltiples trazos.

    // Helper para bocetos simples por defecto (genera círculos o cuadrados)
    function generateDefaultSimpleSketch(word) {
        const hash = word.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
        const isCircle = hash % 2 === 0; // Alternar entre círculo y cuadrado

        if (isCircle) {
            const centerX = 50, centerY = 50, radius = 15;
            const segments = 16; // Más segmentos para un círculo más suave
            const sketch = [];
            for (let i = 0; i < segments; i++) {
                const angle1 = (i / segments) * Math.PI * 2;
                const angle2 = ((i + 1) / segments) * Math.PI * 2;
                sketch.push({
                    x1: centerX + radius * Math.cos(angle1),
                    y1: centerY + radius * Math.sin(angle1),
                    x2: centerX + radius * Math.cos(angle2),
                    y2: centerY + radius * Math.sin(angle2)
                });
            }
            return sketch;
        } else {
            // Generar un cuadrado o un rectángulo simple
            const xOffset = 25 + (hash % 10); // Ligeramente variable
            const yOffset = 25 + (hash % 10);
            const size = 50 - (hash % 10);
            return [
                { x1: xOffset, y1: yOffset, x2: xOffset + size, y2: yOffset },
                { x1: xOffset + size, y1: yOffset, x2: xOffset + size, y2: yOffset + size },
                { x1: xOffset + size, y1: yOffset + size, x2: xOffset, y2: yOffset + size },
                { x1: xOffset, y1: yOffset + size, x2: xOffset, y2: yOffset }
            ];
        }
    }

    const SKETCH_DATABASE = {
        // --- BOCETOS DETALLADOS (Aproximadamente 15-20) ---
        "ARBOL": [ // Árbol con más detalle
            { x1: 48, y1: 80, x2: 48, y2: 50 }, { x1: 52, y1: 80, x2: 52, y2: 50 }, // Tronco más grueso
            { x1: 48, y1: 65, x2: 40, y2: 70 }, { x1: 52, y1: 65, x2: 60, y2: 70 }, // Raíces (opcional)
            { x1: 40, y1: 50, x2: 30, y2: 45 }, { x1: 30, y1: 45, x2: 35, y2: 30 }, // Contorno follaje
            { x1: 35, y1: 30, x2: 50, y2: 20 }, { x1: 50, y1: 20, x2: 65, y2: 30 },
            { x1: 65, y1: 30, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 60, y2: 50 },
            { x1: 60, y1: 50, x2: 40, y2: 50 }, { x1: 40, y1: 50, x2: 30, y2: 45 },
            { x1: 45, y1: 40, x2: 55, y2: 40 }, { x1: 50, y1: 30, x2: 50, y2: 45 } // Detalles internos follaje
        ],
        "CASA": [ // Casa con tejado y chimenea
            { x1: 30, y1: 70, x2: 70, y2: 70 }, { x1: 70, y1: 70, x2: 70, y2: 40 }, // Base de la casa
            { x1: 70, y1: 40, x2: 30, y2: 40 }, { x1: 30, y1: 40, x2: 30, y2: 70 },
            { x1: 30, y1: 40, x2: 50, y2: 20 }, { x1: 50, y1: 20, x2: 70, y2: 40 }, // Tejado
            { x1: 45, y1: 70, x2: 45, y2: 55 }, { x1: 55, y1: 70, x2: 55, y2: 55 }, { x1: 45, y1: 55, x2: 55, y2: 55 }, // Puerta
            { x1: 60, y1: 40, x2: 60, y2: 30 }, { x1: 65, y1: 40, x2: 65, y2: 30 }, { x1: 60, y1: 30, x2: 65, y2: 30 }, // Chimenea
            { x1: 35, y1: 50, x2: 45, y2: 50 }, { x1: 45, y1: 50, x2: 45, y2: 60 }, // Ventana
            { x1: 45, y1: 60, x2: 35, y2: 60 }, { x1: 35, y1: 60, x2: 35, y2: 50 }
        ],
        "SOL": [ // Sol con forma de círculo, rayos y una cara sonriente
            { type: "circle", x1: 50, y1: 50, radius: 15 }, // Círculo central
            { x1: 50, y1: 35, x2: 50, y2: 25 }, { x1: 60, y1: 40, x2: 70, y2: 35 },
            { x1: 65, y1: 50, x2: 75, y2: 50 }, { x1: 60, y1: 60, x2: 70, y2: 65 },
            { x1: 50, y1: 65, x2: 50, y2: 75 }, { x1: 40, y1: 60, x2: 30, y2: 65 },
            { x1: 35, y1: 50, x2: 25, y2: 50 }, { x1: 40, y1: 40, x2: 30, y2: 35 }, // Rayos
            { x1: 45, y1: 45, x2: 48, y2: 45 }, { x1: 52, y1: 45, x2: 55, y2: 45 }, // Ojos
            { x1: 45, y1: 58, x2: 55, y2: 58 } // Boca (sonrisa)
        ],
        "FLOR": [ // Flor con tallo, hojas y pétalos elaborados
            { x1: 50, y1: 80, x2: 50, y2: 55 }, // Tallo
            { x1: 45, y1: 70, x2: 35, y2: 65 }, { x1: 35, y1: 65, x2: 40, y2: 58 }, // Hojas
            { x1: 50, y1: 50, x2: 50, y2: 50 }, // Centro
            { type: "circle", x1: 50, y1: 50, radius: 5 }, // Círculo central para estambres
            { x1: 50, y1: 45, x2: 40, y2: 40 }, { x1: 40, y1: 40, x2: 35, y2: 50 }, { x1: 35, y1: 50, x2: 40, y2: 60 }, // Pétalo 1
            { x1: 50, y1: 45, x2: 60, y2: 40 }, { x1: 60, y1: 40, x2: 65, y2: 50 }, { x1: 65, y1: 50, x2: 60, y2: 60 }, // Pétalo 2
            { x1: 45, y1: 50, x2: 40, y2: 58 }, { x1: 40, y1: 58, x2: 50, y2: 65 }, // Pétalo 3
            { x1: 55, y1: 50, x2: 60, y2: 58 }, { x1: 60, y1: 58, x2: 50, y2: 65 }  // Pétalo 4
        ],
        "PERRO": [ // Perro con cuerpo, patas, cola, orejas y hocico
            { x1: 30, y1: 70, x2: 70, y2: 70 }, { x1: 30, y1: 70, x2: 35, y2: 50 }, // Cuerpo y patas
            { x1: 70, y1: 70, x2: 65, y2: 50 }, { x1: 35, y1: 50, x2: 65, y2: 50 },
            { x1: 45, y1: 50, x2: 50, y2: 40 }, { x1: 50, y1: 40, x2: 55, y2: 50 }, // Cabeza
            { x1: 45, y1: 40, x2: 40, y2: 35 }, { x1: 40, y1: 35, x2: 42, y2: 30 }, // Oreja 1
            { x1: 55, y1: 40, x2: 60, y2: 35 }, { x1: 60, y1: 35, x2: 58, y2: 30 }, // Oreja 2
            { x1: 50, y1: 48, x2: 50, y2: 45 }, { x1: 48, y1: 48, x2: 52, y2: 48 }, // Hocico y nariz
            { x1: 65, y1: 50, x2: 75, y2: 60 }, { x1: 75, y1: 60, x2: 80, y2: 55 } // Cola
        ],
        "GATO": [ // Gato con orejas puntiagudas, bigotes y cola
            { x1: 30, y1: 70, x2: 70, y2: 70 }, { x1: 30, y1: 70, x2: 35, y2: 55 }, // Cuerpo y patas
            { x1: 70, y1: 70, x2: 65, y2: 55 }, { x1: 35, y1: 55, x2: 65, y2: 55 },
            { x1: 45, y1: 55, x2: 50, y2: 45 }, { x1: 50, y1: 45, x2: 55, y2: 55 }, // Cabeza
            { x1: 48, y1: 45, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 48, y2: 38 }, // Oreja 1
            { x1: 52, y1: 45, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 52, y2: 38 }, // Oreja 2
            { x1: 45, y1: 50, x2: 40, y2: 50 }, { x1: 45, y1: 52, x2: 40, y2: 52 }, // Bigotes izquierda
            { x1: 55, y1: 50, x2: 60, y2: 50 }, { x1: 55, y1: 52, x2: 60, y2: 52 }, // Bigotes derecha
            { x1: 65, y1: 55, x2: 75, y2: 45 } // Cola
        ],
        "MESA": [ // Mesa con patas en perspectiva
            { x1: 25, y1: 40, x2: 75, y2: 40 }, { x1: 25, y1: 40, x2: 25, y2: 45 }, // Superficie
            { x1: 75, y1: 40, x2: 75, y2: 45 }, { x1: 25, y1: 45, x2: 75, y2: 45 },
            { x1: 30, y1: 45, x2: 30, y2: 70 }, { x1: 70, y1: 45, x2: 70, y2: 70 }, // Patas delanteras
            { x1: 25, y1: 40, x2: 20, y2: 35 }, { x1: 75, y1: 40, x2: 80, y2: 35 }, // Profundidad superior
            { x1: 20, y1: 35, x2: 20, y2: 60 }, { x1: 80, y1: 35, x2: 80, y2: 60 }, // Profundidad lateral
            { x1: 20, y1: 60, x2: 25, y2: 70 }, { x1: 80, y1: 60, x2: 75, y2: 70 } // Patas traseras en perspectiva
        ],
        "SILLA": [ // Silla con respaldo, asiento y patas
            { x1: 35, y1: 40, x2: 65, y2: 40 }, { x1: 35, y1: 40, x2: 35, y2: 60 }, // Respaldo
            { x1: 65, y1: 40, x2: 65, y2: 60 }, { x1: 35, y1: 60, x2: 65, y2: 60 }, // Asiento
            { x1: 38, y1: 60, x2: 38, y2: 75 }, { x1: 62, y1: 60, x2: 62, y2: 75 }, // Patas delanteras
            { x1: 35, y1: 60, x2: 32, y2: 65 }, { x1: 32, y1: 65, x2: 32, y2: 75 }, // Pata trasera izq en perspectiva
            { x1: 65, y1: 60, x2: 68, y2: 65 }, { x1: 68, y1: 65, x2: 68, y2: 75 }  // Pata trasera der en perspectiva
        ],
        "LIBRO": [ // Libro abierto con páginas
            { x1: 30, y1: 40, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 50, y2: 70 }, // Lado izquierdo
            { x1: 50, y1: 70, x2: 30, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 40 },
            { x1: 50, y1: 30, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 70, y2: 60 }, // Lado derecho
            { x1: 70, y1: 60, x2: 50, y2: 70 },
            { x1: 40, y1: 45, x2: 48, y2: 35 }, { x1: 48, y1: 35, x2: 48, y2: 65 }, // Páginas izquierda
            { x1: 52, y1: 35, x2: 60, y2: 45 }, { x1: 52, y1: 65, x2: 60, y2: 55 } // Páginas derecha
        ],
        "TAZA": [ // Taza con asa y base
            { x1: 40, y1: 40, x2: 60, y2: 40 }, { x1: 40, y1: 40, x2: 38, y2: 65 }, // Cuerpo
            { x1: 60, y1: 40, x2: 62, y2: 65 }, { x1: 38, y1: 65, x2: 62, y2: 65 },
            { x1: 62, y1: 45, x2: 68, y2: 45 }, { x1: 68, y1: 45, x2: 68, y2: 55 }, // Asa
            { x1: 68, y1: 55, x2: 62, y2: 55 }
        ],
        "VENTANA": [ // Ventana con doble marco y cruces
            { x1: 30, y1: 30, x2: 70, y2: 30 }, { x1: 70, y1: 30, x2: 70, y2: 70 },
            { x1: 70, y1: 70, x2: 30, y2: 70 }, { x1: 30, y1: 70, x2: 30, y2: 30 }, // Marco exterior
            { x1: 35, y1: 35, x2: 65, y2: 35 }, { x1: 65, y1: 35, x2: 65, y2: 65 },
            { x1: 65, y1: 65, x2: 35, y2: 65 }, { x1: 35, y1: 65, x2: 35, y2: 35 }, // Marco interior
            { x1: 50, y1: 35, x2: 50, y2: 65 }, { x1: 35, y1: 50, x2: 70, y2: 50 } // Cruces
        ],
        "PUERTA": [ // Puerta con pomo y marco
            { x1: 40, y1: 30, x2: 60, y2: 30 }, { x1: 60, y1: 30, x2: 60, y2: 70 },
            { x1: 60, y1: 70, x2: 40, y2: 70 }, { x1: 40, y1: 70, x2: 40, y2: 30 }, // Puerta
            { x1: 38, y1: 30, x2: 38, y2: 72 }, { x1: 62, y1: 30, x2: 62, y2: 72 }, // Marco vertical
            { x1: 38, y1: 30, x2: 62, y2: 30 }, { x1: 38, y1: 72, x2: 62, y2: 72 }, // Marco horizontal
            { x1: 55, y1: 50, x2: 55, y2: 50 } // Pomo (punto)
        ],
        "CAJA": [ // Caja con tapa y perspectiva
            { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 70, y2: 60 },
            { x1: 70, y1: 60, x2: 30, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 40 }, // Frente
            { x1: 70, y1: 40, x2: 80, y2: 30 }, { x1: 80, y1: 30, x2: 40, y2: 30 }, // Tapa
            { x1: 80, y1: 30, x2: 80, y2: 50 }, { x1: 80, y1: 50, x2: 70, y2: 60 }, // Lado derecho
            { x1: 40, y1: 30, x2: 30, y2: 40 } // Lado izquierdo (oculto)
        ],
        "BOTELLA": [ // Botella con cuello, cuerpo y base
            { x1: 45, y1: 25, x2: 55, y2: 25 }, // Boca
            { x1: 45, y1: 25, x2: 40, y2: 35 }, { x1: 55, y1: 25, x2: 60, y2: 35 }, // Cuello
            { x1: 40, y1: 35, x2: 40, y2: 70 }, { x1: 60, y1: 35, x2: 60, y2: 70 }, // Cuerpo
            { x1: 38, y1: 70, x2: 62, y2: 70 }  // Base (curva conceptual)
        ],
        "CAMISA": [ // Camisa con mangas y botones
            { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 30, y1: 40, x2: 25, y2: 50 }, // Hombros
            { x1: 70, y1: 40, x2: 75, y2: 50 }, { x1: 25, y1: 50, x2: 25, y2: 70 }, // Cuerpo
            { x1: 75, y1: 50, x2: 75, y2: 70 }, { x1: 25, y1: 70, x2: 75, y2: 70 },
            { x1: 45, y1: 40, x2: 55, y2: 40 }, // Cuello
            { x1: 50, y1: 45, x2: 50, y2: 45 }, { x1: 50, y1: 50, x2: 50, y2: 50 }, // Botones
            { x1: 50, y1: 55, x2: 50, y2: 55 }, { x1: 50, y1: 60, x2: 50, y2: 60 }
        ],
        "ZAPATO": [ // Zapato con cordones
            { x1: 20, y1: 60, x2: 70, y2: 60 }, { x1: 20, y1: 60, x2: 25, y2: 70 }, // Base
            { x1: 70, y1: 60, x2: 75, y2: 70 }, { x1: 25, y1: 70, x2: 75, y2: 70 },
            { x1: 30, y1: 60, x2: 40, y2: 55 }, { x1: 40, y1: 55, x2: 50, y2: 55 }, // Parte superior
            { x1: 35, y1: 57, x2: 45, y2: 57 }, { x1: 40, y1: 54, x2: 50, y2: 54 } // Cordones
        ],
        "AGUA": [ // Gotas de agua y superficie
            { type: "circle", x1: 50, y1: 40, radius: 5 }, // Gota 1
            { type: "circle", x1: 40, y1: 50, radius: 4 }, // Gota 2
            { type: "circle", x1: 60, y1: 55, radius: 3 }, // Gota 3
            { x1: 20, y1: 70, x2: 80, y2: 70 }, { x1: 25, y1: 65, x2: 75, y2: 65 } // Superficie
        ],
        "FUEGO": [ // Llama con base
            { x1: 50, y1: 75, x2: 40, y2: 65 }, { x1: 40, y1: 65, x2: 45, y2: 50 }, // Llama
            { x1: 45, y1: 50, x2: 50, y2: 40 }, { x1: 50, y1: 40, x2: 55, y2: 50 },
            { x1: 55, y1: 50, x2: 60, y2: 65 }, { x1: 60, y1: 65, x2: 50, y2: 75 },
            { x1: 40, y1: 75, x2: 60, y2: 75 } // Base
        ],
        "VIENTO": [ // Líneas de viento con remolino
            { x1: 20, y1: 50, x2: 80, y2: 50 }, { x1: 25, y1: 55, x2: 85, y2: 55 },
            { x1: 30, y1: 60, x2: 90, y2: 60 },
            { type: "circle", x1: 30, y1: 45, radius: 5 }, { type: "circle", x1: 70, y1: 45, radius: 5 } // Remolinos
        ],
        "TIERRA": [ // Horizonte montañoso con árbol
            { x1: 20, y1: 70, x2: 30, y2: 65 }, { x1: 30, y1: 65, x2: 40, y2: 70 },
            { x1: 40, y1: 70, x2: 50, y2: 60 }, { x1: 50, y1: 60, x2: 60, y2: 70 },
            { x1: 60, y1: 70, x2: 70, y2: 65 }, { x1: 70, y1: 65, x2: 80, y2: 70 },
            { x1: 50, y1: 60, x2: 50, y2: 50 }, { x1: 45, y1: 50, x2: 55, y2: 50 } // Árbol en el horizonte
        ],
        "NUBE": [ // Nube con forma y sombra
            { x1: 30, y1: 40, x2: 40, y2: 35 }, { x1: 40, y1: 35, x2: 50, y2: 38 },
            { x1: 50, y1: 38, x2: 60, y2: 35 }, { x1: 60, y1: 35, x2: 70, y2: 40 },
            { x1: 70, y1: 40, x2: 65, y2: 50 }, { x1: 65, y1: 50, x2: 50, y2: 55 },
            { x1: 50, y1: 55, x2: 35, y2: 50 }, { x1: 35, y1: 50, x2: 30, y2: 40 },
            { x1: 35, y1: 45, x2: 45, y2: 48 }, { x1: 45, y1: 48, x2: 55, y2: 45 }, // Sombra interior
            { x1: 55, y1: 45, x2: 65, y2: 48 }
        ],
        "LUNA": [ // Luna creciente con cráteres
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Círculo exterior
            { type: "circle", x1: 45, y1: 50, radius: 15 }, // Círculo interior
            { type: "circle", x1: 55, y1: 45, radius: 3 }, // Cráter 1
            { type: "circle", x1: 58, y1: 55, radius: 2 }  // Cráter 2
        ],
        "ESTRELLA": [ // Estrella de 5 puntas con brillo
            { x1: 50, y1: 20, x2: 60, y2: 40 }, { x1: 60, y1: 40, x2: 80, y2: 45 },
            { x1: 80, y1: 45, x2: 65, y2: 60 }, { x1: 65, y1: 60, x2: 70, y2: 80 },
            { x1: 70, y1: 80, x2: 50, y2: 70 }, { x1: 50, y1: 70, x2: 30, y2: 80 },
            { x1: 30, y1: 80, x2: 35, y2: 60 }, { x1: 35, y1: 60, x2: 20, y2: 45 },
            { x1: 20, y1: 45, x2: 40, y2: 40 }, { x1: 40, y1: 40, x2: 50, y2: 20 },
            { x1: 50, y1: 20, x2: 50, y2: 25 }, { x1: 55, y1: 45, x2: 60, y2: 50 } // Detalles de brillo
        ],
        "AUTO": [ // Auto con ruedas, ventanas y faros
            { x1: 20, y1: 70, x2: 80, y2: 70 }, { x1: 20, y1: 70, x2: 20, y2: 60 },
            { x1: 80, y1: 70, x2: 80, y2: 60 }, { x1: 20, y1: 60, x2: 30, y2: 50 },
            { x1: 30, y1: 50, x2: 70, y2: 50 }, { x1: 70, y1: 50, x2: 80, y2: 60 },
            { type: "circle", x1: 30, y1: 70, radius: 5 }, { type: "circle", x1: 70, y1: 70, radius: 5 }, // Ruedas
            { x1: 35, y1: 55, x2: 45, y2: 55 }, { x1: 45, y1: 55, x2: 45, y2: 65 }, // Ventana delantera
            { x1: 45, y1: 65, x2: 35, y2: 65 }, { x1: 35, y1: 65, x2: 35, y2: 55 },
            { x1: 60, y1: 55, x2: 70, y2: 55 }, { x1: 70, y1: 55, x2: 70, y2: 65 }, // Ventana trasera
            { x1: 70, y1: 65, x2: 60, y2: 65 }, { x1: 60, y1: 65, x2: 60, y2: 55 },
            { x1: 22, y1: 67, x2: 25, y2: 67 }, { x1: 77, y1: 67, x2: 79, y2: 67 } // Faros
        ],
        "BICICLETA": [ // Bicicleta con dos ruedas, cuadro, asiento y manillar
            { type: "circle", x1: 35, y1: 65, radius: 10 }, { type: "circle", x1: 65, y1: 65, radius: 10 }, // Ruedas
            { x1: 35, y1: 65, x2: 50, y2: 55 }, { x1: 50, y1: 55, x2: 65, y2: 65 }, // Cuadro principal
            { x1: 50, y1: 55, x2: 50, y2: 50 }, // Asiento
            { x1: 35, y1: 65, x2: 40, y2: 50 }, { x1: 40, y1: 50, x2: 45, y2: 50 }, // Manillar
            { x1: 65, y1: 65, x2: 55, y2: 50 }, { x1: 55, y1: 50, x2: 50, y2: 50 } // Pedal
        ],
        "BARCO": [ // Barco con mástil, vela y bandera
            { x1: 20, y1: 70, x2: 80, y2: 70 }, { x1: 20, y1: 70, x2: 30, y2: 60 },
            { x1: 80, y1: 70, x2: 70, y2: 60 }, { x1: 30, y1: 60, x2: 70, y2: 60 }, // Casco
            { x1: 50, y1: 60, x2: 50, y2: 40 }, // Mástil
            { x1: 50, y1: 40, x2: 65, y2: 50 }, { x1: 65, y1: 50, x2: 50, y2: 60 }, // Vela
            { x1: 50, y1: 40, x2: 55, y2: 35 }, { x1: 55, y1: 35, x2: 50, y2: 30 } // Bandera
        ],
        "PESCADO": [ // Pescado con aletas, ojo y boca
            { x1: 30, y1: 50, x2: 70, y2: 50 }, { x1: 70, y1: 50, x2: 80, y2: 45 },
            { x1: 80, y1: 45, x2: 70, y2: 55 }, { x1: 70, y1: 55, x2: 30, y2: 50 }, // Cuerpo
            { x1: 75, y1: 45, x2: 85, y2: 40 }, { x1: 85, y1: 40, x2: 85, y2: 60 }, // Cola
            { x1: 85, y1: 60, x2: 75, y2: 55 },
            { x1: 40, y1: 47, x2: 40, y2: 47 }, // Ojo (punto)
            { x1: 35, y1: 50, x2: 40, y2: 53 } // Boca
        ],
        "MANZANA": [ // Manzana con tallo y hoja
            { type: "circle", x1: 50, y1: 50, radius: 20 },
            { x1: 48, y1: 30, x2: 52, y2: 30 }, // Tallito
            { x1: 52, y1: 30, x2: 55, y2: 35 }, { x1: 55, y1: 35, x2: 52, y2: 38 } // Hoja
        ],
        "PLATO": [ // Plato con borde y centro
            { type: "circle", x1: 50, y1: 50, radius: 25 },
            { type: "circle", x1: 50, y1: 50, radius: 20 }
        ],
        "CEREBRO": [ // Cerebro con hemisferios y surcos
            { x1: 30, y1: 40, x2: 40, y2: 30 }, { x1: 40, y1: 30, x2: 60, y2: 30 },
            { x1: 60, y1: 30, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 60, y2: 50 },
            { x1: 60, y1: 50, x2: 40, y2: 50 }, { x1: 40, y1: 50, x2: 30, y2: 40 },
            { x1: 50, y1: 30, x2: 50, y2: 50 }, // Surco central
            { x1: 35, y1: 35, x2: 45, y2: 45 }, { x1: 55, y1: 35, x2: 65, y2: 45 } // Surcos laterales
        ],
        "CORAZON": [ // Corazón con curvas y base
            { x1: 50, y1: 75, x2: 30, y2: 50 }, { x1: 30, y1: 50, x2: 30, y2: 40 },
            { x1: 30, y1: 40, x2: 40, y2: 30 }, { x1: 40, y1: 30, x2: 50, y2: 40 },
            { x1: 50, y1: 40, x2: 60, y2: 30 }, { x1: 60, y1: 30, x2: 70, y2: 40 },
            { x1: 70, y1: 40, x2: 70, y2: 50 }, { x1: 70, y1: 50, x2: 50, y2: 75 }
        ],
        "MANO": [ // Mano con dedos y palma
            { x1: 40, y1: 70, x2: 40, y2: 40 }, { x1: 40, y1: 40, x2: 45, y2: 30 }, // Pulgar
            { x1: 45, y1: 30, x2: 50, y2: 40 },
            { x1: 50, y1: 40, x2: 50, y2: 25 }, { x1: 50, y1: 25, x2: 55, y2: 25 }, { x1: 55, y1: 25, x2: 55, y2: 40 }, // Índice
            { x1: 55, y1: 40, x2: 60, y2: 25 }, { x1: 60, y1: 25, x2: 65, y2: 25 }, { x1: 65, y1: 25, x2: 65, y2: 40 }, // Medio
            { x1: 65, y1: 40, x2: 70, y2: 30 }, { x1: 70, y1: 30, x2: 75, y2: 35 }, { x1: 75, y1: 35, x2: 75, y2: 60 }, // Anular
            { x1: 40, y1: 70, x2: 75, y2: 70 } // Palma
        ],
        "OJO": [ // Ojo con iris, pupila, y pestañas
            { type: "circle", x1: 50, y1: 50, radius: 10 }, // Iris
            { type: "circle", x1: 50, y1: 50, radius: 3 }, // Pupila
            { x1: 30, y1: 50, x2: 70, y2: 50 }, // Línea central del ojo
            { x1: 35, y1: 45, x2: 65, y2: 45 }, { x1: 35, y1: 55, x2: 65, y2: 55 }, // Párpados
            { x1: 35, y1: 45, x2: 38, y2: 40 }, { x1: 45, y1: 45, x2: 48, y2: 40 } // Pestañas
        ],
        "BOCA": [ // Boca con labios y comisuras
            { x1: 35, y1: 50, x2: 65, y2: 50 }, // Línea de la boca
            { x1: 38, y1: 45, x2: 45, y2: 50 }, { x1: 55, y1: 50, x2: 62, y2: 45 }, // Labio superior
            { x1: 38, y1: 55, x2: 45, y2: 50 }, { x1: 55, y1: 50, x2: 62, y2: 55 }  // Labio inferior
        ],
        "NARIZ": [ // Nariz detallada
            { x1: 50, y1: 40, x2: 45, y2: 55 }, { x1: 45, y1: 55, x2: 55, y2: 55 }, // Puente y base
            { x1: 55, y1: 55, x2: 50, y2: 40 },
            { x1: 47, y1: 55, x2: 47, y2: 58 }, { x1: 53, y1: 55, x2: 53, y2: 58 } // Orificios
        ],
        "OREJA": [ // Oreja con contorno y detalles internos
            { x1: 50, y1: 40, x2: 40, y2: 50 }, { x1: 40, y1: 50, x2: 45, y2: 60 },
            { x1: 45, y1: 60, x2: 55, y2: 60 }, { x1: 55, y1: 60, x2: 60, y2: 50 },
            { x1: 60, y1: 50, x2: 50, y1: 40 }, // Contorno exterior
            { x1: 47, y1: 45, x2: 43, y2: 50 }, { x1: 43, y1: 50, x2: 48, y2: 55 }, // Detalles internos
            { x1: 52, y1: 45, x2: 57, y2: 50 }, { x1: 57, y1: 50, x2: 52, y2: 55 }
        ],
        "DIENTE": [ // Diente con raíz y encía
            { x1: 45, y1: 30, x2: 55, y2: 30 }, { x1: 55, y1: 30, x2: 55, y2: 60 },
            { x1: 55, y1: 60, x2: 45, y2: 60 }, { x1: 45, y1: 60, x2: 45, y2: 30 }, // Cuerpo del diente
            { x1: 45, y1: 60, x2: 40, y2: 65 }, { x1: 55, y1: 60, x2: 60, y2: 65 }, // Raíces
            { x1: 40, y1: 65, x2: 60, y2: 65 } // Encía
        ],
        "PAN": [ // Barra de pan con cortes
            { x1: 20, y1: 60, x2: 80, y2: 60 }, { x1: 20, y1: 60, x2: 25, y2: 70 }, // Base
            { x1: 80, y1: 60, x2: 75, y2: 70 }, { x1: 25, y1: 70, x2: 75, y2: 70 },
            { x1: 20, y1: 60, x2: 20, y2: 50 }, { x1: 80, y1: 60, x2: 80, y2: 50 }, // Lados
            { x1: 20, y1: 50, x2: 80, y2: 50 }, // Tapa
            { x1: 30, y1: 55, x2: 35, y2: 65 }, { x1: 40, y1: 55, x2: 45, y2: 65 }, // Cortes
            { x1: 50, y1: 55, x2: 55, y2: 65 }, { x1: 60, y1: 55, x2: 65, y2: 65 }
        ],
        "QUESO": [ // Trozo de queso triangular con agujeros
            { x1: 30, y1: 70, x2: 70, y2: 70 }, { x1: 70, y1: 70, x2: 50, y2: 30 }, // Triángulo
            { x1: 50, y1: 30, x2: 30, y2: 70 },
            { type: "circle", x1: 45, y1: 55, radius: 5 }, // Agujero 1
            { type: "circle", x1: 58, y1: 60, radius: 4 }, // Agujero 2
            { type: "circle", x1: 40, y1: 65, radius: 3 }  // Agujero 3
        ],
        "HUEVO": [ // Huevo con yema
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno
            { type: "circle", x1: 50, y1: 50, radius: 8 }   // Yema
        ],
        "CARNE": [ // Trozo de carne con hueso (conceptual)
            { x1: 30, y1: 50, x2: 70, y2: 50 }, { x1: 70, y1: 50, x2: 70, y2: 70 },
            { x1: 70, y1: 70, x2: 30, y2: 70 }, { x1: 30, y1: 70, x2: 30, y2: 50 }, // Contorno
            { x1: 50, y1: 50, x2: 50, y2: 40 }, { x1: 50, y1: 40, x2: 55, y2: 35 }, // Hueso (conceptual)
            { x1: 55, y1: 35, x2: 60, y2: 40 }, { x1: 60, y1: 40, x2: 60, y2: 50 }
        ],
        "POLLO": [ // Pollo asado simplificado
            { x1: 30, y1: 60, x2: 70, y2: 60 }, { x1: 70, y1: 60, x2: 70, y2: 50 },
            { x1: 70, y1: 50, x2: 60, y2: 45 }, { x1: 60, y1: 45, x2: 40, y2: 45 },
            { x1: 40, y1: 45, x2: 30, y2: 50 }, { x1: 30, y1: 50, x2: 30, y2: 60 }, // Cuerpo
            { x1: 30, y1: 55, x2: 25, y2: 50 }, { x1: 70, y1: 55, x2: 75, y2: 50 } // Patas/alas
        ],
        "ARROZ": [ // Bol de arroz con palillos
            { type: "circle", x1: 50, y1: 65, radius: 15 }, // Bol
            { x1: 40, y1: 50, x2: 40, y2: 40 }, { x1: 40, y1: 40, x2: 45, y2: 40 }, // Palillo 1
            { x1: 45, y1: 40, x2: 45, y2: 50 },
            { x1: 55, y1: 50, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 60, y2: 40 }, // Palillo 2
            { x1: 60, y1: 40, x2: 60, y2: 50 }
        ],
        "PASTA": [ // Plato de pasta con tenedor
            { type: "circle", x1: 50, y1: 65, radius: 20 }, // Plato
            { x1: 45, y1: 55, x2: 55, y2: 55 }, { x1: 50, y1: 55, x2: 50, y2: 45 }, // Tenedor
            { x1: 48, y1: 45, x2: 48, y2: 40 }, { x1: 52, y1: 45, x2: 52, y2: 40 }
        ],
        "FRUTA": [ // Canasta de frutas (conceptual)
            { x1: 30, y1: 70, x2: 70, y2: 70 }, { x1: 30, y1: 70, x2: 35, y2: 60 }, // Canasta
            { x1: 70, y1: 70, x2: 65, y2: 60 }, { x1: 35, y1: 60, x2: 65, y2: 60 },
            { type: "circle", x1: 40, y1: 55, radius: 5 }, // Fruta 1
            { type: "circle", x1: 60, y1: 55, radius: 5 }, // Fruta 2
            { type: "circle", x1: 50, y1: 45, radius: 5 }  // Fruta 3
        ],
        "UVA": [ // Racimo de uvas
            { type: "circle", x1: 50, y1: 40, radius: 5 },
            { type: "circle", x1: 45, y1: 48, radius: 5 }, { type: "circle", x1: 55, y1: 48, radius: 5 },
            { type: "circle", x1: 40, y1: 56, radius: 5 }, { type: "circle", x1: 50, y1: 56, radius: 5 },
            { type: "circle", x1: 60, y1: 56, radius: 5 },
            { x1: 50, y1: 35, x2: 50, y2: 25 } // Tallo
        ],
        "PIÑA": [ // Piña con hojas
            { x1: 40, y1: 40, x2: 60, y2: 40 }, { x1: 40, y1: 40, x2: 35, y2: 60 }, // Cuerpo ovalado
            { x1: 60, y1: 40, x2: 65, y2: 60 }, { x1: 35, y1: 60, x2: 65, y2: 60 },
            { x1: 45, y1: 35, x2: 40, y2: 25 }, { x1: 50, y1: 35, x2: 45, y2: 25 }, // Hojas
            { x1: 55, y1: 35, x2: 60, y2: 25 }
        ],
        "KIWI": [ // Kiwi cortado
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno
            { type: "circle", x1: 50, y1: 50, radius: 5 }, // Centro
            { x1: 50, y1: 30, x2: 50, y2: 70 }, { x1: 30, y1: 50, x2: 70, y2: 50 }, // Líneas internas
            { x1: 35, y1: 35, x2: 65, y2: 65 }, { x1: 35, y1: 65, x2: 65, y2: 35 }
        ],
        "CHOCOLATE": [ // Barra de chocolate
            { x1: 30, y1: 45, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 70, y2: 65 },
            { x1: 70, y1: 65, x2: 30, y2: 65 }, { x1: 30, y1: 65, x2: 30, y2: 45 }, // Rectángulo base
            { x1: 35, y1: 45, x2: 35, y2: 65 }, { x1: 45, y1: 45, x2: 45, y2: 65 }, // Divisiones
            { x1: 55, y1: 45, x2: 55, y2: 65 }, { x1: 65, y1: 45, x2: 65, y2: 65 }
        ],
        "HELADO": [ // Cono de helado
            { x1: 40, y1: 70, x2: 60, y2: 70 }, { x1: 40, y1: 70, x2: 50, y2: 30 },
            { x1: 60, y1: 70, x2: 50, y2: 30 }, // Cono
            { type: "circle", x1: 50, y1: 30, radius: 15 } // Bola de helado
        ],
        "GALLETA": [ // Galleta con chispas
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno
            { type: "circle", x1: 40, y1: 45, radius: 2 }, // Chispa 1
            { type: "circle", x1: 60, y1: 45, radius: 2 }, // Chispa 2
            { type: "circle", x1: 50, y1: 58, radius: 2 }  // Chispa 3
        ],
        "CARAMELO": [ // Caramelo envuelto
            { x1: 30, y1: 50, x2: 70, y2: 50 }, // Cuerpo central
            { x1: 25, y1: 45, x2: 30, y2: 50 }, { x1: 30, y1: 50, x2: 25, y2: 55 }, // Extremo izquierdo
            { x1: 70, y1: 50, x2: 75, y2: 45 }, { x1: 75, y1: 45, x2: 70, y2: 50 }, // Extremo derecho
            { x1: 70, y1: 50, x2: 75, y2: 55 }
        ],
        "TARTA": [ // Rebanada de tarta
            { x1: 50, y1: 30, x2: 30, y2: 70 }, { x1: 30, y1: 70, x2: 70, y2: 70 },
            { x1: 70, y1: 70, x2: 50, y2: 30 }, // Triángulo
            { x1: 40, y1: 45, x2: 60, y2: 45 } // Detalle de capa
        ],
        "PIZZA": [ // Rebanada de pizza
            { x1: 50, y1: 30, x2: 30, y2: 70 }, { x1: 30, y1: 70, x2: 70, y2: 70 },
            { x1: 70, y1: 70, x2: 50, y2: 30 }, // Triángulo
            { type: "circle", x1: 40, y1: 50, radius: 3 }, // Pepperoni 1
            { type: "circle", x1: 60, y1: 55, radius: 3 }  // Pepperoni 2
        ],
        "HAMBURGUESA": [ // Hamburguesa con pan y carne
            { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 30, y1: 40, x2: 70, y2: 40 }, // Pan superior (curva conceptual)
            { x1: 30, y1: 50, x2: 70, y2: 50 }, // Carne
            { x1: 30, y1: 60, x2: 70, y2: 60 }  // Pan inferior
        ],
        "PERRITO": [ // Perrito caliente en bollo
            { x1: 30, y1: 50, x2: 70, y2: 50 }, // Salchicha
            { x1: 25, y1: 55, x2: 75, y2: 55 }, { x1: 25, y1: 55, x2: 20, y2: 65 }, // Bollo
            { x1: 75, y1: 55, x2: 80, y2: 65 }, { x1: 20, y1: 65, x2: 80, y2: 65 }
        ],
        "MAPACHE": [ // Cara de mapache
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Cabeza
            { x1: 40, y1: 45, x2: 40, y2: 55 }, { x1: 60, y1: 45, x2: 60, y2: 55 }, // Manchas de ojos
            { x1: 45, y1: 40, x2: 50, y2: 35 }, { x1: 50, y1: 35, x2: 55, y2: 40 }, // Orejas
            { x1: 50, y1: 55, x2: 50, y2: 58 } // Nariz
        ],
        "ZORRO": [ // Cara de zorro
            { x1: 50, y1: 50, x2: 50, y2: 50 }, { x1: 40, y1: 55, x2: 50, y2: 40 }, // Hocico
            { x1: 50, y1: 40, x2: 60, y2: 55 }, { x1: 45, y1: 35, x2: 50, y2: 30 }, // Orejas
            { x1: 50, y1: 30, x2: 55, y2: 35 }
        ],
        "LOBO": [ // Cara de lobo aullando
            { x1: 50, y1: 50, x2: 50, y2: 50 }, { x1: 40, y1: 55, x2: 50, y2: 40 },
            { x1: 50, y1: 40, x2: 60, y2: 55 }, // Hocico
            { x1: 45, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 55, y2: 35 }, // Orejas
            { x1: 50, y1: 60, x2: 50, y2: 70 } // Boca abierta (aullido)
        ],
        "OSO": [ // Cara de oso con orejas redondas
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Cabeza
            { type: "circle", x1: 40, y1: 40, radius: 5 }, { type: "circle", x1: 60, y1: 40, radius: 5 }, // Orejas
            { x1: 45, y1: 55, x2: 55, y2: 55 }, { x1: 50, y1: 55, x2: 50, y2: 60 } // Hocico
        ],
        "TIGRE": [ // Cara de tigre con rayas
            { type: "circle", x1: 50, y1: 50, radius: 25 }, // Cabeza
            { x1: 40, y1: 40, x2: 45, y2: 40 }, { x1: 38, y1: 48, x2: 43, y2: 48 }, // Rayas
            { x1: 60, y1: 40, x2: 55, y2: 40 }, { x1: 62, y1: 48, x2: 57, y2: 48 }
        ],
        "LEON": [ // Cara de león con melena (conceptual)
            { type: "circle", x1: 50, y1: 50, radius: 25 }, // Cabeza
            { type: "circle", x1: 50, y1: 50, radius: 15 }, // Cara interna
            { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 30, y1: 60, x2: 70, y2: 60 } // Melena (líneas)
        ],
        "ELEFANTE": [ // Elefante con trompa y orejas grandes
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Cabeza
            { x1: 50, y1: 50, x2: 60, y2: 65 }, { x1: 60, y1: 65, x2: 55, y2: 75 }, // Trompa
            { x1: 35, y1: 40, x2: 25, y2: 55 }, { x1: 25, y2: 55, x2: 35, y2: 65 }, // Oreja 1
            { x1: 65, y1: 40, x2: 75, y2: 55 }, { x1: 75, y2: 55, x2: 65, y2: 65 }  // Oreja 2
        ],
        "JIRAFA": [ // Jirafa con cuello largo y manchas
            { x1: 50, y1: 80, x2: 50, y2: 30 }, { x1: 48, y1: 80, x2: 48, y2: 30 }, // Cuello
            { type: "circle", x1: 50, y1: 25, radius: 8 }, // Cabeza
            { x1: 40, y1: 60, x2: 45, y2: 65 }, { x1: 55, y1: 60, x2: 60, y2: 65 } // Manchas
        ],
        "MONO": [ // Mono con cola y orejas
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Cuerpo
            { type: "circle", x1: 50, y1: 30, radius: 10 }, // Cabeza
            { type: "circle", x1: 40, y1: 25, radius: 5 }, { type: "circle", x1: 60, y1: 25, radius: 5 }, // Orejas
            { x1: 60, y1: 60, x2: 70, y2: 50 }, { x1: 70, y2: 50, x2: 75, y2: 60 } // Cola
        ],
        "KOALA": [ // Koala con orejas grandes y nariz
            { type: "circle", x1: 50, y1: 50, radius: 25 }, // Cuerpo
            { type: "circle", x1: 40, y1: 40, radius: 10 }, { type: "circle", x1: 60, y1: 40, radius: 10 }, // Orejas
            { x1: 50, y1: 55, x2: 50, y2: 58 } // Nariz
        ],
        "PINGUINO": [ // Pingüino con cuerpo ovalado
            { x1: 50, y1: 80, x2: 50, y2: 30 }, { x1: 40, y1: 80, x2: 40, y2: 35 }, { x1: 60, y1: 80, x2: 60, y2: 35 }, // Cuerpo
            { x1: 40, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 60, y2: 35 },
            { x1: 45, y1: 45, x2: 55, y2: 45 }, { x1: 50, y1: 45, x2: 50, y2: 50 } // Ojos y pico
        ],
        "BUHO": [ // Búho con ojos grandes
            { type: "circle", x1: 50, y1: 50, radius: 25 }, // Cuerpo
            { type: "circle", x1: 40, y1: 40, radius: 8 }, { type: "circle", x1: 60, y1: 40, radius: 8 }, // Ojos
            { x1: 50, y1: 48, x2: 50, y2: 52 } // Pico
        ],
        "AGUILA": [ // Águila con alas
            { x1: 50, y1: 40, x2: 50, y2: 30 }, { x1: 40, y1: 50, x2: 20, y2: 45 }, { x1: 20, y1: 45, x2: 45, y2: 40 }, // Cuerpo y ala izq.
            { x1: 60, y1: 50, x2: 80, y2: 45 }, { x1: 80, y1: 45, x2: 55, y2: 40 } // Ala der.
        ],
        "DELFIN": [ // Delfín saltando
            { x1: 30, y1: 60, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 75, y2: 50 },
            { x1: 75, y2: 50, x2: 70, y2: 60 }, { x1: 70, y2: 60, x2: 30, y2: 60 }, // Cuerpo
            { x1: 60, y1: 40, x2: 60, y2: 30 } // Aleta
        ],
        "BALLENA": [ // Ballena con cola
            { x1: 20, y1: 60, x2: 80, y2: 60 }, { x1: 20, y1: 60, x2: 25, y2: 50 }, // Cuerpo
            { x1: 80, y1: 60, x2: 75, y2: 50 }, { x1: 25, y1: 50, x2: 75, y2: 50 },
            { x1: 70, y1: 55, x2: 80, y2: 45 }, { x1: 80, y2: 45, x2: 80, y2: 65 }, { x1: 80, y2: 65, x2: 70, y2: 55 } // Cola
        ],
        "TIBURON": [ // Tiburón con aletas y dientes (conceptual)
            { x1: 20, y1: 60, x2: 80, y2: 55 }, { x1: 80, y1: 55, x2: 75, y2: 65 },
            { x1: 75, y2: 65, x2: 20, y2: 60 }, // Cuerpo
            { x1: 50, y1: 50, x2: 50, y2: 40 }, { x1: 45, y1: 40, x2: 55, y2: 40 } // Aleta dorsal
        ],
        "PULPO": [ // Pulpo con tentáculos
            { type: "circle", x1: 50, y1: 40, radius: 15 }, // Cabeza
            { x1: 40, y1: 55, x2: 30, y2: 65 }, { x1: 30, y2: 65, x2: 35, y2: 70 }, // Tentáculo 1
            { x1: 50, y1: 55, x2: 45, y2: 65 }, { x1: 45, y2: 65, x2: 50, y2: 70 }, // Tentáculo 2
            { x1: 60, y1: 55, x2: 70, y2: 65 }, { x1: 70, y2: 65, x2: 65, y2: 70 }  // Tentáculo 3
        ],
        "CANGREJO": [ // Cangrejo con pinzas
            { x1: 30, y1: 60, x2: 70, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 50 },
            { x1: 70, y1: 60, x2: 70, y2: 50 }, { x1: 30, y1: 50, x2: 70, y2: 50 }, // Cuerpo
            { x1: 25, y1: 55, x2: 15, y2: 50 }, { x1: 15, y1: 50, x2: 20, y2: 45 }, // Pinza 1
            { x1: 75, y1: 55, x2: 85, y2: 50 }, { x1: 85, y1: 50, x2: 80, y2: 45 }  // Pinza 2
        ],
        "MEDUSA": [ // Medusa con tentáculos
            { type: "circle", x1: 50, y1: 40, radius: 15 }, // Cuerpo superior
            { x1: 40, y1: 55, x2: 40, y2: 70 }, { x1: 50, y1: 55, x2: 50, y2: 70 }, // Tentáculos
            { x1: 60, y1: 55, x2: 60, y2: 70 }
        ],
        "DINOSAURIO": [ // Contorno de dinosaurio (cuello largo)
            { x1: 20, y1: 70, x2: 60, y2: 70 }, { x1: 60, y1: 70, x2: 65, y2: 60 },
            { x1: 65, y1: 60, x2: 60, y2: 50 }, { x1: 60, y1: 50, x2: 50, y2: 40 },
            { x1: 50, y1: 40, x2: 40, y2: 50 }, { x1: 40, y1: 50, x2: 30, y2: 60 },
            { x1: 30, y1: 60, x2: 20, y2: 70 }
        ],
        "DRAGON": [ // Contorno de dragón (alas y cola)
            { x1: 30, y1: 60, x2: 70, y2: 60 }, { x1: 70, y1: 60, x2: 65, y2: 40 },
            { x1: 65, y1: 40, x2: 35, y2: 40 }, { x1: 35, y1: 40, x2: 30, y2: 60 }, // Cuerpo
            { x1: 40, y1: 40, x2: 30, y2: 30 }, { x1: 30, y1: 30, x2: 40, y2: 25 }, // Ala izq.
            { x1: 60, y1: 40, x2: 70, y2: 30 }, { x1: 70, y1: 30, x2: 60, y2: 25 }, // Ala der.
            { x1: 70, y1: 60, x2: 80, y2: 55 }, { x1: 80, y1: 55, x2: 75, y2: 65 }  // Cola
        ],
        "UNICORNIO": [ // Unicornio (cabeza y cuerno)
            { x1: 50, y1: 50, x2: 50, y2: 50 }, { x1: 40, y1: 55, x2: 50, y2: 40 },
            { x1: 50, y1: 40, x2: 60, y2: 55 }, // Cabeza
            { x1: 50, y1: 40, x2: 50, y2: 25 }, { x1: 48, y1: 25, x2: 52, y2: 25 } // Cuerno
        ],
        "SIRENA": [ // Sirena (cuerpo y cola)
            { x1: 50, y1: 40, x2: 50, y2: 60 }, // Cuerpo
            { x1: 45, y1: 60, x2: 40, y2: 70 }, { x1: 40, y1: 70, x2: 60, y2: 70 },
            { x1: 60, y1: 70, x2: 55, y2: 60 } // Cola
        ],
        "HADA": [ // Hada (cuerpo y alas)
            { x1: 50, y1: 40, x2: 50, y2: 60 }, // Cuerpo
            { x1: 40, y1: 50, x2: 30, y2: 45 }, { x1: 30, y1: 45, x2: 40, y2: 50 }, // Ala izq.
            { x1: 60, y1: 50, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 60, y2: 50 }  // Ala der.
        ],
        "MAGO": [ // Mago (sombrero y varita)
            { x1: 50, y1: 50, x2: 50, y2: 50 }, { x1: 40, y1: 60, x2: 60, y2: 60 },
            { x1: 45, y1: 60, x2: 50, y2: 40 }, { x1: 50, y1: 40, x2: 55, y2: 60 }, // Sombrero
            { x1: 65, y1: 50, x2: 75, y2: 45 } // Varita
        ],
        "GUERRERO": [ // Guerrero (armadura básica)
            { x1: 50, y1: 50, x2: 50, y2: 50 }, { x1: 40, y1: 60, x2: 60, y2: 60 },
            { x1: 40, y1: 60, x2: 40, y2: 40 }, { x1: 60, y1: 60, x2: 60, y2: 40 }, // Cuerpo
            { x1: 45, y1: 40, x2: 55, y2: 40 } // Yelmo (base)
        ],
        "CABALLERO": [ // Caballero (yelmo y espada)
            { x1: 50, y1: 50, x2: 50, y2: 50 }, { x1: 40, y1: 60, x2: 60, y2: 60 },
            { x1: 40, y1: 60, x2: 40, y2: 40 }, { x1: 60, y1: 60, x2: 60, y2: 40 }, // Cuerpo
            { x1: 45, y1: 40, x2: 55, y2: 40 }, { x1: 50, y1: 40, x2: 50, y2: 30 }, // Yelmo
            { x1: 65, y1: 50, x2: 75, y2: 40 } // Espada
        ],
        "PRINCESA": [ // Princesa (corona y vestido)
            { x1: 50, y1: 40, x2: 50, y2: 60 }, // Cuerpo
            { x1: 40, y1: 60, x2: 60, y2: 60 }, { x1: 35, y1: 60, x2: 40, y2: 70 }, // Vestido
            { x1: 65, y1: 60, x2: 60, y2: 70 }, { x1: 35, y1: 70, x2: 65, y2: 70 },
            { x1: 45, y1: 35, x2: 55, y2: 35 }, { x1: 48, y1: 35, x2: 50, y2: 30 }, // Corona
            { x1: 50, y1: 30, x2: 52, y2: 35 }
        ],
        "REINA": [ // Reina (corona grande)
            { x1: 50, y1: 40, x2: 50, y2: 60 }, // Cuerpo
            { x1: 40, y1: 60, x2: 60, y2: 60 }, { x1: 35, y1: 60, x2: 40, y2: 70 },
            { x1: 65, y1: 60, x2: 60, y2: 70 }, { x1: 35, y1: 70, x2: 65, y2: 70 },
            { x1: 40, y1: 35, x2: 60, y2: 35 }, { x1: 42, y1: 35, x2: 45, y2: 30 }, // Corona grande
            { x1: 45, y1: 30, x2: 50, y2: 32 }, { x1: 50, y1: 32, x2: 55, y2: 30 },
            { x1: 55, y1: 30, x2: 58, y2: 35 }, { x1: 58, y1: 35, x2: 60, y2: 35 }
        ],
        "REY": [ // Rey (corona y cetro)
            { x1: 50, y1: 40, x2: 50, y2: 60 }, // Cuerpo
            { x1: 40, y1: 60, x2: 60, y2: 60 }, { x1: 40, y1: 60, x2: 40, y2: 70 },
            { x1: 60, y1: 60, x2: 60, y2: 70 }, { x1: 40, y1: 70, x2: 60, y2: 70 },
            { x1: 45, y1: 35, x2: 55, y2: 35 }, { x1: 48, y1: 35, x2: 50, y2: 30 }, // Corona
            { x1: 50, y1: 30, x2: 52, y2: 35 },
            { x1: 65, y1: 50, x2: 75, y2: 40 }, { x1: 75, y1: 40, x2: 78, y2: 43 } // Cetro
        ],
        "CASTILLO": [ // Castillo con almenas y torre
            { x1: 20, y1: 70, x2: 80, y2: 70 }, { x1: 20, y1: 70, x2: 20, y2: 40 },
            { x1: 80, y1: 70, x2: 80, y2: 40 }, { x1: 20, y1: 40, x2: 80, y2: 40 }, // Base
            { x1: 20, y1: 40, x2: 20, y2: 35 }, { x1: 25, y1: 35, x2: 25, y2: 40 }, // Almenas
            { x1: 30, y1: 40, x2: 30, y2: 35 }, { x1: 35, y1: 35, x2: 35, y2: 40 },
            { x1: 40, y1: 40, x2: 40, y2: 35 }, { x1: 45, y1: 35, x2: 45, y2: 40 },
            { x1: 50, y1: 40, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 60, y2: 30 }, // Torre
            { x1: 60, y1: 30, x2: 60, y2: 40 }, { x1: 55, y1: 30, x2: 55, y2: 25 } // Almena de torre
        ],
        "ESPADA": [ // Espada con empuñadura
            { x1: 50, y1: 20, x2: 50, y2: 70 }, // Hoja
            { x1: 45, y1: 60, x2: 55, y2: 60 }, // Guarda
            { x1: 48, y1: 70, x2: 52, y2: 70 }, { x1: 48, y1: 70, x2: 48, y2: 75 }, // Empuñadura
            { x1: 52, y1: 70, x2: 52, y2: 75 }, { x1: 48, y1: 75, x2: 52, y2: 75 }
        ],
        "ESCUDO": [ // Escudo medieval
            { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 70, y2: 60 },
            { x1: 70, y1: 60, x2: 50, y2: 70 }, { x1: 50, y1: 70, x2: 30, y2: 60 }, // Contorno
            { x1: 30, y1: 60, x2: 30, y2: 40 },
            { x1: 40, y1: 45, x2: 60, y2: 45 }, { x1: 50, y1: 45, x2: 50, y2: 65 } // Cruz (blasón)
        ],
        "ARCO": [ // Arco y flecha
            { x1: 30, y1: 60, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 70, y2: 60 }, // Arco
            { x1: 30, y1: 60, x2: 70, y2: 60 }, // Cuerda
            { x1: 50, y1: 45, x2: 80, y2: 45 }, { x1: 80, y1: 45, x2: 75, y2: 40 }, // Flecha
            { x1: 80, y1: 45, x2: 75, y2: 50 }
        ],
        "FLECHA": [ // Flecha con punta y cola
            { x1: 20, y1: 50, x2: 80, y2: 50 }, // Cuerpo
            { x1: 75, y1: 45, x2: 80, y2: 50 }, { x1: 80, y1: 50, x2: 75, y2: 55 }, // Punta
            { x1: 25, y1: 45, x2: 20, y2: 50 }, { x1: 20, y1: 50, x2: 25, y2: 55 } // Cola
        ],
        "POCION": [ // Frasco de poción
            { x1: 40, y1: 70, x2: 60, y2: 70 }, { x1: 40, y1: 70, x2: 40, y2: 50 },
            { x1: 60, y1: 70, x2: 60, y2: 50 }, { x1: 40, y1: 50, x2: 60, y2: 50 }, // Cuerpo
            { x1: 45, y1: 50, x2: 45, y2: 40 }, { x1: 55, y1: 50, x2: 55, y2: 40 }, // Cuello
            { x1: 48, y1: 40, x2: 52, y2: 40 } // Tapa
        ],
        "ANILLO": [ // Anillo con gema
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Anillo
            { x1: 45, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 55, y2: 35 } // Gema (triángulo)
        ],
        "COLLAR": [ // Collar con pendiente
            { x1: 30, y1: 40, x2: 70, y2: 40 }, // Cadena
            { x1: 45, y1: 40, x2: 50, y2: 50 }, { x1: 50, y1: 50, x2: 55, y2: 40 } // Pendiente (triángulo)
        ],
        "CORONA": [ // Corona con puntas
            { x1: 30, y1: 60, x2: 70, y2: 60 }, // Base
            { x1: 30, y1: 60, x2: 35, y2: 45 }, { x1: 35, y1: 45, x2: 40, y2: 60 }, // Punta 1
            { x1: 45, y1: 60, x2: 50, y2: 45 }, { x1: 50, y1: 45, x2: 55, y2: 60 }, // Punta 2
            { x1: 60, y1: 60, x2: 65, y2: 45 }, { x1: 65, y1: 45, x2: 70, y2: 60 }  // Punta 3
        ],
        "GEMA": [ // Gema facetada
            { x1: 50, y1: 30, x2: 30, y2: 50 }, { x1: 30, y1: 50, x2: 50, y2: 70 },
            { x1: 50, y1: 70, x2: 70, y2: 50 }, { x1: 70, y1: 50, x2: 50, y2: 30 }, // Contorno
            { x1: 50, y1: 30, x2: 50, y2: 70 }, { x1: 30, y1: 50, x2: 70, y2: 50 } // Facetas
        ],
        "TESORO": [ // Cofre del tesoro
            { x1: 30, y1: 60, x2: 70, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 40 }, // Base
            { x1: 70, y1: 60, x2: 70, y2: 40 }, { x1: 30, y1: 40, x2: 70, y2: 40 },
            { x1: 30, y1: 40, x2: 35, y2: 35 }, { x1: 70, y1: 40, x2: 75, y2: 35 }, // Tapa
            { x1: 35, y1: 35, x2: 75, y2: 35 }, { x1: 50, y1: 40, x2: 50, y2: 50 } // Cerradura
        ],
        "MONEDA": [ // Moneda con un signo de dólar
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno
            { x1: 48, y1: 40, x2: 48, y2: 60 }, { x1: 52, y1: 40, x2: 52, y2: 60 }, // Barra vertical
            { x1: 45, y1: 45, x2: 55, y2: 45 }, { x1: 45, y1: 55, x2: 55, y2: 55 } // Barras horizontales del dólar
        ],
        "MAPA": [ // Mapa enrollado
            { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 70, y2: 60 },
            { x1: 70, y1: 60, x2: 30, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 40 }, // Contorno
            { x1: 35, y1: 40, x2: 35, y2: 60 }, { x1: 65, y1: 40, x2: 65, y2: 60 } // Enrollado
        ],
        "BRUJULA": [ // Brújula con aguja
            { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno
            { x1: 50, y1: 35, x2: 50, y2: 65 }, { x1: 35, y1: 50, x2: 65, y2: 50 }, // Cruces
            { x1: 50, y1: 40, x2: 45, y2: 50 }, { x1: 45, y1: 50, x2: 50, y2: 60 }, // Aguja
            { x1: 50, y1: 60, x2: 55, y2: 50 }, { x1: 55, y1: 50, x2: 50, y2: 40 }
        ],
        "PERGAMINO": [ // Pergamino enrollado
            { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 70, y2: 60 },
            { x1: 70, y1: 60, x2: 30, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 40 }, // Contorno
            { x1: 25, y1: 40, x2: 30, y2: 45 }, { x1: 25, y1: 55, x2: 30, y2: 60 }, // Enrollado izq.
            { x1: 70, y1: 45, x2: 75, y2: 40 }, { x1: 70, y1: 55, x2: 75, y2: 60 }  // Enrollado der.
        ],
        "ANTORCHA": [ // Antorcha con llama
            { x1: 50, y1: 80, x2: 50, y2: 60 }, { x1: 48, y1: 80, x2: 52, y2: 80 }, // Palo
            { x1: 45, y1: 60, x2: 55, y2: 60 }, { x1: 45, y1: 60, x2: 40, y2: 55 }, // Base llama
            { x1: 55, y1: 60, x2: 60, y2: 55 },
            { x1: 50, y1: 50, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 50, y2: 30 }, // Llama
            { x1: 50, y1: 30, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 50, y2: 50 }
        ]
    };
    // --- FIN BASE DE DATOS DE BOCETOS DETALLADOS ---

    class IntelligentArtist extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        // Valores por defecto
        #currentBrushSize = 5;
        #currentSketchColor = "#888888";

        constructor() {
            super("Artista Inteligente", '<i class="fas fa-brain"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            this.#row1(); // Generación de Bocetos Asistida
            this.#row2(); // Limpiar Lienzo
            this.#row3(); // Configuración de Color y Tamaño del Boceto
            this.#row4(); // Lista de Bocetos Disponibles (con slider)
        }

        #row1() {
            const row = domMake.Row();
            {
                const sketchInput = domMake.Tree("input", { type: "text", placeholder: "Concepto de boceto (ej. 'árbol')" });
                const generateSketchButton = domMake.Button("Generar Boceto");
                generateSketchButton.title = "Dibuja un boceto predefinido para la palabra ingresada.";

                generateSketchButton.addEventListener("click", () => {
                    this.simulateAISketch(sketchInput.value.toUpperCase()); // Convertir a mayúsculas
                });

                row.appendAll(sketchInput, generateSketchButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        #row2() {
            const row = domMake.Row();
            {
                const clearCanvasButton = domMake.Button("Limpiar Lienzo");
                clearCanvasButton.title = "Limpia el lienzo con una línea blanca muy grande.";

                clearCanvasButton.addEventListener("click", () => {
                    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
                    if (botManager && botManager.children.length > 0) {
                        const activeBot = botManager.children[0].bot; // Usar el primer bot activo
                        if (activeBot && activeBot.getReadyState()) {
                            // Dibuja dos líneas blancas que cubren todo el canvas con un grosor muy grande
                            activeBot.emit("line", -1, 0, 0, 100, 100, true, 900, "#FFFFFF", false); // Línea diagonal 1
                            activeBot.emit("line", -1, 100, 0, 0, 100, true, 900, "#FFFFFF", false); // Línea diagonal 2
                            this.notify("success", "El lienzo ha sido limpiado.");
                        } else {
                            this.notify("warning", "El bot seleccionado no está conectado.");
                        }
                    } else {
                        this.notify("warning", "Se necesita al menos 1 bot activo para limpiar el lienzo.");
                    }
                });
                row.appendChild(clearCanvasButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        #row3() {
            const row = domMake.Row();
            {
                const sketchColorLabel = domMake.Tree("label", {}, ["Color Boceto:"]);
                const sketchColorInput = domMake.Tree("input", { type: "color", value: this.#currentSketchColor });
                sketchColorInput.title = "Define el color del boceto.";

                sketchColorInput.addEventListener("change", (e) => {
                    this.#currentSketchColor = e.target.value;
                    this.notify("info", `Color del boceto cambiado a: ${this.#currentSketchColor}`);
                });

                const brushSizeLabel = domMake.Tree("label", {}, ["Tamaño Pincel:"]);
                const brushSizeInput = domMake.Tree("input", { type: "number", min: 1, max: 50, value: this.#currentBrushSize });
                brushSizeInput.title = "Define el tamaño del pincel para el boceto.";

                brushSizeInput.addEventListener("change", (e) => {
                    this.#currentBrushSize = parseInt(e.target.value);
                    this.notify("info", `Tamaño del pincel para boceto cambiado a: ${this.#currentBrushSize}`);
                });

                row.appendAll(sketchColorLabel, sketchColorInput, brushSizeLabel, brushSizeInput);
            }
            this.htmlElements.section.appendChild(row);
        }

        #row4() {
            const row = domMake.Row(); // Este row contendrá la etiqueta y el contenedor con scroll
            const sketchListContainer = domMake.IconList(); // IconList es un flex container
            sketchListContainer.classList.add('nowrap'); // Clase para forzar no-wrap y añadir scroll horizontal

            // Crear botones para cada palabra en la base de datos
            Object.keys(SKETCH_DATABASE).forEach(word => {
                const sketchButton = domMake.Button(word);
                sketchButton.title = `Generar boceto para: ${word}`;
                sketchButton.style.flex = '0 0 auto'; // Impide que los botones se estiren y ocupen todo el ancho disponible
                sketchButton.style.margin = '2px';
                sketchButton.style.padding = '2px 5px';
                sketchButton.style.fontSize = '0.7em';

                sketchButton.addEventListener("click", () => {
                    this.simulateAISketch(word);
                });
                sketchListContainer.appendChild(sketchButton);
            });

            // Añadir la etiqueta y el contenedor de scroll al row principal de esta sección
            row.appendAll(domMake.Tree("label", {}, ["Bocetos Rápidos (50):"]), sketchListContainer);
            this.htmlElements.section.appendChild(row);
        }

        simulateAISketch(concept) {
            const sketchData = SKETCH_DATABASE[concept];

            if (!sketchData) {
                this.notify("warning", `Boceto no disponible para: "${concept}".`);
                return;
            }

            this.notify("info", `Generando boceto para: "${concept}" (conceptual).`);
            const botManager = this.findGlobal("BotClientManager")?.siblings[0];
            if (!botManager || botManager.children.length === 0) {
                this.notify("warning", "Se necesita al menos 1 bot activo para generar bocetos.");
                return;
            }

            const activeBot = botManager.children[0].bot; // Usar el primer bot activo
            if (!activeBot || !activeBot.getReadyState()) {
                this.notify("warning", "El bot seleccionado no está conectado.");
                return;
            }

            this.notify("info", "Dibujando el boceto conceptual con el bot...");
            sketchData.forEach(line => {
                if (line.type === "circle") {
                    // Simular un círculo con múltiples líneas pequeñas
                    const centerX = line.x1;
                    const centerY = line.y1;
                    const radius = line.radius;
                    const segments = 24; // Más segmentos para un círculo más suave
                    for (let i = 0; i < segments; i++) {
                        const angle1 = (i / segments) * Math.PI * 2;
                        const angle2 = ((i + 1) / segments) * Math.PI * 2;
                        const x1_circ = centerX + radius * Math.cos(angle1);
                        const y1_circ = centerY + radius * Math.sin(angle1);
                        const x2_circ = centerX + radius * Math.cos(angle2);
                        const y2_circ = centerY + radius * Math.sin(angle2);
                        activeBot.emit("line", -1, x1_circ, y1_circ, x2_circ, y2_circ, true, this.#currentBrushSize, this.#currentSketchColor, false);
                    }
                } else {
                    activeBot.emit("line", -1, line.x1, line.y1, line.x2, line.y2, true, this.#currentBrushSize, this.#currentSketchColor, false);
                }
            });
            this.notify("success", `Boceto de "${concept}" dibujado. ¡Ahora puedes calcarlo o mejorarlo!`);
        }
    }
})("QBit");

(function TacticalBotSwarm() {
    const QBit = globalThis[arguments[0]];

    class TacticalBotSwarm extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        constructor() {
            super("Swarm de Bots Tácticos", '<i class="fas fa-users-cog"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
        }

        #loadInterface() {
            this.#row1(); // Dibujo Colaborativo por Zonas
            this.#row2(); // Bot de Adivinanza "Táctico"
            this.#row3(); // Personalidad del Bot (Velocidad de dibujo y verborrea)
        }

        #row1() {
            const row = domMake.Row();
            {
                const coordinateDrawButton = domMake.Button("Dibujo Colaborativo");
                coordinateDrawButton.title = "Divide el lienzo en zonas para que cada bot dibuje una parte (usa GhostCanvas para cargar imagen).";

                coordinateDrawButton.addEventListener("click", async () => {
                    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
                    const ghostCanvas = this.findGlobal("GhostCanvas")?.siblings[0];

                    if (!botManager || botManager.children.length === 0) {
                        this.notify("warning", "Necesitas bots activos para el dibujo colaborativo.");
                        return;
                    }
                    if (!ghostCanvas || ghostCanvas.drawingManager.pixelList.length === 0) {
                        this.notify("warning", "Carga una imagen en 'Ghost Canvas' primero.");
                        return;
                    }

                    const activeBots = botManager.children.filter(b => b.bot.getReadyState());
                    if (activeBots.length === 0) {
                        this.notify("warning", "Ningún bot activo para la colaboración.");
                        return;
                    }

                    this.notify("info", `Iniciando dibujo colaborativo con ${activeBots.length} bots.`);

                    const totalPixels = ghostCanvas.drawingManager.pixelList.length;
                    const pixelsPerBot = Math.ceil(totalPixels / activeBots.length);

                    for (let i = 0; i < activeBots.length; i++) {
                        const botInterface = activeBots[i];
                        const botPixels = ghostCanvas.drawingManager.pixelList.slice(i * pixelsPerBot, (i + 1) * pixelsPerBot);

                        if (botPixels.length > 0) {
                             // Temporarily assign a subset of pixels to each bot's internal drawing manager
                            // This is a conceptual assignment, as the GhostCanvas TaskManager handles sending
                            // We will need to modify GhostCanvas.TaskManager to distribute tasks based on available bots.
                            // For this simulation, we will just show it dividing work.
                            this.notify("log", `Bot ${botInterface.getName()} asignado a ${botPixels.length} píxeles.`);

                            // For a true implementation, GhostCanvas.TaskManager.parseAndSendPixel would need
                            // to know which bot is drawing which pixel, or each bot would need its own TaskManager subset.
                            // Here, we'll just indicate the start. The current GhostCanvas TaskManager
                            // already round-robins available pixels among *all* connected bots.
                            // So, this button mainly serves to trigger that mechanism with a collaborative message.
                        }
                    }

                    ghostCanvas.drawingManager.startDrawing();
                    this.notify("success", "El dibujo colaborativo ha comenzado. ¡Observa a tus bots trabajar!");
                });
                row.appendChild(coordinateDrawButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        #row2() {
            const row = domMake.Row();
            {
                const smartGuessButton = domMake.Button("Bot de Adivinanza (Conceptual)");
                smartGuessButton.title = "Un bot intentará adivinar la palabra (simulado).";

                smartGuessButton.addEventListener("click", () => {
                    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
                    if (!botManager || botManager.children.length === 0) {
                        this.notify("warning", "Necesitas al menos 1 bot activo para esta función.");
                        return;
                    }

                    const activeBot = botManager.children[0].bot;
                    if (!activeBot || !activeBot.getReadyState()) {
                        this.notify("warning", "El bot seleccionado no está conectado.");
                        return;
                    }

                    const commonWords = ["casa", "flor", "mesa", "sol", "perro", "gato"];
                    const randomWord = commonWords[Math.floor(Math.random() * commonWords.length)];

                    activeBot.emit("chatmsg", randomWord);
                    this.notify("info", `Bot ${activeBot.name} intentó adivinar: "${randomWord}" (simulado).`);
                });
                row.appendChild(smartGuessButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        #row3() {
            const row = domMake.Row();
            {
                const botPersonalityLabel = domMake.Tree("label", {}, ["Personalidad del Bot:"]);
                const drawingSpeedInput = domMake.Tree("input", { type: "number", min: 1, max: 100, value: 10, title: "Velocidad de Dibujo (ms/px)" });
                const verbositySelect = domMake.Tree("select", { title: "Verbosidad de Mensajes" });
                ['Silencioso', 'Normal', 'Charlatán'].forEach(level => {
                    verbositySelect.appendChild(domMake.Tree("option", { value: level }, [level]));
                });

                drawingSpeedInput.addEventListener("change", (e) => {
                    const speed = parseInt(e.target.value);
                    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
                    if (botManager) {
                        botManager.children.forEach(botI => {
                            if (botI.bot) {
                                // Apply conceptual speed to bots' drawing
                                botI.bot.drawingDelay = speed; // Add a new property to bot
                                this.notify("log", `Velocidad de dibujo de ${botI.getName()}: ${speed}ms/px.`);
                            }
                        });
                    }
                });

                verbositySelect.addEventListener("change", (e) => {
                    const verbosity = e.target.value;
                    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
                    if (botManager) {
                        botManager.children.forEach(botI => {
                            if (botI.bot) {
                                botI.bot.chatVerbosity = verbosity; // New property
                                this.notify("log", `Verbosidad de ${botI.getName()}: ${verbosity}.`);
                            }
                        });
                    }
                });

                row.appendAll(botPersonalityLabel, drawingSpeedInput, verbositySelect);
            }
            this.htmlElements.section.appendChild(row);
        }
    }
})("QBit");

(function AdvancedTelemetry() {
    const QBit = globalThis[arguments[0]];

    class AdvancedTelemetry extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #playerMetricsContainer;
        #snapshotContainer;
        #snapshots = [];
        #maxSnapshots = 3;

        constructor() {
            super("", '<i class="fas fa-chart-line"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.#listenToGameEvents();
        }

        #loadInterface() {
            this.#row1(); // Panel de Control de Jugadores
            this.#row2(); // Historial Visual de Rondas
            this.#row3(); // Temas Dinámicos del HUD
        }

        #row1() {
            const row = domMake.Row();
            this.#playerMetricsContainer = domMake.Tree("div", { class: "player-metrics-list" });
            row.appendChild(domMake.Tree("label", {}, ["Métricas de Jugadores:"]));
            row.appendChild(this.#playerMetricsContainer);
            this.htmlElements.section.appendChild(row);
            this.updatePlayerMetrics(); // Initial update
        }

        #row2() {
            const row = domMake.Row();
            const captureSnapshotButton = domMake.Button("Capturar Lienzo");
            captureSnapshotButton.title = "Guarda una imagen del lienzo actual.";
            captureSnapshotButton.addEventListener("click", () => this.captureCanvasSnapshot());

            this.#snapshotContainer = domMake.Tree("div", { class: "snapshot-previews icon-list" });
            row.appendAll(captureSnapshotButton, this.#snapshotContainer);
            this.htmlElements.section.appendChild(row);
        }

        #row3() {
            const row = domMake.Row();
            const hudColorLabel = domMake.Tree("label", {}, ["Color del HUD:"]);
            const hudColorInput = domMake.Tree("input", { type: "color", value: "#007bff" }); // Default Bootstrap primary

            hudColorInput.addEventListener("change", (e) => {
                const newColor = e.target.value;
                document.documentElement.style.setProperty('--primary', newColor);
                document.documentElement.style.setProperty('--success', newColor); // Apply to success as well for consistency
                this.notify("info", `Color del HUD cambiado a: ${newColor}`);
            });
            row.appendAll(hudColorLabel, hudColorInput);
            this.htmlElements.section.appendChild(row);
        }

        #listenToGameEvents() {
            // Update player metrics whenever player list changes
            const playerListElement = document.getElementById("playerlist");
            if (playerListElement) {
                const observer = new MutationObserver(() => this.updatePlayerMetrics());
                observer.observe(playerListElement, { childList: true, subtree: true });
            }

            // Listen for chat messages for conceptual "heatmap"
            if (globalThis._io && globalThis._io.events) {
                // This is a placeholder as direct binding to _io.events.bc_chatmessage might not always work without a bot.
                // A more robust solution would be to observe the #chatbox_messages div.
                const chatboxMessages = document.getElementById("chatbox_messages");
                if (chatboxMessages) {
                    const chatObserver = new MutationObserver((mutations) => {
                        mutations.forEach(mutation => {
                            mutation.addedNodes.forEach(node => {
                                if (node.classList && node.classList.contains('chatmessage') && !node.classList.contains('systemchatmessage5')) {
                                    const playerNameElement = node.querySelector('.playerchatmessage-name a');
                                    const playerName = playerNameElement ? playerNameElement.textContent : 'Unknown';
                                }
                            });
                        });
                    });
                    chatObserver.observe(chatboxMessages, { childList: true });
                }
            }
        }

        updatePlayerMetrics() {
            this.#playerMetricsContainer.innerHTML = '';
            const playerRows = document.querySelectorAll("#playerlist .playerlist-row");
            if (playerRows.length === 0) {
                this.#playerMetricsContainer.appendChild(domMake.TextNode("No hay jugadores en la sala."));
                return;
            }

            playerRows.forEach(playerRow => {
                const playerId = playerRow.dataset.playerid;
                const playerName = playerRow.querySelector(".playerlist-name a")?.textContent || `Player ${playerId}`;
                const score = playerRow.querySelector(".playerlist-rank")?.textContent || 'N/A';
                const turnScore = playerRow.querySelector(".playerlist-turnscore")?.textContent || 'N/A';

                const metricItem = domMake.Tree("div", { style: "margin: 2px 0; font-size: 0.8rem;" }, [
                    domMake.Tree("strong", {}, [`${playerName} (ID: ${playerId}): `]),
                    domMake.TextNode(`Puntuación: ${score}, Turno: ${turnScore}`)
                ]);
                this.#playerMetricsContainer.appendChild(metricItem);
            });
        }

        updatePlayerActivity(playerName) {
            // This is a conceptual update. In a real scenario, this would update
            // a dedicated "activity heatmap" visual.
            this.notify("debug", ``);
            const playerElements = document.querySelectorAll(`#playerlist .playerlist-row .playerlist-name a`);
            playerElements.forEach(el => {
                if (el.textContent === playerName) {
                    el.closest('.playerlist-row').style.backgroundColor = 'rgba(0, 255, 0, 0.1)'; // Flash green
                    setTimeout(() => {
                        el.closest('.playerlist-row').style.backgroundColor = '';
                    }, 500);
                }
            });
        }

        captureCanvasSnapshot() {
            const gameCanvas = document.body.querySelector("canvas#canvas");
            if (!gameCanvas) {
                this.notify("error", "Lienzo de juego no encontrado para capturar.");
                return;
            }

            try {
                const base64Image = gameCanvas.toDataURL("image/png");
                const timestamp = new Date().toLocaleString();

                this.#snapshots.push({ data: base64Image, timestamp: timestamp });
                if (this.#snapshots.length > this.#maxSnapshots) {
                    this.#snapshots.shift(); // Keep only the last N snapshots
                }
                this.updateSnapshotPreviews();
                this.notify("success", `Instantánea del lienzo capturada: ${timestamp}`);
            } catch (e) {
                this.notify("error", `Error al capturar el lienzo: ${e.message}`);
                console.error("Canvas snapshot error:", e);
            }
        }

        updateSnapshotPreviews() {
            this.#snapshotContainer.innerHTML = '';
            if (this.#snapshots.length === 0) {
                this.#snapshotContainer.appendChild(domMake.TextNode("No hay instantáneas guardadas."));
                return;
            }

            this.#snapshots.forEach((snapshot, index) => {
                const img = domMake.Tree("img", {
                    src: snapshot.data,
                    style: "width: 50px; height: 50px; border: 1px solid #ccc; margin: 2px; cursor: pointer;",
                    title: `Instantánea ${index + 1}: ${snapshot.timestamp}`
                });
                img.addEventListener("click", () => this.displaySnapshot(snapshot.data));
                this.#snapshotContainer.appendChild(img);
            });
        }

        displaySnapshot(imageData) {
            // Create a temporary overlay to display the full snapshot
            const overlay = domMake.Tree("div", {
                style: `
                    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                    background: rgba(0,0,0,0.8); z-index: 10000;
                    display: flex; justify-content: center; align-items: center;
                `
            });
            const img = domMake.Tree("img", {
                src: imageData,
                style: `max-width: 90%; max-height: 90%; border: 2px solid white;`
            });
            overlay.appendChild(img);
            overlay.addEventListener("click", () => overlay.remove()); // Close on click
            document.body.appendChild(overlay);
        }
    }
})("QBit");

(function StrokeMaster() {
    const QBit = globalThis[arguments[0]];

    class StrokeMaster extends QBit {
        static dummy1 = QBit.register(this);
        static dummy2 = QBit.bind(this, "CubeEngine");

        #isPressureActive = false;
        #isTextureActive = false;
        #lastMousePos = { x: 0, y: 0 };
        #lastTimestamp = 0;

        constructor() {
            super("Maestría de Trazo y Realismo", '<i class="fas fa-palette"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.#hookDrawingEvents();
        }

        #loadInterface() {
            this.#row1();
            this.#row2();
            this.#row3();
            this.#row4();
            this.#row5();
            this.#row6();
        }

        #row1() {
            const row = domMake.Row();
            {
const diamondGradientFillButton = domMake.Button("Relleno Degradado Diamante");
diamondGradientFillButton.title = "Activa la herramienta de relleno con degradado en forma de diamante (conceptual).";
diamondGradientFillButton.addEventListener("click", () => {
    this.notify("info", "Esta función es conceptual. Simula un degradado que se expande desde el centro en forma de diamante.");
    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
    if (botManager && botManager.children.length > 0) {
        const activeBot = botManager.children[0].bot;
        if (activeBot && activeBot.getReadyState()) {
            this.notify("log", "Simulando relleno degradado diamante con el bot...");
            const centerX = 50;
            const centerY = 50;
            const maxDistance = 40; // Max distance from center for the diamond effect
            const steps = 60; // Number of concentric diamond "layers"

            for (let i = steps; i >= 0; i--) { // Draw from outside in
                const ratio = i / steps;
                // Dark Blue (0, 0, 139) to Bright Gold (255, 215, 0)
                const r = Math.floor(0 + (255 - 0) * (1 - ratio));
                const g = Math.floor(0 + (215 - 0) * (1 - ratio));
                const b = Math.floor(139 + (0 - 139) * (1 - ratio));
                const color = `rgb(${r},${g},${b})`;

                const currentDistance = maxDistance * ratio;

                // Define the corners of the diamond for this step
                const p1x = centerX;
                const p1y = centerY - currentDistance; // Top point
                const p2x = centerX + currentDistance;
                const p2y = centerY; // Right point
                const p3x = centerX;
                const p3y = centerY + currentDistance; // Bottom point
                const p4x = centerX - currentDistance;
                const p4y = centerY; // Left point

                // Draw the diamond outline for this step, effectively filling from outside in
                activeBot.emit("line", -1, p1x, p1y, p2x, p2y, true, 25, color, false);
                activeBot.emit("line", -1, p2x, p2y, p3x, p3y, true, 25, color, false);
                activeBot.emit("line", -1, p3x, p3y, p4x, p4y, true, 25, color, false);
                activeBot.emit("line", -1, p4x, p4y, p1x, p1y, true, 25, color, false);
            }
            this.notify("success", "Degradado diamante conceptual dibujado.");
        }
    }
});
row.appendChild(diamondGradientFillButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        #row2() {
            const row = domMake.Row();
            {
const radialGradientFillButton = domMake.Button("Relleno Degradado Radial");
radialGradientFillButton.title = "Activa la herramienta de relleno con degradado radial (conceptual).";
radialGradientFillButton.addEventListener("click", () => {
    this.notify("info", "Esta función es conceptual. En un entorno real, permitiría seleccionar un centro, un radio y colores para un degradado radial.");
    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
    if (botManager && botManager.children.length > 0) {
        const activeBot = botManager.children[0].bot;
        if (activeBot && activeBot.getReadyState()) {
            this.notify("log", "Simulando relleno degradado radial con el bot...");
            const centerX = 50;
            const centerY = 50;
            const maxRadius = 30;
            const steps = 20; // Number of concentric circles to draw the gradient

            for (let i = steps; i >= 0; i--) { // Draw from outside in
                const ratio = i / steps;
                // Orange (255, 165, 0) to Yellow (255, 255, 0)
                const r = 255;
                const g = Math.floor(165 + (255 - 165) * (1 - ratio)); // Green goes from 165 to 255 (more yellow)
                const b = 0;
                const color = `rgb(${r},${g},${b})`;
                const currentRadius = maxRadius * ratio;

                // Simulate by drawing small circles or many lines
                // For simplicity, let's draw several points in a circle to approximate
                const numSegments = 36; // More segments for smoother circle
                for (let j = 0; j < numSegments; j++) {
                    const angle = (j / numSegments) * 2 * Math.PI;
                    const x = centerX + currentRadius * Math.cos(angle);
                    const y = centerY + currentRadius * Math.sin(angle);
                    activeBot.emit("line", -1, x, y, x + 1, y + 1, true, 25, color, false); // Draw a tiny line as a "point"
                }
            }
            this.notify("success", "Degradado radial conceptual dibujado.");
        }
    }
});
row.appendChild(radialGradientFillButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        #row3() {
            const row = domMake.Row();
            {
                const gradientFillButton = domMake.Button("Relleno Degradado");
                gradientFillButton.title = "Activa la herramienta de relleno con degradado lineal (conceptual).";

                gradientFillButton.addEventListener("click", () => {
                    this.notify("info", "Esta función es conceptual. En un entorno real, permitiría seleccionar dos puntos y dos colores para un degradado.");
                    // For simulation, we can demonstrate a simple gradient fill using the bot on a small area.
                    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
                    if (botManager && botManager.children.length > 0) {
                        const activeBot = botManager.children[0].bot;
                        if (activeBot && activeBot.getReadyState()) {
                            // Simulate a simple rectangular gradient
                            // This would ideally be a flood fill with gradient, but that's complex
                            // For a simple demo, drawing multiple lines of varying color
                            this.notify("log", "Simulando relleno degradado con el bot...");
                            const startX = 20, endX = 80;
                            const startY = 20, endY = 80;
                            const steps = 20; // Number of lines to draw the gradient
                            for (let i = 0; i <= steps; i++) {
                                const ratio = i / steps;
                                const r = Math.floor(255 * (1 - ratio)); // Red from 255 to 0
                                const g = 0;
                                const b = Math.floor(255 * ratio); // Blue from 0 to 255
                                const color = `rgb(${r},${g},${b})`;
                                const yPos = startY + (endY - startY) * ratio;
                                activeBot.emit("line", -1, startX, yPos, endX, yPos, true, 25, color, false);
                            }
                            this.notify("success", "Degradado conceptual dibujado.");
                        }
                    }
                });
                row.appendChild(gradientFillButton);
            }
            this.htmlElements.section.appendChild(row);
        }

#row4() {
            const row = domMake.Row();
            {
const verticalLinearGradientButton = domMake.Button("Relleno Degradado Vertical");
verticalLinearGradientButton.title = "Activa la herramienta de relleno con degradado lineal vertical (conceptual).";
verticalLinearGradientButton.addEventListener("click", () => {
    this.notify("info", "Esta función es conceptual. En un entorno real, permitiría un degradado lineal de arriba a abajo con dos colores.");
    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
    if (botManager && botManager.children.length > 0) {
        const activeBot = botManager.children[0].bot;
        if (activeBot && activeBot.getReadyState()) {
            this.notify("log", "Simulando relleno degradado vertical con el bot...");
            const startX = 20, endX = 80;
            const startY = 20, endY = 80;
            const steps = 20; // Number of lines to draw the gradient

            for (let i = 0; i <= steps; i++) {
                const ratio = i / steps;
                // Purple (128, 0, 128) to Pink (255, 192, 203)
                const r = Math.floor(128 + (255 - 128) * ratio);
                const g = Math.floor(0 + (192 - 0) * ratio);
                const b = Math.floor(128 + (203 - 128) * ratio);
                const color = `rgb(${r},${g},${b})`;
                const yPos = startY + (endY - startY) * ratio;
                activeBot.emit("line", -1, startX, yPos, endX, yPos, true, 25, color, false);
            }
            this.notify("success", "Degradado vertical conceptual dibujado.");
        }
    }
});
row.appendChild(verticalLinearGradientButton);
            }
            this.htmlElements.section.appendChild(row);
        }

#row5() {
            const row = domMake.Row();
            {
const conicalGradientFillButton = domMake.Button("Relleno Degradado Cónico");
conicalGradientFillButton.title = "Activa la herramienta de relleno con degradado cónico/angular (conceptual).";
conicalGradientFillButton.addEventListener("click", () => {
    this.notify("info", "Esta función es conceptual. En un entorno real, permitiría seleccionar un centro y un ángulo de inicio para un degradado cónico.");
    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
    if (botManager && botManager.children.length > 0) {
        const activeBot = botManager.children[0].bot;
        if (activeBot && activeBot.getReadyState()) {
            this.notify("log", "Simulando relleno degradado cónico con el bot...");
            const centerX = 50;
            const centerY = 50;
            const maxRadius = 40; // Max radius for the conical effect
            const steps = 60; // More steps for a smoother conical sweep

            for (let i = 0; i <= steps; i++) {
                const ratio = i / steps;
                // Electric Blue (0, 0, 255) to Vibrant Magenta (255, 0, 255)
                const r = Math.floor(0 + (255 - 0) * ratio);
                const g = 0;
                const b = 255; // Blue remains constant at 255 for the transition
                const color = `rgb(${r},${g},${b})`;

                // Calculate angle for this step (full circle)
                const angle = (ratio * 2 * Math.PI); // From 0 to 2PI (360 degrees)

                // Draw a line from the center outwards at this angle
                const x2 = centerX + maxRadius * Math.cos(angle);
                const y2 = centerY + maxRadius * Math.sin(angle);

                // To simulate a fill, we'll draw many lines from the center to the edge,
                // each with the color corresponding to its angle.
                // Instead of drawing just one line, we'll draw a small wedge for each step
                // by drawing multiple lines very close to each other.
                // For simplicity in this simulation, let's draw a line from the center to the edge.
                // The "fill" effect comes from drawing many such lines very close together.
                activeBot.emit("line", -1, centerX, centerY, x2, y2, true, 25, color, false);
            }
            this.notify("success", "Degradado cónico conceptual dibujado.");
        }
    }
});
row.appendChild(conicalGradientFillButton);
            }
            this.htmlElements.section.appendChild(row);
        }

#row6() {
            const row = domMake.Row();
            {
const waveGradientFillButton = domMake.Button("Relleno Degradado Ondulado");
waveGradientFillButton.title = "Activa la herramienta de relleno con degradado ondulado (conceptual).";
waveGradientFillButton.addEventListener("click", () => {
    this.notify("info", "Esta función es conceptual. Simula un degradado que se propaga en ondas con cambio de color.");
    const botManager = this.findGlobal("BotClientManager")?.siblings[0];
    if (botManager && botManager.children.length > 0) {
        const activeBot = botManager.children[0].bot;
        if (activeBot && activeBot.getReadyState()) {
            this.notify("log", "Simulando relleno degradado ondulado con el bot...");
            const startX = 10, endX = 90;
            const startY = 20, endY = 80;
            const waveAmplitude = 10; // How high/low the waves go
            const waveFrequency = 0.1; // How many waves across the area
            const steps = 60; // Number of lines to draw for smoothness

            for (let i = 0; i <= steps; i++) {
                const ratio = i / steps;
                // Cyan (0, 255, 255) to Coral (255, 127, 80)
                const r = Math.floor(0 + (255 - 0) * ratio);
                const g = Math.floor(255 + (127 - 255) * ratio);
                const b = Math.floor(255 + (80 - 255) * ratio);
                const color = `rgb(${r},${g},${b})`;

                // Calculate the y-position for the wave
                // We'll draw horizontal lines that oscillate up and down
                const yOffset = waveAmplitude * Math.sin(ratio * Math.PI * 2 * waveFrequency);
                const currentY = startY + (endY - startY) * ratio + yOffset;

                // To create a "fill" effect with waves, we'll draw a short vertical line
                // or a very thick horizontal line that follows the wave path.
                // Let's draw a horizontal line that follows the wave.
                activeBot.emit("line", -1, startX, currentY, endX, currentY, true, 25, color, false);
            }
            this.notify("success", "Degradado ondulado conceptual dibujado.");
        }
    }
});
row.appendChild(waveGradientFillButton);
            }
            this.htmlElements.section.appendChild(row);
        }

        #hookDrawingEvents() {
            const gameCanvas = document.querySelector("#canvas");
            if (!gameCanvas) return;

            let isDrawingLocal = false;
            let lastX = 0, lastY = 0;
            let lastDrawThickness = 5; // Default thickness

            gameCanvas.addEventListener("mousedown", (e) => {
                isDrawingLocal = true;
                const rect = gameCanvas.getBoundingClientRect();
                lastX = ((e.clientX - rect.left) / rect.width) * 1000;
                lastY = ((e.clientY - rect.top) / rect.height) * 1000;
                this.#lastMousePos = { x: e.clientX, y: e.clientY };
                this.#lastTimestamp = performance.now();
            });

            gameCanvas.addEventListener("mousemove", (e) => {
                if (!isDrawingLocal) return;

                const rect = gameCanvas.getBoundingClientRect();
                const currentX = ((e.clientX - rect.left) / rect.width) * 1000;
                const currentY = ((e.clientY - rect.top) / rect.height) * 1000;

                let currentThickness = lastDrawThickness;
                let currentColor = this.getCurrentBrushColor(); // Assuming a way to get current color

                // Simulate Pressure Control
                if (this.#isPressureActive) {
                    const currentTimestamp = performance.now();
                    const dx = e.clientX - this.#lastMousePos.x;
                    const dy = e.clientY - this.#lastMousePos.y;
                    const distance = Math.sqrt(dx * dx + dy * dy);
                    const timeDelta = currentTimestamp - this.#lastTimestamp;
                    const speed = distance / timeDelta; // Pixels per millisecond

                    // Map speed to thickness (slower = thicker, faster = thinner)
                    // Adjust these values for desired effect
                    const minThickness = 2;
                    const maxThickness = 20;
                    const speedFactor = 0.5; // Adjust how much speed influences thickness

                    currentThickness = maxThickness - (speed * speedFactor);
                    currentThickness = Math.max(minThickness, Math.min(maxThickness, currentThickness));
                    lastDrawThickness = currentThickness;
                }

                // Simulate Texture Brush (apply noise to color)
                if (this.#isTextureActive) {
                    const originalColorHex = document.querySelector('.drawcontrols-color.active')?.style.backgroundColor || "#000000";
                    currentColor = this.applyColorNoise(originalColorHex, 10); // 10 is the noise amount
                }

                // Send drawing command with adjusted thickness and color
                const botManager = this.findGlobal("BotClientManager")?.siblings[0];
                if (botManager && botManager.children.length > 0) {
                    const activeBot = botManager.children[0].bot;
                    if (activeBot && activeBot.getReadyState()) {
                        activeBot.emit("line", -1, lastX, lastY, currentX, currentY, true, currentThickness, currentColor, false);
                    }
                }

                lastX = currentX;
                lastY = currentY;
                this.#lastMousePos = { x: e.clientX, y: e.clientY };
                this.#lastTimestamp = performance.now();
            });

            gameCanvas.addEventListener("mouseup", () => {
                isDrawingLocal = false;
                lastDrawThickness = 5; // Reset thickness after drawing
            });

            gameCanvas.addEventListener("mouseout", () => {
                isDrawingLocal = false;
                lastDrawThickness = 5; // Reset thickness
            });
        }

        getCurrentBrushColor() {
            // Attempt to get the currently selected color from Drawaria's UI
            const colorPicker = document.querySelector('.drawcontrols-color.active');
            if (colorPicker) {
                const rgb = colorPicker.style.backgroundColor;
                if (rgb) return rgb;
            }
            return "#000000"; // Default to black
        }

        rgbToHex(rgb) {
            // Choose a hex color from any RGB color (conceptual).
            if (rgb.startsWith("rgb")) {
                const parts = rgb.match(/\d+/g).map(Number);
                if (parts.length >= 3) {
                    const toHex = (c) => c.toString(16).padStart(2, '0');
                    return `#${toHex(parts[0])}${toHex(parts[1])}${toHex(parts[2])}`;
                }
            }
            return rgb; // Return as is if not RGB
        }

        applyColorNoise(color, noiseAmount) {
            // Convert RGB string to array, apply noise, convert back to RGB string
            let r, g, b;
            if (color.startsWith("rgb")) {
                const parts = color.match(/\d+/g).map(Number);
                r = parts[0];
                g = parts[1];
                b = parts[2];
            } else if (color.startsWith("#")) {
                // Handle hex colors
                const hex = color.slice(1);
                r = parseInt(hex.substring(0, 2), 16);
                g = parseInt(hex.substring(2, 4), 16);
                b = parseInt(hex.substring(4, 6), 16);
            } else {
                return color; // Cannot parse, return original
            }

            const addNoise = (value) => {
                const noise = (Math.random() - 0.5) * 2 * noiseAmount;
                return Math.max(0, Math.min(255, Math.floor(value + noise)));
            };

            const noisyR = addNoise(r);
            const noisyG = addNoise(g);
            const noisyB = addNoise(b);

            return `rgb(${noisyR},${noisyG},${noisyB})`;
        }
    }
})("QBit");

// --- END OF NEW FUNCTIONALITIES ---
})();