Cube Engine Uptaded New Options

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

À partir de 2025-07-09. Voir la dernière version.

// ==UserScript==
// @name         Cube Engine Uptaded New Options
// @version      9.0.1
// @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
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js
// ==/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();
      }, 200);
    };
  })("QBit")();

// ... (final del módulo CubicEngine, p.ej. })("QBit")(); )

// --- Global readiness promises for external libraries ---
// Estas promesas se resolverán cuando la librería respectiva esté completamente cargada e inicializada.
// Su colocación es CRÍTICA: Deben estar en el scope más externo de tu userscript
// pero después de la inicialización de CubicEngine para que 'QBit' y 'globalThis' estén disponibles.
// NOTA: image-js ha sido ELIMINADO de aquí y del código del módulo ImageAnalyzer.

let _cvReadyPromise = new Promise(resolve => {
    // OpenCV.js requiere `cv.onRuntimeInitialized` para asegurar que WebAssembly se ha cargado.
    if (typeof cv !== 'undefined') {
        if (cv.Mat) { // Si ya está listo (poco probable tan temprano), resolvemos.
            resolve();
            console.log("Cube Engine: OpenCV.js ya estaba listo al inicio.");
        } else {
            cv.onRuntimeInitialized = () => {
                resolve();
                console.log("Cube Engine: OpenCV.js onRuntimeInitialized disparado. Librería lista.");
            };
        }
    }
});
// --- End Global readiness promises ---


// --- START NEW MODULE: ImageAnalyzer (CORREGIDO) ---
// (Pega el código completo del módulo ImageAnalyzer aquí)
// --- END NEW MODULE: ImageAnalyzer ---

// --- START NEW MODULE: ShapeDetector (CORREGIDO) ---
// (Pega el código completo del módulo ShapeDetector aquí)
// --- END NEW MODULE: ShapeDetector ---

(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`;
    }

    // CLASE BOTCLIENT MODIFICADA PARA HEREDAR DE QBit
    class BotClient extends QBit { // <--- ESTA LÍNEA FUE MODIFICADA/DESCOMENTADA
      static dummy1 = QBit.register(this);

      // constructor(name = '', avatar = []) {
      constructor(name = "JavaScript", avatar = ["86e33830-86ea-11ec-8553-bff27824cf71"]) {
        super(name, `<img src="${parseAvatarURL(avatar)}">`); // Asegura que se llama al constructor de la clase padre

        this.name = name; // Asegura que el nombre del bot se almacene para 'notify'
        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();
      }

      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
      },
      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;
      }

      // --- INICIO: Nueva opción de "Enable rapid Color Change" ---
      {
        // Generamos un UUID completamente nuevo para este checkbox,
        // asegurando que no haya conflictos y evitando el uso de propiedades privadas.
        const rapidColorChangeCheckboxId = generate.uuidv4() + "-rapidColorChange";

        // Creamos el input (checkbox). No es necesario que esté "hidden: true" aquí
        // porque será un hijo del label y el label es la parte visual y clicable.
        const rapidColorChangeInput = domMake.Tree("input", {
          type: "checkbox",
          id: rapidColorChangeCheckboxId,
        });

        // Creamos el label, y añadimos el checkbox, el icono y el texto como sus hijos.
        // Esto hace que todo el área del label sea clicable para el checkbox.
        const rapidColorChangeLabel = domMake.Tree("label", {
            for: rapidColorChangeCheckboxId, // Vincula el label al input por su ID
            class: "col", // Aplica la clase 'col' al label para el diseño flexbox dentro de la fila
            title: "Enable rapid Color Change",
        });

        // Orden de los elementos dentro del label: checkbox, luego icono, luego texto.
        rapidColorChangeLabel.appendChild(rapidColorChangeInput);
        rapidColorChangeLabel.appendChild(domMake.Tree("i", { class: "fas fa-adjust" }));
        rapidColorChangeLabel.appendChild(domMake.TextNode(" Rapid Color Change"));

        // Añadimos el evento 'input' directamente al checkbox.
        // El click en el label propagará al input, por lo que este listener funcionará.
        rapidColorChangeInput.addEventListener("input", () => {
            const colorflowSpeedInput = document.querySelector('input[data-localprop="colorflow"]');
            const colorflowTypeSelect = document.querySelector('select[data-localprop="colorautochange"]');
            const settingsContainer = document.querySelector(".drawcontrols-settingscontainer:has([data-localprop='colorautochange'])");

            if (!colorflowSpeedInput || !colorflowTypeSelect || !settingsContainer) {
                this.notify("warning", "Color flow controls not found. Make sure drawing controls are visible.");
                return;
            }

            if (rapidColorChangeInput.checked) {
                colorflowTypeSelect.value = "2";
                colorflowSpeedInput.max = 10;
                colorflowSpeedInput.value = 10;
            } else {
                colorflowTypeSelect.value = "0";
                colorflowSpeedInput.max = 1;
                colorflowSpeedInput.value = 0;
            }
            settingsContainer.dispatchEvent(new CustomEvent("change"));
        });

        // Solo el label (que ahora contiene el checkbox y los demás elementos) se añade a la fila.
        row.appendChild(rapidColorChangeLabel);
      }
      // --- FIN: Nueva opción de "Enable rapid Color Change" ---

      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 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 BotKickModule() {
    const QBit = globalThis[arguments[0]]; // Corrected access to QBit

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

        #playerListContainer; // Container for player buttons

        constructor() {
            super("Kick con Bot", '<i class="fas fa-user-times"></i>'); // Icon for kicking (user + times)
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            // Update player list whenever the playerlist DOM changes
            const playerListElement = document.getElementById("playerlist");
            if (playerListElement) {
                const observer = new MutationObserver(() => this.#updatePlayerListButtons());
                observer.observe(playerListElement, { childList: true, subtree: true });
            }
            this.#updatePlayerListButtons(); // Initial update
        }

        #loadInterface() {
            const row = domMake.Row();
            this.#playerListContainer = domMake.IconList(); // Use IconList for flexible layout
            row.appendChild(this.#playerListContainer);
            this.htmlElements.section.appendChild(row);
        }

        #updatePlayerListButtons() {
            this.#playerListContainer.innerHTML = ''; // Clear existing buttons

            const playerRows = document.querySelectorAll("#playerlist .playerlist-row");
            const myPlayerIdElement = document.querySelector(".playerlist-name-self")?.parentElement;
            const myPlayerId = myPlayerIdElement ? myPlayerIdElement.dataset.playerid : null;

            if (playerRows.length <= 1) { // Only self or no other players
                const noPlayersMessage = domMake.Tree("span", {}, ["No hay otros jugadores para kickear."]);
                this.#playerListContainer.appendChild(noPlayersMessage);
                return;
            }

            playerRows.forEach(playerRow => {
                const playerId = playerRow.dataset.playerid;
                const playerName = playerRow.querySelector(".playerlist-name a")?.textContent || `Player ${playerId}`;

                // Don't create a button for the current player (self)
                if (playerId === myPlayerId) {
                    return;
                }

                const playerButton = domMake.Button(playerName);
                playerButton.title = `Kickear a ${playerName} (ID: ${playerId}) con el bot seleccionado.`;
                playerButton.style.margin = '2px';
                playerButton.style.padding = '2px 5px';
                playerButton.style.fontSize = '0.7em';

                playerButton.addEventListener("click", () => {
                    this.#sendBotKick(parseInt(playerId), playerName);
                });
                this.#playerListContainer.appendChild(playerButton);
            });
        }

        /**
         * Retrieves the currently selected bot instance from BotClientManager.
         * Falls back to the first available bot if none is explicitly selected.
         * Notifies the user if no bot is active or connected.
         * @returns {object|null} The active bot instance, or null if none found/ready.
         */
        #getBot() {
            const botManagerClass = this.findGlobal("BotClientManager");
            if (!botManagerClass || !botManagerClass.siblings || botManagerClass.siblings.length === 0) {
                this.notify("warning", "No hay instancias activas de 'BotClientManager'. Por favor, crea uno desde 'CubeEngine'.");
                return null;
            }

            // Assuming there's only one main BotClientManager instance that holds all BotClientInterfaces
            const botManagerInstance = botManagerClass.siblings[0];

//        if (!botManagerInstance || !botManagerInstance.children || botManagerInstance.children.length === 0) {
//              this.notify("warning", "No hay bots activos en 'BotClientManager'. Por favor, crea y conecta uno.");
//              return null;
//          }

            const botClientInterfaces = botManagerInstance.children;
            let activeBotClientInterface = null;

            const selectedBotInput = document.querySelector('input[name="botClient"]:checked');
            if (selectedBotInput) {
                activeBotClientInterface = botClientInterfaces.find(bci => bci.htmlElements.input === selectedBotInput);
            }

            // Fallback to the first available bot if no specific bot is selected or found
            if (!activeBotClientInterface && botClientInterfaces.length > 0) {
                activeBotClientInterface = botClientInterfaces[0];
                this.notify("info", `No se seleccionó un bot. Usando el primer bot disponible: ${activeBotClientInterface.getName()}.`);
            }

//          if (!activeBotClientInterface || !activeBotClientInterface.bot || !activeBotClientInterface.bot.getReadyState()) {
//              this.notify("warning", `El bot "${activeBotClientInterface ? activeBotClientInterface.getName() : 'desconocido'}" no está conectado y listo para enviar comandos.`);
//              return null;
// }
            return activeBotClientInterface.bot;
        }

        /**
         * Sends a vote kick command via the selected (or first available) bot.
         * @param {number} targetPlayerId - The ID of the player to kick.
         * @param {string} targetPlayerName - The name of the player to kick.
         */
        #sendBotKick(targetPlayerId, targetPlayerName) {
            const bot = this.#getBot();
            if (!bot) return; // #getBot already handles notifications

            // Send the vote kick command through the bot
            const data = _io.emits.sendvotekick(targetPlayerId);
            bot.send(data);
            this.notify("success", `Bot "${bot.name}" envió solicitud de kick para ${targetPlayerName}.`);
        }
    }
})("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 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 MEJORADOS (Simulando curvas y texturas) ---

    "ARBOL": [
        // Tronco (más orgánico y con textura)
        { x1: 45, y1: 80, x2: 43, y2: 60 }, { x1: 43, y1: 60, x2: 45, y2: 40 },
        { x1: 55, y1: 80, x2: 57, y2: 60 }, { x1: 57, y1: 60, x2: 55, y2: 40 },
        // Textura del tronco (Bark)
        { x1: 48, y1: 75, x2: 48, y2: 70 }, { x1: 51, y1: 65, x2: 51, y2: 60 },
        { x1: 46, y1: 55, x2: 46, y2: 50 },
        // Raíces más definidas
        { x1: 45, y1: 80, x2: 35, y2: 85 }, { x1: 55, y1: 80, x2: 65, y2: 85 },
        // Follaje (Contorno más irregular y segmentado)
        { x1: 45, y1: 40, x2: 30, y2: 45 }, { x1: 30, y1: 45, x2: 25, y2: 35 },
        { x1: 25, y1: 35, x2: 35, y2: 25 }, { x1: 35, y1: 25, x2: 40, y2: 20 },
        { x1: 40, y1: 20, x2: 50, y2: 15 }, { x1: 50, y1: 15, x2: 60, y2: 20 },
        { x1: 60, y1: 20, x2: 70, y2: 25 }, { x1: 70, y1: 25, x2: 75, y2: 35 },
        { x1: 75, y1: 35, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 55, y2: 40 },
        // Detalles internos del follaje (Clumps of leaves)
        { x1: 45, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 55, y2: 35 },
        { x1: 35, y1: 40, x2: 30, y2: 35 }, { x1: 65, y1: 40, x2: 70, y2: 35 },
        { x1: 50, y1: 25, x2: 45, y2: 22 }, { x1: 50, y1: 25, x2: 55, y2: 22 }
    ],

    "CASA": [
        // Estructura principal
        { x1: 30, y1: 80, x2: 70, y2: 80 }, { x1: 30, y1: 80, x2: 30, y2: 50 },
        { x1: 70, y1: 80, x2: 70, y2: 50 },
        // Tejado (Con alero)
        { x1: 25, y1: 50, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 75, y2: 50 },
        { x1: 25, y1: 50, x2: 75, y2: 50 },
        // Textura del tejado (Shingles)
        { x1: 28, y1: 45, x2: 72, y2: 45 }, { x1: 32, y1: 40, x2: 68, y2: 40 },
        { x1: 38, y1: 35, x2: 62, y2: 35 },
        // Chimenea con ladrillos
        { x1: 60, y1: 40, x2: 60, y2: 25 }, { x1: 65, y1: 40, x2: 65, y2: 25 },
        { x1: 60, y1: 25, x2: 65, y2: 25 },
        { x1: 60, y1: 30, x2: 65, y2: 30 }, { x1: 60, y1: 35, x2: 65, y2: 35 }, // Ladrillos
        // Puerta con pomo y marco
        { x1: 45, y1: 80, x2: 45, y2: 60 }, { x1: 55, y1: 80, x2: 55, y2: 60 },
        { x1: 45, y1: 60, x2: 55, y2: 60 },
        { type: "circle", x1: 53, y1: 70, radius: 1 }, // Pomo
        // Ventana con cruz y marco
        { x1: 32, y1: 55, x2: 42, y2: 55 }, { x1: 42, y1: 55, x2: 42, y2: 65 },
        { x1: 42, y1: 65, x2: 32, y2: 65 }, { x1: 32, y1: 65, x2: 32, y2: 55 },
        { x1: 37, y1: 55, x2: 37, y2: 65 }, { x1: 32, y1: 60, x2: 42, y2: 60 } // Cruz ventana
    ],

    "SOL": [
        { type: "circle", x1: 50, y1: 50, radius: 15 }, // Círculo central
        // Rayos (más variados y con un ligero patrón)
        { x1: 50, y1: 35, x2: 50, y2: 25 }, { x1: 50, y1: 35, x2: 48, y2: 28 }, { x1: 50, y1: 35, x2: 52, y2: 28 }, // Arriba
        { x1: 60, y1: 40, x2: 68, y2: 32 }, { x1: 60, y1: 40, x2: 65, y2: 35 }, // Arriba-derecha
        { x1: 65, y1: 50, x2: 75, y2: 50 }, { x1: 65, y1: 50, x2: 70, y2: 48 }, // Derecha
        { x1: 60, y1: 60, x2: 68, y2: 68 }, { x1: 60, y1: 60, x2: 65, y2: 65 }, // Abajo-derecha
        { x1: 50, y1: 65, x2: 50, y2: 75 }, { x1: 50, y1: 65, x2: 48, y2: 72 }, { x1: 50, y1: 65, x2: 52, y2: 72 }, // Abajo
        { x1: 40, y1: 60, x2: 32, y2: 68 }, { x1: 40, y1: 60, x2: 35, y2: 65 }, // Abajo-izquierda
        { x1: 35, y1: 50, x2: 25, y2: 50 }, { x1: 35, y1: 50, x2: 30, y2: 48 }, // Izquierda
        { x1: 40, y1: 40, x2: 32, y2: 32 }, { x1: 40, y1: 40, x2: 35, y2: 35 }, // Arriba-izquierda
        // Ojos y Boca (con más expresión)
        { type: "circle", x1: 45, y1: 45, radius: 1.5 }, { type: "circle", x1: 55, y1: 45, radius: 1.5 }, // Ojos más grandes
        { x1: 45, y1: 55, x2: 47, y2: 58 }, { x1: 47, y1: 58, x2: 53, y2: 58 }, { x1: 53, y1: 58, x2: 55, y2: 55 } // Boca más curvada
    ],

    "FLOR": [
        { x1: 50, y1: 80, x2: 50, y2: 55 }, // Tallo
        // Hojas (Más orgánicas y con venas)
        { x1: 50, y1: 70, x2: 40, y2: 65 }, { x1: 40, y1: 65, x2: 45, y2: 58 },
        { x1: 42, y1: 66, x2: 48, y2: 62 }, // Vena hoja 1
        { x1: 50, y1: 70, x2: 60, y2: 65 }, { x1: 60, y1: 65, x2: 55, y2: 58 },
        { x1: 58, y1: 66, x2: 52, y2: 62 }, // Vena hoja 2
        // Centro de la flor
        { type: "circle", x1: 50, y1: 50, radius: 5 }, // Círculo central para estambres
        { type: "circle", x1: 50, y1: 50, radius: 2 }, // Punto central del estambre
        // Pétalos (Más suaves y superpuestos, usando más segmentos)
        { x1: 50, y1: 45, x2: 40, y2: 38 }, { x1: 40, y1: 38, x2: 35, y2: 45 }, { x1: 35, y1: 45, x2: 38, y2: 55 }, { x1: 38, y1: 55, x2: 45, y2: 55 }, { x1: 45, y1: 55, x2: 50, y2: 45 }, // Pétalo superior-izquierda
        { x1: 50, y1: 45, x2: 60, y2: 38 }, { x1: 60, y1: 38, x2: 65, y2: 45 }, { x1: 65, y1: 45, x2: 62, y2: 55 }, { x1: 62, y1: 55, x2: 55, y2: 55 }, { x1: 55, y1: 55, x2: 50, y2: 45 }, // Pétalo superior-derecha
        { x1: 45, y1: 50, x2: 38, y2: 58 }, { x1: 38, y1: 58, x2: 40, y2: 65 }, { x1: 40, y1: 65, x2: 48, y2: 65 }, { x1: 48, y1: 65, x2: 50, y2: 55 }, { x1: 50, y1: 55, x2: 45, y2: 50 }, // Pétalo inferior-izquierda
        { x1: 55, y1: 50, x2: 62, y2: 58 }, { x1: 62, y1: 58, x2: 60, y2: 65 }, { x1: 60, y1: 65, x2: 52, y2: 65 }, { x1: 52, y1: 65, x2: 50, y2: 55 }, { x1: 50, y1: 55, x2: 55, y2: 50 }  // Pétalo inferior-derecha
    ],

    "PERRO": [
        // Cuerpo (Más curvo y orgánico)
        { x1: 40, y1: 60, x2: 50, y2: 55 }, { x1: 50, y1: 55, x2: 70, y2: 58 }, // Lomo
        { x1: 40, y1: 70, x2: 50, y2: 68 }, { x1: 50, y1: 68, x2: 70, y2: 65 }, // Vientre
        // Cabeza y Hocico
        { x1: 30, y1: 65, x2: 40, y2: 60 }, { x1: 40, y1: 60, x2: 35, y2: 50 }, // Cuello y cabeza
        { x1: 35, y1: 50, x2: 25, y2: 55 }, { x1: 25, y1: 55, x2: 30, y2: 65 }, // Hocico
        // Oreja
        { x1: 35, y1: 50, x2: 30, y2: 45 }, { x1: 30, y1: 45, x2: 40, y2: 50 },
        // Ojo y Nariz
        { type: "circle", x1: 32, y1: 55, radius: 1 }, // Ojo
        { x1: 25, y1: 55, x2: 26, y2: 56 }, // Nariz (punto)
        // Patas (Con grosor y articulaciones)
        // Delantera
        { x1: 40, y1: 70, x2: 40, y2: 80 }, { x1: 43, y1: 70, x2: 43, y2: 80 },
        // Trasera
        { x1: 70, y1: 65, x2: 65, y2: 75 }, { x1: 65, y1: 75, x2: 65, y2: 80 },
        { x1: 73, y1: 65, x2: 68, y2: 80 },
        // Cola (Curva)
        { x1: 70, y1: 58, x2: 75, y2: 50 }, { x1: 75, y1: 50, x2: 80, y2: 45 },
        // Textura de pelaje (líneas cortas)
        { x1: 50, y1: 55, x2: 50, y2: 53 }, { x1: 60, y1: 56, x2: 60, y2: 54 },
        { x1: 45, y1: 68, x2: 45, y2: 70 }, { x1: 55, y1: 68, x2: 55, y2: 70 }
    ],

    "GATO": [
         // Cuerpo (sentado, más curvo)
        { x1: 40, y1: 80, x2: 60, y2: 80 }, // Base
        { x1: 40, y1: 80, x2: 35, y2: 60 }, { x1: 35, y1: 60, x2: 40, y2: 50 }, // Lado Izq
        { x1: 60, y1: 80, x2: 65, y2: 60 }, { x1: 65, y1: 60, x2: 60, y2: 50 }, // Lado Der
        // Cabeza (más redonda)
        { type: "circle", x1: 50, y1: 45, radius: 10 },
        // Orejas puntiagudas detalladas
        { x1: 42, y1: 40, x2: 40, y2: 30 }, { x1: 40, y1: 30, x2: 48, y2: 38 }, // Oreja Izq
        { x1: 58, y1: 40, x2: 60, y2: 30 }, { x1: 60, y1: 30, x2: 52, y2: 38 }, // Oreja Der
        // Ojos y Nariz
        { type: "circle", x1: 45, y1: 45, radius: 1 }, { type: "circle", x1: 55, y1: 45, radius: 1 },
        { x1: 50, y1: 48, x2: 50, y2: 50 }, // Nariz y boca (línea Y)
        { x1: 50, y1: 50, x2: 47, y2: 52 }, { x1: 50, y1: 50, x2: 53, y2: 52 },
        // Bigotes (Whiskers)
        { x1: 45, y1: 50, x2: 30, y2: 48 }, { x1: 45, y1: 51, x2: 30, y2: 51 },
        { x1: 55, y1: 50, x2: 70, y2: 48 }, { x1: 55, y1: 51, x2: 70, y2: 51 },
        // Cola (enroscada alrededor del cuerpo)
        { x1: 65, y1: 75, x2: 75, y2: 75 }, { x1: 75, y1: 75, x2: 70, y2: 80 },
        // Textura de pelaje (Hatching ligero)
        { x1: 50, y1: 60, x2: 50, y2: 58 }, { x1: 45, y1: 70, x2: 45, y2: 68 },
        { x1: 55, y1: 70, x2: 55, y2: 68 }
    ],

    "MESA": [
        // Superficie (con grosor y perspectiva mejorada)
        { x1: 25, y1: 40, x2: 75, y2: 40 }, // Borde frontal
        { x1: 25, y1: 40, x2: 20, y2: 35 }, // Lado izquierdo superior
        { x1: 75, y1: 40, x2: 80, y2: 35 }, // Lado derecho superior
        { x1: 20, y1: 35, x2: 80, y2: 35 }, // Borde trasero
        { x1: 25, y1: 45, x2: 75, y2: 45 }, // Borde frontal inferior (grosor)
        { x1: 20, y1: 40, x2: 20, y2: 35 }, // Lateral inferior izq
        { x1: 80, y1: 40, x2: 80, y2: 35 }, // Lateral inferior der

        // Patas delanteras (con grosor)
        { x1: 30, y1: 45, x2: 30, y2: 70 }, { x1: 32, y1: 45, x2: 32, y2: 70 },
        { x1: 68, y1: 45, x2: 68, y2: 70 }, { x1: 70, y1: 45, x2: 70, y2: 70 },
        // Patas traseras en perspectiva (con grosor)
        { x1: 20, y1: 35, x2: 20, y2: 60 }, { x1: 22, y1: 35, x2: 22, y2: 60 }, // Pata trasera izq
        { x1: 78, y1: 35, x2: 78, y2: 60 }, { x1: 80, y1: 35, x2: 80, y2: 60 }, // Pata trasera der
        // Líneas de conexión para perspectiva
        { x1: 30, y1: 70, x2: 20, y2: 60 }, // Diagonal inferior izq
        { x1: 70, y1: 70, x2: 80, y2: 60 }  // Diagonal inferior der
    ],

    "SILLA": [
        // Respaldo (con detalles de listones)
        { x1: 35, y1: 40, x2: 35, y2: 60 }, { x1: 65, y1: 40, x2: 65, y2: 60 }, // Postes verticales
        { x1: 35, y1: 40, x2: 65, y2: 40 }, // Borde superior
        { x1: 38, y1: 45, x2: 62, y2: 45 }, { x1: 38, y1: 50, x2: 62, y2: 50 }, // Listones horizontales
        { x1: 38, y1: 55, x2: 62, y2: 55 },
        // Asiento (con perspectiva)
        { x1: 35, y1: 60, x2: 65, y2: 60 }, // Borde frontal
        { x1: 35, y1: 60, x2: 32, y2: 63 }, // Lado izquierdo
        { x1: 65, y1: 60, x2: 68, y2: 63 }, // Lado derecho
        { x1: 32, y1: 63, x2: 68, y2: 63 }, // Borde trasero
        // Patas delanteras (con grosor)
        { x1: 38, y1: 60, x2: 38, y2: 75 }, { x1: 40, y1: 60, x2: 40, y2: 75 },
        { x1: 60, y1: 60, x2: 60, y2: 75 }, { x1: 62, y1: 60, x2: 62, y2: 75 },
        // Patas traseras en perspectiva (con grosor y curvatura)
        { x1: 32, y1: 63, x2: 32, y2: 75 }, { x1: 30, y1: 63, x2: 30, y2: 75 }, // Pata trasera izq
        { x1: 68, y1: 63, x2: 68, y2: 75 }, { x1: 70, y1: 63, x2: 70, y2: 75 }, // Pata trasera der
        // Conexiones de las patas al asiento
        { x1: 38, y1: 60, x2: 32, y2: 63 },
        { x1: 62, y1: 60, x2: 68, y2: 63 }
    ],

    "LIBRO": [
        // Lado izquierdo (con grosor de página)
        { x1: 30, y1: 40, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 50, y2: 70 },
        { x1: 50, y1: 70, x2: 30, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 40 },
        { x1: 32, y1: 42, x2: 48, y2: 32 }, { x1: 48, y1: 32, x2: 48, y2: 68 }, // Página izquierda interior
        // Lado derecho (con grosor de página)
        { x1: 50, y1: 30, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 70, y2: 60 },
        { x1: 70, y1: 60, x2: 50, y2: 70 },
        { x1: 52, y1: 32, x2: 68, y2: 42 }, { x1: 68, y1: 42, x2: 68, y2: 68 }, // Página derecha interior
        // Lomo del libro
        { x1: 50, y1: 30, x2: 50, y2: 70 },
        // Páginas (líneas que simulan texto)
        { x1: 35, y1: 45, x2: 45, y2: 40 }, { x1: 35, y1: 50, x2: 45, y2: 45 },
        { x1: 55, y1: 45, x2: 65, y2: 50 }, { x1: 55, y1: 50, x2: 65, y2: 55 }
    ],

    "TAZA": [
        // Cuerpo de la taza (más curvo y con base más ancha)
        { x1: 40, y1: 40, x2: 60, y2: 40 }, // Borde superior
        { x1: 38, y1: 40, x2: 35, y2: 65 }, // Lado izquierdo
        { x1: 62, y1: 40, x2: 65, y2: 65 }, // Lado derecho
        { x1: 35, y1: 65, x2: 65, y2: 65 }, // Base (curvada)
        // Asa (con grosor y curvatura)
        { x1: 65, y1: 45, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 70, y2: 55 }, { x1: 70, y1: 55, x2: 65, y2: 55 },
        { x1: 65, y1: 47, x2: 68, y2: 47 }, { x1: 68, y1: 47, x2: 68, y2: 53 }, { x1: 68, y1: 53, x2: 65, y2: 53 }, // Grosor del asa
        // Interior de la taza (para dar profundidad)
        { x1: 42, y1: 42, x2: 58, y2: 42 }
    ],

    "VENTANA": [
        // Marco exterior (con grosor)
        { x1: 28, y1: 28, x2: 72, y2: 28 }, { x1: 72, y1: 28, x2: 72, y2: 72 },
        { x1: 72, y1: 72, x2: 28, y2: 72 }, { x1: 28, y1: 72, x2: 28, y2: 28 },
        { 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 interior (con grosor y divisiones)
        { 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 },
        { x1: 40, y1: 35, x2: 40, y2: 65 }, { x1: 50, y1: 35, x2: 50, y2: 65 },
        { x1: 60, y1: 35, x2: 60, y2: 65 },
        { x1: 35, y1: 40, x2: 65, y2: 40 }, { x1: 35, y1: 50, x2: 65, y2: 50 },
        { x1: 35, y1: 60, x2: 65, y2: 60 }
    ],

    "PUERTA": [
        // Puerta principal (con paneles 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 },
        // Marco exterior (con grosor)
        { x1: 38, y1: 28, x2: 38, y2: 72 }, { x1: 62, y1: 28, x2: 62, y2: 72 },
        { x1: 38, y1: 28, x2: 62, y2: 28 }, { x1: 38, y1: 72, x2: 62, y2: 72 },
        // Paneles de la puerta
        { x1: 43, y1: 35, x2: 57, y2: 35 }, { x1: 57, y1: 35, x2: 57, y2: 45 },
        { x1: 57, y1: 45, x2: 43, y2: 45 }, { x1: 43, y1: 45, x2: 43, y2: 35 },
        { x1: 43, y1: 50, x2: 57, y2: 50 }, { x1: 57, y1: 50, x2: 57, y2: 65 },
        { x1: 57, y1: 65, x2: 43, y2: 65 }, { x1: 43, y1: 65, x2: 43, y2: 50 },
        // Pomo (círculo)
        { type: "circle", x1: 55, y1: 50, radius: 2 }
    ],

    "CAJA": [
        // Frente de la caja (con grosor de las líneas)
        { 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 },
        // Tapa (con grosor y ligera elevación)
        { x1: 30, y1: 40, x2: 35, y2: 35 }, { x1: 70, y1: 40, x2: 75, y2: 35 },
        { x1: 35, y1: 35, x2: 75, y2: 35 }, // Borde frontal de la tapa
        { x1: 32, y1: 38, x2: 72, y2: 38 }, // Borde trasero de la tapa (grosor)
        { x1: 35, y1: 35, x2: 32, y2: 38 }, { x1: 75, y1: 35, x2: 72, y2: 38 },
        // Lado derecho (con grosor)
        { x1: 70, y1: 40, x2: 75, y2: 35 }, { x1: 70, y1: 60, x2: 75, y2: 55 }, // Perspectiva
        { x1: 75, y1: 35, x2: 75, y2: 55 },
        // Sombreado interior (opcional, para dar profundidad)
        { x1: 32, y1: 60, x2: 32, y2: 58 }, { x1: 32, y1: 58, x2: 68, y2: 58 }, { x1: 68, y1: 58, x2: 68, y2: 60 }
    ],

    "BOTELLA": [
        // Cuello (más largo y definido)
        { x1: 48, y1: 20, x2: 52, y2: 20 }, // Boca
        { x1: 48, y1: 20, x2: 45, y2: 30 }, { x1: 52, y1: 20, x2: 55, y2: 30 }, // Parte superior del cuello
        { x1: 45, y1: 30, x2: 45, y2: 35 }, { x1: 55, y1: 30, x2: 55, y2: 35 }, // Parte inferior del cuello
        // Hombros de la botella (curva)
        { x1: 45, y1: 35, x2: 40, y2: 45 }, { x1: 55, y1: 35, x2: 60, y2: 45 },
        // Cuerpo (más curvado)
        { x1: 40, y1: 45, x2: 38, y2: 70 }, { x1: 60, y1: 45, x2: 62, y2: 70 },
        // Base (con grosor y curvatura)
        { x1: 38, y1: 70, x2: 62, y2: 70 },
        { x1: 39, y1: 72, x2: 61, y2: 72 } // Sombra de la base
    ],

    "CAMISA": [
        // Cuello
        { x1: 45, y1: 35, x2: 55, y2: 35 }, { x1: 45, y1: 35, x2: 40, y2: 40 }, // Lado izquierdo del cuello
        { x1: 55, y1: 35, x2: 60, y2: 40 }, // Lado derecho del cuello
        // Hombros y mangas (con pliegues)
        { x1: 40, y1: 40, x2: 25, y2: 50 }, { x1: 25, y1: 50, x2: 20, y2: 60 }, // Manga izquierda
        { x1: 60, y1: 40, x2: 75, y2: 50 }, { x1: 75, y1: 50, x2: 80, y2: 60 }, // Manga derecha
        // Cuerpo (con pliegues y dobladillo)
        { x1: 20, y1: 60, x2: 20, y2: 75 }, { x1: 80, y1: 60, x2: 80, y2: 75 },
        { x1: 20, y1: 75, x2: 80, y2: 75 },
        // Línea central y botones
        { x1: 50, y1: 40, x2: 50, y2: 75 },
        { type: "circle", x1: 50, y1: 48, radius: 1 }, { type: "circle", x1: 50, y1: 55, radius: 1 },
        { type: "circle", x1: 50, y1: 62, radius: 1 }, { type: "circle", x1: 50, y1: 69, radius: 1 },
        // Pliegues sutiles en la tela
        { x1: 30, y1: 65, x2: 35, y2: 68 }, { x1: 70, y1: 65, x2: 65, y2: 68 }
    ],

    "ZAPATO": [
        // Suela (más gruesa y con relieve)
        { x1: 20, y1: 70, x2: 80, y2: 70 }, { x1: 20, y1: 70, x2: 25, y2: 75 },
        { x1: 80, y1: 70, x2: 75, y2: 75 }, { x1: 25, y1: 75, x2: 75, y2: 75 },
        { x1: 30, y1: 72, x2: 35, y2: 72 }, { x1: 40, y1: 72, x2: 45, y2: 72 }, // Relieve suela
        // Cuerpo del zapato (más orgánico y con punta)
        { x1: 20, y1: 70, x2: 25, y2: 60 }, { x1: 25, y1: 60, x2: 35, y2: 55 },
        { x1: 35, y1: 55, x2: 65, y2: 55 }, { x1: 65, y1: 55, x2: 75, y2: 60 },
        { x1: 75, y1: 60, x2: 80, y2: 70 },
        // Lengüeta del zapato
        { x1: 40, y1: 55, x2: 45, y2: 50 }, { x1: 45, y1: 50, x2: 55, y2: 50 }, { x1: 55, y1: 50, x2: 60, y2: 55 },
        // Cordones (con más detalle)
        { x1: 42, y1: 56, x2: 58, y2: 56 }, // Línea base
        { x1: 40, y1: 57, x2: 45, y2: 53 }, { x1: 45, y1: 53, x2: 50, y2: 57 }, // Cruce 1
        { x1: 50, y1: 57, x2: 55, y2: 53 }, { x1: 55, y1: 53, x2: 60, y2: 57 }  // Cruce 2
    ],

    "AGUA": [
        // Superficie del agua (ondas y reflejos)
        { x1: 20, y1: 70, x2: 80, y2: 70 }, { x1: 25, y1: 65, x2: 75, y2: 65 },
        { x1: 30, y1: 60, x2: 70, y2: 60 }, // Ondas concéntricas
        { x1: 35, y1: 55, x2: 65, y2: 55 },
        // Gotas de agua (con brillo)
        { type: "circle", x1: 50, y1: 40, radius: 5 }, { type: "circle", x1: 48, y1: 38, radius: 1 }, // Gota 1 con brillo
        { type: "circle", x1: 40, y1: 50, radius: 4 }, { type: "circle", x1: 39, y1: 49, radius: 0.8 }, // Gota 2 con brillo
        { type: "circle", x1: 60, y1: 55, radius: 3 }, { type: "circle", x1: 59, y1: 54, radius: 0.6 }  // Gota 3 con brillo
    ],

    "FUEGO": [
        // Llama (más dinámica y con múltiples picos)
        { x1: 50, y1: 75, x2: 40, y2: 65 }, { x1: 40, y1: 65, x2: 45, y2: 50 },
        { 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: 48, y1: 55, x2: 45, y2: 48 }, { x1: 45, y1: 48, x2: 50, y2: 42 }, // Llama interior 1
        { x1: 52, y1: 55, x2: 55, y2: 48 }, { x1: 55, y1: 48, x2: 50, y2: 42 }, // Llama interior 2
        // Base del fuego (simulando troncos o brasas)
        { x1: 40, y1: 75, x2: 60, y2: 75 },
        { x1: 42, y1: 77, x2: 50, y2: 77 }, { x1: 50, y1: 77, x2: 58, y2: 77 } // Líneas internas de la base
    ],

    "VIENTO": [
        // Líneas de viento con mayor dinamismo y remolinos definidos
        { x1: 15, y1: 50, x2: 85, y2: 50 }, { x1: 20, y1: 55, x2: 90, y2: 55 },
        { x1: 25, y1: 60, x2: 95, y2: 60 },
        // Remolino 1 (espiral simulada con segmentos)
        { x1: 30, y1: 45, x2: 35, y2: 40 }, { x1: 35, y1: 40, x2: 40, y2: 45 },
        { x1: 40, y1: 45, x2: 35, y2: 50 }, { x1: 35, y1: 50, x2: 30, y2: 45 },
        // Remolino 2
        { x1: 70, y1: 45, x2: 75, y2: 40 }, { x1: 75, y1: 40, x2: 80, y2: 45 },
        { x1: 80, y1: 45, x2: 75, y2: 50 }, { x1: 75, y1: 50, x2: 70, y2: 45 },
        // Pequeñas ráfagas adicionales
        { x1: 45, y1: 40, x2: 40, y2: 38 }, { x1: 55, y1: 40, x2: 60, y2: 38 }
    ],

    "TIERRA": [
        // Horizonte montañoso (más picos y valles)
        { x1: 20, y1: 70, x2: 30, y2: 65 }, { x1: 30, y1: 65, x2: 35, y2: 70 },
        { x1: 35, y1: 70, x2: 45, y2: 60 }, { x1: 45, y1: 60, x2: 50, y2: 65 },
        { x1: 50, y1: 65, x2: 60, y2: 55 }, { x1: 60, y1: 55, x2: 65, y2: 60 },
        { x1: 65, y1: 60, x2: 75, y2: 65 }, { x1: 75, y1: 65, x2: 80, y2: 70 },
        // Terreno frontal (rocas y textura)
        { x1: 25, y1: 75, x2: 35, y2: 78 }, { x1: 40, y1: 75, x2: 45, y2: 78 },
        { x1: 55, y1: 75, x2: 60, y2: 78 },
        // Árboles distantes (más pequeños y esquemáticos)
        { x1: 30, y1: 62, x2: 30, y2: 58 }, { x1: 28, y1: 58, x2: 32, y2: 58 }, // Árbol 1
        { x1: 70, y1: 62, x2: 70, y2: 58 }, { x1: 68, y1: 58, x2: 72, y2: 58 }  // Árbol 2
    ],

    "NUBE": [
        // Forma de nube (más orgánica e irregular)
        { x1: 30, y1: 40, x2: 40, y2: 35 }, { x1: 40, y1: 35, x2: 48, y2: 32 }, { x1: 48, y1: 32, x2: 55, y2: 35 },
        { x1: 55, y1: 35, x2: 62, y2: 32 }, { x1: 62, y1: 32, x2: 70, y2: 35 }, { x1: 70, y1: 35, x2: 75, y2: 40 },
        { x1: 75, y1: 40, x2: 70, y2: 50 }, { x1: 70, y1: 50, x2: 65, y2: 55 }, { x1: 65, y1: 55, x2: 55, y2: 58 },
        { x1: 55, y1: 58, x2: 45, y2: 55 }, { x1: 45, y1: 55, x2: 35, y2: 50 }, { x1: 35, y1: 50, x2: 30, y2: 40 },
        // Sombreado interno (líneas curvas paralelas para volumen)
        { x1: 35, y1: 45, x2: 45, y2: 43 }, { x1: 45, y1: 43, x2: 55, y2: 45 },
        { x1: 40, y1: 50, x2: 50, y2: 52 }, { x1: 50, y1: 52, x2: 60, y2: 50 }
    ],

    "LUNA": [
        // Luna creciente (con un corte más suave)
        { type: "circle", x1: 50, y1: 50, radius: 20 }, // Círculo exterior
        { type: "circle", x1: 42, y1: 50, radius: 18 }, // Círculo interior para la forma creciente
        // Cráteres (varios tamaños y posiciones)
        { type: "circle", x1: 55, y1: 40, radius: 3 },
        { type: "circle", x1: 60, y1: 50, radius: 2.5 },
        { type: "circle", x1: 52, y1: 58, radius: 4 },
        { type: "circle", x1: 48, y1: 45, radius: 1.5 }
    ],

    "ESTRELLA": [
        // Estrella de 5 puntas (proporciones más precisas)
        { x1: 50, y1: 20, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 75, y2: 45 },
        { x1: 75, y1: 45, x2: 60, y2: 60 }, { x1: 60, y1: 60, x2: 65, y2: 80 },
        { x1: 65, y1: 80, x2: 50, y2: 70 }, { x1: 50, y1: 70, x2: 35, y2: 80 },
        { x1: 35, y1: 80, x2: 40, y2: 60 }, { x1: 40, y1: 60, x2: 25, y2: 45 },
        { x1: 25, y1: 45, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 50, y2: 20 },
        // Brillo (múltiples líneas finas saliendo del centro)
        { x1: 50, y1: 50, x2: 50, y2: 30 }, { x1: 50, y1: 50, x2: 65, y2: 40 },
        { x1: 50, y1: 50, x2: 60, y2: 65 }, { x1: 50, y1: 50, x2: 35, y2: 65 },
        { x1: 50, y1: 50, x2: 35, y2: 40 }
    ],

    "AUTO": [
        // Chasis inferior y parachoques
        { x1: 15, y1: 75, x2: 85, y2: 75 },
        { x1: 15, y1: 75, x2: 10, y2: 70 }, { x1: 85, y1: 75, x2: 90, y2: 70 },
        // Carrocería (más aerodinámica)
        { x1: 10, y1: 70, x2: 10, y2: 60 }, // Frente
        { x1: 10, y1: 60, x2: 25, y2: 50 }, // Capó
        { x1: 25, y1: 50, x2: 35, y2: 40 }, // Parabrisas
        { x1: 35, y1: 40, x2: 65, y2: 40 }, // Techo
        { x1: 65, y1: 40, x2: 80, y2: 50 }, // Ventana trasera
        { x1: 80, y1: 50, x2: 90, y2: 60 }, // Maletero
        { x1: 90, y1: 60, x2: 90, y2: 70 }, // Trasera
        // Ruedas (Con detalle interior/Hubcap)
        { type: "circle", x1: 25, y1: 75, radius: 8 },
        { type: "circle", x1: 25, y1: 75, radius: 3 }, // Hubcap
        { type: "circle", x1: 75, y1: 75, radius: 8 },
        { type: "circle", x1: 75, y1: 75, radius: 3 }, // Hubcap
        // Ventanas y Puertas
        { x1: 35, y1: 40, x2: 35, y2: 55 }, { x1: 65, y1: 40, x2: 65, y2: 55 },
        { x1: 50, y1: 40, x2: 50, y2: 75 }, // División de puertas
        // Detalles (Manija y Faro)
        { x1: 40, y1: 60, x2: 45, y2: 60 }, // Manija delantera
        { x1: 10, y1: 65, x2: 15, y2: 65 }, { x1: 15, y1: 65, x2: 15, y2: 70 } // Faro
    ],

    "BICICLETA": [
        // Ruedas (con rayos y válvula)
        { type: "circle", x1: 35, y1: 65, radius: 10 }, { type: "circle", x1: 35, y1: 65, radius: 1 }, // Válvula
        { x1: 35, y1: 55, x2: 35, y2: 75 }, { x1: 25, y1: 65, x2: 45, y2: 65 }, // Rayos
        { type: "circle", x1: 65, y1: 65, radius: 10 }, { type: "circle", x1: 65, y1: 65, radius: 1 }, // Válvula
        { x1: 65, y1: 55, x2: 65, y2: 75 }, { x1: 55, y1: 65, x2: 75, y2: 65 }, // Rayos
        // Cuadro principal (más triángulos y estructura)
        { x1: 35, y1: 65, x2: 50, y2: 55 }, { x1: 50, y1: 55, x2: 65, y2: 65 },
        { x1: 50, y1: 55, x2: 40, y2: 45 }, { x1: 40, y1: 45, x2: 35, y2: 65 }, // Tubo diagonal
        { x1: 50, y1: 55, x2: 50, y2: 50 }, // Tubo de asiento
        // Asiento (con forma de sillín)
        { x1: 48, y1: 48, x2: 52, y2: 48 }, { x1: 48, y1: 48, x2: 45, y2: 45 }, { x1: 52, y1: 48, x2: 55, y2: 45 }, // Sillín
        // Manillar (con puños)
        { x1: 40, y1: 45, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 55, y2: 40 }, // Manillar
        { x1: 40, y1: 45, x2: 38, y2: 45 }, { x1: 55, y1: 40, x2: 57, y2: 40 }, // Puños
        // Pedal y cadena (detalles)
        { x1: 50, y1: 65, x2: 52, y2: 68 }, { x1: 52, y1: 68, x2: 55, y2: 65 }, // Pedal
        { x1: 50, y1: 65, x2: 60, y2: 65 } // Cadena (línea)
    ],

    "BARCO": [
        // Casco (más curvado y con profundidad)
        { x1: 20, y1: 70, x2: 80, y2: 70 }, // Base
        { x1: 20, y1: 70, x2: 25, y2: 60 }, { x1: 80, y1: 70, x2: 75, y2: 60 }, // Lados del casco
        { x1: 25, y1: 60, x2: 75, y2: 60 },
        { x1: 28, y1: 62, x2: 72, y2: 62 }, // Borde interior del casco
        // Mástil (más grueso y con uniones)
        { x1: 50, y1: 60, x2: 50, y2: 30 }, { x1: 48, y1: 60, x2: 48, y2: 30 }, // Grosor del mástil
        { x1: 48, y1: 30, x2: 52, y2: 30 }, // Parte superior del mástil
        // Vela (más voluminosa y con líneas de viento)
        { x1: 50, y1: 30, x2: 65, y2: 40 }, { x1: 65, y1: 40, x2: 50, y2: 55 }, // Contorno de la vela
        { x1: 52, y1: 35, x2: 60, y2: 40 }, { x1: 52, y1: 40, x2: 60, y2: 45 }, // Líneas de viento en la vela
        // Bandera (ondeando)
        { x1: 50, y1: 30, x2: 55, y2: 25 }, { x1: 55, y1: 25, x2: 50, y2: 20 }, { x1: 50, y1: 20, x2: 50, y2: 30 }
    ],

    "PESCADO": [
        // Cuerpo (más hidrodinámico y con escamas)
        { x1: 30, y1: 50, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 75, y2: 50 }, // Lomo
        { x1: 30, y1: 50, x2: 70, y2: 55 }, { x1: 70, y1: 55, x2: 75, y2: 50 }, // Vientre
        { x1: 75, y1: 50, x2: 80, y2: 48 }, // Transición a la cola
        // Cola (más bifurcada y detallada)
        { x1: 80, y1: 48, x2: 85, y2: 40 }, { x1: 85, y1: 40, x2: 85, y2: 60 }, { x1: 85, y1: 60, x2: 80, y2: 52 },
        // Aletas (con rayos)
        { x1: 40, y1: 45, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 40, y2: 50 }, // Aleta dorsal
        { x1: 40, y1: 55, x2: 45, y2: 60 }, { x1: 45, y1: 60, x2: 40, y2: 50 }, // Aleta ventral
        // Ojo y Boca (con detalle)
        { type: "circle", x1: 35, y1: 48, radius: 1.5 }, { type: "circle", x1: 34.5, y1: 47.5, radius: 0.5 }, // Ojo con brillo
        { x1: 30, y1: 50, x2: 32, y2: 53 }, { x1: 32, y1: 53, x2: 30, y2: 52 } // Boca
    ],

    "MANZANA": [
        { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno
        // Tallito (más realista)
        { x1: 48, y1: 30, x2: 52, y2: 30 }, { x1: 50, y1: 30, x2: 50, y2: 25 }, // Grosor del tallo
        // Hoja (con vena)
        { x1: 50, y1: 25, x2: 55, y2: 28 }, { x1: 55, y1: 28, x2: 52, y2: 32 }, { x1: 52, y1: 32, x2: 50, y2: 25 },
        { x1: 52, y1: 27, x2: 54, y2: 30 } // Vena de la hoja
    ],

    "PLATO": [
        { type: "circle", x1: 50, y1: 50, radius: 25 }, // Borde exterior
        { type: "circle", x1: 50, y1: 50, radius: 20 }, // Borde interior
        // Detalles para dar profundidad y relieve
        { x1: 30, y1: 50, x2: 32, y2: 52 }, { x1: 70, y1: 50, x2: 68, y2: 52 }, // Curvas sutiles
        { x1: 50, y1: 25, x2: 52, y2: 27 }, { x1: 50, y1: 75, x2: 48, y2: 73 }
    ],

    "CEREBRO": [
        // Hemisferios con surcos más detallados y orgánicos
        { 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: 65, y2: 50 },
        { x1: 65, y1: 50, x2: 55, y2: 55 }, { x1: 55, y1: 55, x2: 45, y2: 55 },
        { x1: 45, y1: 55, x2: 35, y2: 50 }, { x1: 35, y1: 50, x2: 30, y2: 40 }, // Contorno exterior
        { x1: 50, y1: 30, x2: 50, y2: 55 }, // Surco central (más profundo)
        // Surcos secundarios
        { x1: 35, y1: 35, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 40, y2: 48 }, // Surco 1
        { x1: 55, y1: 35, x2: 65, y2: 40 }, { x1: 65, y1: 40, x2: 60, y2: 48 }, // Surco 2
        { x1: 40, y1: 32, x2: 35, y2: 38 }, { x1: 60, y1: 32, x2: 65, y2: 38 } // Surcos superiores
    ],

    "CORAZON": [
        // Corazón con curvas más suaves y volumen
        { 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: 35 }, // Curva superior izquierda
        { x1: 50, y1: 35, 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 }, // Curva superior derecha y base
        // Línea central (para dar forma al lóbulo)
        { x1: 50, y1: 35, x2: 50, y2: 65 }
    ],

    "MANO": [
        // Palma y muñeca (base más orgánica)
        { x1: 50, y1: 80, x2: 40, y2: 75 }, { x1: 40, y1: 75, x2: 40, y2: 60 },
        { x1: 50, y1: 80, x2: 70, y2: 75 }, { x1: 70, y1: 75, x2: 70, y2: 60 },
        { x1: 40, y1: 60, x2: 70, y2: 60 },
        // Pulgar
        { x1: 40, y1: 65, x2: 35, y2: 55 }, { x1: 35, y1: 55, x2: 38, y2: 50 },
        { x1: 38, y1: 50, x2: 45, y2: 58 },
        // Índice
        { x1: 45, y1: 60, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 48, y2: 35 },
        { x1: 48, y1: 35, x2: 52, y2: 35 }, { x1: 52, y1: 35, x2: 52, y2: 60 },
        // Medio
        { x1: 52, y1: 60, x2: 52, y2: 32 }, { x1: 52, y1: 32, x2: 55, y2: 30 },
        { x1: 55, y1: 30, x2: 58, y2: 32 }, { x1: 58, y1: 32, x2: 58, y2: 60 },
        // Anular
        { x1: 58, y1: 60, x2: 58, y2: 35 }, { x1: 58, y1: 35, x2: 61, y2: 33 },
        { x1: 61, y1: 33, x2: 64, y2: 35 }, { x1: 64, y1: 35, x2: 64, y2: 60 },
        // Meñique
        { x1: 64, y1: 60, x2: 64, y2: 45 }, { x1: 64, y1: 45, x2: 67, y2: 43 },
        { x1: 67, y1: 43, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 70, y2: 60 },
        // Detalles (Nudillos/Líneas de la palma)
        { x1: 48, y1: 55, x2: 55, y2: 55 }, { x1: 60, y1: 55, x2: 65, y2: 55 }
    ],

    "OJO": [
        // Forma almendrada del ojo (simulada con segmentos)
        { x1: 30, y1: 50, x2: 40, y2: 42 }, { x1: 40, y1: 42, x2: 60, y2: 42 },
        { x1: 60, y1: 42, x2: 70, y2: 50 }, // Párpado superior
        { x1: 30, y1: 50, x2: 40, y2: 58 }, { x1: 40, y1: 58, x2: 60, y2: 58 },
        { x1: 60, y1: 58, x2: 70, y2: 50 }, // Párpado inferior
        // Iris y Pupila
        { type: "circle", x1: 50, y1: 50, radius: 10 }, // Iris
        { type: "circle", x1: 50, y1: 50, radius: 4 },  // Pupila
        // Brillo (Highlight) - da vida al ojo
        { type: "circle", x1: 47, y1: 47, radius: 1 },
        // Pestañas (varias líneas finas)
        { x1: 40, y1: 42, x2: 38, y2: 38 }, { x1: 45, y1: 42, x2: 45, y2: 37 },
        { x1: 50, y1: 42, x2: 52, y2: 37 }, { x1: 55, y1: 42, x2: 57, y2: 38 },
        { x1: 60, y1: 42, x2: 62, y2: 39 },
        // Pliegue del párpado superior
        { x1: 35, y1: 40, x2: 50, y2: 38 }, { x1: 50, y1: 38, x2: 65, y2: 40 }
    ],

    "BOCA": [
        // Contorno de labios más detallado y curvo
        { x1: 35, y1: 50, x2: 45, y2: 45 }, { x1: 45, y1: 45, x2: 55, y2: 45 }, { x1: 55, y1: 45, x2: 65, y2: 50 }, // Labio superior
        { x1: 35, y1: 50, x2: 45, y2: 55 }, { x1: 45, y1: 55, x2: 55, y2: 55 }, { x1: 55, y1: 55, x2: 65, y2: 50 }, // Labio inferior
        // Comisuras y pliegues
        { x1: 35, y1: 50, x2: 33, y2: 52 }, { x1: 65, y1: 50, x2: 67, y2: 52 },
        { x1: 40, y1: 50, x2: 40, y2: 52 }, { x1: 60, y1: 50, x2: 60, y2: 52 } // Líneas internas
    ],

    "NARIZ": [
        // Puente de la nariz (con detalle)
        { x1: 50, y1: 40, x2: 45, y2: 50 }, { x1: 50, y1: 40, x2: 55, y2: 50 },
        // Base de la nariz y fosas nasales (más detalladas)
        { x1: 45, y1: 50, x2: 45, y2: 55 }, { x1: 55, y1: 50, x2: 55, y2: 55 },
        { x1: 45, y1: 55, x2: 55, y2: 55 },
        { type: "circle", x1: 47, y1: 57, radius: 1 }, { type: "circle", x1: 53, y1: 57, radius: 1 }, // Fosas nasales
        // Sombreado bajo la nariz
        { x1: 46, y1: 58, x2: 54, y2: 58 }
    ],

    "OREJA": [
        // Contorno exterior (más orgánico y con lóbulo)
        { x1: 50, y1: 40, x2: 40, y2: 45 }, { x1: 40, y1: 45, x2: 38, y2: 55 },
        { x1: 38, y1: 55, x2: 45, y2: 65 }, { x1: 45, y1: 65, x2: 50, y2: 68 }, // Lóbulo
        { x1: 50, y1: 68, x2: 55, y2: 65 }, { x1: 55, y1: 65, x2: 62, y2: 55 },
        { x1: 62, y1: 55, x2: 60, y2: 45 }, { x1: 60, y1: 45, x2: 50, y1: 40 },
        // Detalles internos (conchas de la oreja)
        { x1: 45, y1: 48, x2: 42, y2: 52 }, { x1: 42, y1: 52, x2: 45, y2: 58 },
        { x1: 55, y1: 48, x2: 58, y2: 52 }, { x1: 58, y1: 52, x2: 55, y2: 58 },
        { x1: 50, y1: 50, x2: 50, y2: 55 } // Conector
    ],

    "DIENTE": [
        // Cuerpo del diente (más natural y redondeado)
        { x1: 45, y1: 30, x2: 55, y2: 30 }, // Parte superior
        { x1: 45, y1: 30, x2: 43, y2: 50 }, { x1: 55, y1: 30, x2: 57, y2: 50 }, // Curvas laterales
        { x1: 43, y1: 50, x2: 45, y2: 60 }, { x1: 57, y1: 50, x2: 55, y2: 60 }, // Transición a la encía
        { x1: 45, y1: 60, x2: 55, y2: 60 }, // Borde inferior (encía)
        // Raíces (más definidas y con separación)
        { x1: 46, y1: 60, x2: 44, y2: 68 }, { x1: 44, y1: 68, x2: 46, y2: 70 },
        { x1: 54, y1: 60, x2: 56, y2: 68 }, { x1: 56, y1: 68, x2: 54, y2: 70 },
        // Encía (curvada)
        { x1: 40, y1: 65, x2: 50, y2: 68 }, { x1: 50, y1: 68, x2: 60, y2: 65 }
    ],

    "PAN": [
        // Barra de pan (más redondeada y con volumen)
        { x1: 20, y1: 60, x2: 80, y2: 60 }, // Base
        { x1: 20, y1: 60, x2: 22, y2: 50 }, { x1: 80, y1: 60, x2: 78, y2: 50 }, // Laterales
        { x1: 22, y1: 50, x2: 78, y2: 50 }, // Parte superior
        { x1: 20, y1: 60, x2: 25, y2: 70 }, { x1: 80, y1: 60, x2: 75, y2: 70 }, // Sombras de base
        { x1: 25, y1: 70, x2: 75, y2: 70 },
        // Cortes (más profundos y definidos)
        { x1: 30, y1: 50, x2: 35, y2: 60 }, { x1: 35, y1: 60, x2: 40, y2: 50 },
        { x1: 45, y1: 50, x2: 50, y2: 60 }, { x1: 50, y1: 60, x2: 55, y2: 50 },
        { x1: 60, y1: 50, x2: 65, y2: 60 }, { x1: 65, y1: 60, x2: 70, y2: 50 }
    ],

    "QUESO": [
        // Trozo de queso triangular (con grosor y textura)
        { x1: 30, y1: 70, x2: 70, y2: 70 }, // Base
        { x1: 30, y1: 70, x2: 50, y2: 30 }, // Lado izquierdo
        { x1: 70, y1: 70, x2: 50, y2: 30 }, // Lado derecho
        { x1: 35, y1: 68, x2: 50, y2: 35 }, { x1: 65, y1: 68, x2: 50, y2: 35 }, // Grosor y cara superior
        // Agujeros (más irregulares)
        { type: "circle", x1: 45, y1: 55, radius: 5 },
        { type: "circle", x1: 58, y1: 60, radius: 4 },
        { type: "circle", x1: 40, y1: 65, radius: 3 },
        { type: "circle", x1: 50, y1: 45, radius: 2 } // Agujero pequeño
    ],

    "HUEVO": [
        // Contorno de huevo (más ovalado en la parte superior)
        { type: "circle", x1: 50, y1: 55, radius: 20 }, // Base redonda
        { x1: 50, y1: 35, x2: 45, y2: 30 }, { x1: 50, y1: 35, x2: 55, y2: 30 }, // Parte superior ovalada
        { x1: 45, y1: 30, x2: 42, y2: 35 }, { x1: 55, y1: 30, x2: 58, y2: 35 },
        { x1: 42, y1: 35, x2: 30, y2: 55 }, { x1: 58, y1: 35, x2: 70, y2: 55 },
        // Yema (con brillo)
        { type: "circle", x1: 50, y1: 50, radius: 8 },
        { type: "circle", x1: 48, y1: 48, radius: 1 } // Brillo en la yema
    ],

    "CARNE": [
        // Trozo de carne (forma más irregular y orgánica)
        { x1: 30, y1: 50, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 75, y2: 60 },
        { x1: 75, y1: 60, x2: 60, y2: 70 }, { x1: 60, y1: 70, x2: 35, y2: 65 },
        { x1: 35, y1: 65, x2: 30, y2: 50 },
        // Hueso (más detallado)
        { x1: 50, y1: 50, x2: 50, y2: 35 }, { x1: 45, y1: 35, x2: 55, y2: 35 }, // Hueso principal
        { type: "circle", x1: 45, y1: 35, radius: 3 }, { type: "circle", x1: 55, y1: 35, radius: 3 }, // Nudillos del hueso
        // Líneas de grasa/textura
        { x1: 40, y1: 55, x2: 50, y2: 58 }, { x1: 60, y1: 50, x2: 65, y2: 55 }
    ],

    "POLLO": [
        // Pollo asado (más volumen y piernas definidas)
        { 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
        // Piernas (muslos y contramuslos)
        { x1: 35, y1: 58, x2: 25, y2: 55 }, { x1: 25, y1: 55, x2: 20, y2: 60 }, // Pierna izq
        { x1: 65, y1: 58, x2: 75, y2: 55 }, { x1: 75, y1: 55, x2: 80, y2: 60 }, // Pierna der
        // Textura de piel/dorado
        { x1: 40, y1: 50, x2: 50, y2: 48 }, { x1: 50, y1: 48, x2: 60, y2: 50 } // Líneas para sombreado
    ],

    "ARROZ": [
        // Bol (con grosor y apertura)
        { type: "circle", x1: 50, y1: 70, radius: 20 }, // Base del bol
        { x1: 30, y1: 70, x2: 35, y2: 60 }, { x1: 70, y1: 70, x2: 65, y2: 60 }, // Lados inclinados
        { x1: 35, y1: 60, x2: 65, y2: 60 }, // Borde superior del bol
        // Arroz (montón de puntos o pequeñas líneas)
        { type: "circle", x1: 50, y1: 55, radius: 15 }, // Simular el montón
        { x1: 45, y1: 50, x2: 46, y2: 50 }, { x1: 55, y1: 52, x2: 56, y2: 52 }, // Granos de arroz (puntos)
        { x1: 48, y1: 58, x2: 49, y2: 58 }, { x1: 52, y1: 47, x2: 53, y2: 47 },
        // Palillos (con detalle y en ángulo)
        { x1: 40, y1: 55, x2: 40, y2: 35 }, { x1: 40, y1: 35, x2: 42, y2: 30 }, // Palillo 1
        { x1: 42, y1: 30, x2: 42, y2: 50 },
        { x1: 45, y1: 55, x2: 45, y2: 35 }, { x1: 45, y1: 35, x2: 47, y2: 30 }, // Palillo 2
        { x1: 47, y1: 30, x2: 47, y2: 50 }
    ],

    "PASTA": [
        // Plato (con borde y sombreado para profundidad)
        { type: "circle", x1: 50, y1: 65, radius: 20 }, // Borde exterior
        { type: "circle", x1: 50, y1: 65, radius: 18 }, // Borde interior
        { x1: 32, y1: 65, x2: 35, y2: 68 }, { x1: 68, y1: 65, x2: 65, y2: 68 }, // Sombreado del plato
        // Pasta (espagueti en un montón)
        { type: "circle", x1: 50, y1: 50, radius: 10 }, // Base del montón
        { x1: 40, y1: 50, x2: 45, y2: 45 }, { x1: 45, y1: 45, x2: 50, y2: 50 }, // Hilos de pasta
        { x1: 50, y1: 50, x2: 55, y2: 45 }, { x1: 55, y1: 45, x2: 60, y2: 50 },
        { x1: 45, y1: 55, x2: 50, y2: 50 }, { x1: 55, y1: 55, x2: 50, y2: 50 },
        // Tenedor (con dientes)
        { x1: 48, y1: 50, x2: 48, y2: 40 }, { x1: 52, y1: 50, x2: 52, y2: 40 }, // Mangos
        { x1: 47, y1: 40, x2: 47, y2: 35 }, { x1: 49, y1: 40, x2: 49, y2: 35 }, // Dientes
        { x1: 51, y1: 40, x2: 51, y2: 35 }, { x1: 53, y1: 40, x2: 53, y2: 35 }
    ],

    "FRUTA": [
        // Canasta (con textura de mimbre y asa)
        { x1: 30, y1: 70, x2: 70, y2: 70 }, // Base
        { x1: 30, y1: 70, x2: 35, y2: 60 }, { x1: 70, y1: 70, x2: 65, y2: 60 }, // Lados inclinados
        { x1: 35, y1: 60, x2: 65, y2: 60 }, // Borde superior de la canasta
        { x1: 37, y1: 62, x2: 63, y2: 62 }, { x1: 39, y1: 64, x2: 61, y2: 64 }, // Textura de mimbre
        { x1: 45, y1: 60, x2: 45, y2: 50 }, { x1: 55, y1: 60, x2: 55, y2: 50 }, // Asa
        { x1: 45, y1: 50, x2: 55, y2: 50 },
        // Frutas (varias formas y tamaños)
        { type: "circle", x1: 40, y1: 55, radius: 5 }, // Manzana
        { type: "circle", x1: 60, y1: 55, radius: 4 }, // Naranja
        { x1: 50, y1: 48, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 50, y2: 48 } // Plátano
    ],

    "UVA": [
        // Racimo de uvas (más densas y con superposición)
        { type: "circle", x1: 50, y1: 40, radius: 5 }, // Uva superior
        { 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 },
        { type: "circle", x1: 45, y1: 64, radius: 5 }, { type: "circle", x1: 55, y1: 64, radius: 5 },
        { type: "circle", x1: 50, y1: 72, radius: 5 }, // Uva inferior
        // Tallo (más orgánico y con rama pequeña)
        { x1: 50, y1: 35, x2: 50, y2: 25 },
        { x1: 50, y1: 30, x2: 55, y2: 28 }, { x1: 55, y1: 28, x2: 52, y2: 32 } // Rama
    ],

    "PIÑA": [
        // Cuerpo ovalado (con textura de rombos)
        { x1: 40, y1: 40, x2: 60, y2: 40 }, { x1: 40, y1: 40, x2: 35, y2: 60 },
        { x1: 60, y1: 40, x2: 65, y2: 60 }, { x1: 35, y1: 60, x2: 65, y2: 60 },
        // Textura de rombos
        { x1: 40, y1: 45, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 50, y2: 45 }, // Fila 1
        { x1: 50, y1: 45, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 60, y2: 45 },
        { x1: 37, y1: 50, x2: 42, y2: 45 }, { x1: 42, y1: 45, x2: 47, y2: 50 }, // Fila 2
        { x1: 47, y1: 50, x2: 52, y2: 45 }, { x1: 52, y1: 45, x2: 57, y2: 50 },
        { x1: 57, y1: 50, x2: 62, y2: 45 },
        // Hojas superiores (más puntiagudas y variadas)
        { x1: 45, y1: 38, x2: 40, y2: 25 }, { x1: 50, y1: 38, x2: 45, y2: 22 },
        { x1: 55, y1: 38, x2: 50, y2: 25 }, { x1: 60, y1: 38, x2: 55, y2: 22 }
    ],

    "KIWI": [
        { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno exterior
        { type: "circle", x1: 50, y1: 50, radius: 5 }, // Centro
        // Líneas internas (más para simular las semillas y la pulpa)
        { x1: 50, y1: 30, x2: 50, y2: 70 }, { x1: 30, y1: 50, x2: 70, y2: 50 },
        { x1: 35, y1: 35, x2: 65, y2: 65 }, { x1: 35, y1: 65, x2: 65, y2: 35 },
        { x1: 40, y1: 30, x2: 40, y2: 70 }, { x1: 60, y1: 30, x2: 60, y2: 70 }, // Líneas de la pulpa
        { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 30, y1: 60, x2: 70, y2: 60 },
        // Semillas (puntos pequeños alrededor del centro)
        { type: "circle", x1: 42, y1: 48, radius: 0.5 }, { type: "circle", x1: 42, y1: 52, radius: 0.5 },
        { type: "circle", x1: 48, y1: 42, radius: 0.5 }, { type: "circle", x1: 52, y1: 42, radius: 0.5 },
        { type: "circle", x1: 58, y1: 48, radius: 0.5 }, { type: "circle", x1: 58, y1: 52, radius: 0.5 },
        { type: "circle", x1: 48, y1: 58, radius: 0.5 }, { type: "circle", x1: 52, y1: 58, radius: 0.5 }
    ],

    "CHOCOLATE": [
        // Barra de chocolate (con grosor y divisiones en 3D)
        { 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 }, // Cara frontal
        { x1: 30, y1: 45, x2: 25, y2: 40 }, { x1: 70, y1: 45, x2: 65, y2: 40 }, // Borde superior en perspectiva
        { x1: 25, y1: 40, x2: 65, y2: 40 },
        { x1: 25, y1: 40, x2: 25, y2: 60 }, { x1: 65, y1: 40, x2: 65, y2: 60 }, // Lados en perspectiva
        { x1: 25, y1: 60, x2: 30, y2: 65 }, { x1: 65, y1: 60, x2: 70, y2: 65 },
        // Divisiones (con líneas que simulan los cuadrados)
        { x1: 35, y1: 45, x2: 35, y2: 65 }, { x1: 45, y1: 45, x2: 45, y2: 65 },
        { x1: 55, y1: 45, x2: 55, y2: 65 }, { x1: 65, y1: 45, x2: 65, y2: 65 },
        { x1: 30, y1: 55, x2: 70, y2: 55 }
    ],

    "HELADO": [
        // Cono (con textura de waffle)
        { x1: 40, y1: 70, x2: 50, y2: 30 }, { x1: 60, y1: 70, x2: 50, y2: 30 },
        { x1: 40, y1: 70, x2: 60, y2: 70 },
        { x1: 45, y1: 65, x2: 55, y2: 65 }, { x1: 42, y1: 60, x2: 58, y2: 60 }, // Líneas horizontales del waffle
        { x1: 47, y1: 70, x2: 50, y2: 30 }, { x1: 53, y1: 70, x2: 50, y2: 30 }, // Líneas verticales del waffle
        // Bola de helado (con derretimiento)
        { type: "circle", x1: 50, y1: 30, radius: 15 },
        { x1: 40, y1: 35, x2: 42, y2: 40 }, { x1: 42, y1: 40, x2: 40, y2: 42 }, // Gotas simuladas
        { x1: 60, y1: 35, x2: 58, y2: 40 }, { x1: 58, y1: 40, x2: 60, y2: 42 }
    ],

    "GALLETA": [
        { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno (más irregular para un aspecto casero)
        { x1: 35, y1: 45, x2: 38, y2: 42 }, { x1: 42, y1: 38, x2: 45, y2: 35 },
        { x1: 65, y1: 45, x2: 62, y2: 42 }, { x1: 58, y1: 38, x2: 55, y2: 35 },
        // Chispas de chocolate (con un punto central para dar volumen)
        { type: "circle", x1: 40, y1: 45, radius: 2 }, { type: "circle", x1: 40, y1: 45, radius: 0.5 },
        { type: "circle", x1: 60, y1: 45, radius: 2 }, { type: "circle", x1: 60, y1: 45, radius: 0.5 },
        { type: "circle", x1: 50, y1: 58, radius: 2 }, { type: "circle", x1: 50, y1: 58, radius: 0.5 },
        { type: "circle", x1: 45, y1: 52, radius: 1.5 }, { type: "circle", x1: 55, y1: 52, radius: 1.5 }
    ],

    "CARAMELO": [
        // Cuerpo central (más grueso y con reflejo)
        { x1: 30, y1: 50, x2: 70, y2: 50 },
        { x1: 30, y1: 52, x2: 70, y2: 52 }, // Grosor
        { x1: 35, y1: 50, x2: 65, y2: 50 }, // Línea de reflejo
        // Envoltorio (más plisado y con puntas definidas)
        { x1: 25, y1: 45, x2: 30, y2: 50 }, { x1: 30, y1: 50, x2: 25, y2: 55 },
        { x1: 20, y1: 48, x2: 25, y2: 45 }, { x1: 20, y1: 52, x2: 25, y2: 55 }, // Pliegues izq
        { x1: 70, y1: 50, x2: 75, y2: 45 }, { x1: 75, y1: 45, x2: 70, y2: 50 },
        { x1: 75, y1: 50, x2: 75, y2: 55 }, { x1: 70, y1: 50, x2: 80, y2: 48 }, // Pliegues der
        { x1: 80, y1: 48, x2: 75, y2: 45 }, { x1: 80, y1: 52, x2: 75, y2: 55 }
    ],

    "TARTA": [
        // Rebanada de tarta (con capas y textura de crema)
        { 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 principal
        // Capas internas
        { x1: 40, y1: 45, x2: 60, y2: 45 }, // Capa 1
        { x1: 35, y1: 55, x2: 65, y2: 55 }, // Capa 2
        // Textura de crema/glaseado
        { x1: 50, y1: 30, x2: 50, y2: 28 }, { x1: 48, y1: 28, x2: 52, y2: 28 }, // Topping
        { x1: 30, y1: 70, x2: 32, y2: 68 }, { x1: 70, y1: 70, x2: 68, y2: 68 } // Borde inferior
    ],

    "PIZZA": [
        // Rebanada de pizza (con borde y ingredientes)
        { 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 de la rebanada
        // Borde de la corteza
        { x1: 50, y1: 30, x2: 40, y2: 35 }, { x1: 40, y1: 35, x2: 32, y2: 65 },
        { x1: 32, y1: 65, x2: 30, y2: 70 }, // Borde izquierdo
        { x1: 50, y1: 30, x2: 60, y2: 35 }, { x1: 60, y1: 35, x2: 68, y2: 65 },
        { x1: 68, y1: 65, x2: 70, y2: 70 }, // Borde derecho
        // Pepperoni (con detalle interior)
        { type: "circle", x1: 40, y1: 50, radius: 3 }, { type: "circle", x1: 40, y1: 50, radius: 1 },
        { type: "circle", x1: 60, y1: 55, radius: 3 }, { type: "circle", x1: 60, y1: 55, radius: 1 },
        { type: "circle", x1: 50, y1: 40, radius: 2.5 } // Otro pepperoni
    ],

    "HAMBURGUESA": [
        // Pan superior (curvo y con semillas)
        { x1: 30, y1: 40, x2: 70, y2: 40 }, { x1: 30, y1: 40, x2: 25, y2: 45 },
        { x1: 70, y1: 40, x2: 75, y2: 45 }, { x1: 25, y1: 45, x2: 75, y2: 45 }, // Curva superior
        { type: "circle", x1: 40, y1: 42, radius: 0.5 }, { type: "circle", x1: 50, y1: 42, radius: 0.5 }, { type: "circle", x1: 60, y1: 42, radius: 0.5 }, // Semillas
        // Lechuga/Tomate (línea ondulada)
        { x1: 25, y1: 45, x2: 30, y2: 48 }, { x1: 30, y1: 48, x2: 40, y2: 46 }, { x1: 40, y1: 46, x2: 50, y2: 48 },
        { x1: 50, y1: 48, x2: 60, y2: 46 }, { x1: 60, y1: 46, x2: 70, y2: 48 }, { x1: 70, y1: 48, x2: 75, y2: 45 },
        // Carne (con textura)
        { x1: 28, y1: 50, x2: 72, y2: 50 }, { x1: 28, y1: 50, x2: 28, y2: 55 },
        { x1: 72, y1: 50, x2: 72, y2: 55 }, { x1: 28, y1: 55, x2: 72, y2: 55 },
        { x1: 35, y1: 52, x2: 38, y2: 52 }, { x1: 45, y1: 53, x2: 48, y2: 53 }, // Textura
        // Pan inferior (curvo)
        { x1: 25, y1: 60, x2: 75, y2: 60 }, { x1: 25, y1: 60, x2: 30, y2: 55 },
        { x1: 75, y1: 60, x2: 70, y2: 55 }
    ],

    "PERRITO": [
        // Salchicha (con textura y ligeramente curva)
        { x1: 30, y1: 50, x2: 70, y2: 50 }, { x1: 30, y1: 50, x2: 30, y2: 53 },
        { x1: 70, y1: 50, x2: 70, y2: 53 }, { x1: 30, y1: 53, x2: 70, y2: 53 },
        { x1: 40, y1: 51, x2: 40, y2: 52 }, { x1: 50, y1: 51, x2: 50, y2: 52 }, { x1: 60, y1: 51, x2: 60, y2: 52 }, // Rayas de la salchicha
        // Bollo (más abierto y con textura)
        { x1: 25, y1: 55, x2: 75, y2: 55 }, // Borde superior del bollo
        { x1: 25, y1: 55, x2: 20, y2: 65 }, { x1: 75, y1: 55, x2: 80, y2: 65 }, // Lados del bollo
        { x1: 20, y1: 65, x2: 80, y2: 65 }, // Base del bollo
        { x1: 30, y1: 60, x2: 35, y2: 62 }, { x1: 65, y1: 60, x2: 60, y2: 62 } // Sombreado interno del bollo
    ],

    "MAPACHE": [
        // Cabeza (más definida)
        { type: "circle", x1: 50, y1: 50, radius: 20 },
        // Orejas (con forma de gota y pelaje)
        { x1: 40, y1: 35, x2: 35, y2: 40 }, { x1: 35, y1: 40, x2: 40, y2: 45 }, { x1: 40, y1: 45, x2: 45, y2: 40 },
        { x1: 60, y1: 35, x2: 65, y2: 40 }, { x1: 65, y1: 40, x2: 60, y2: 45 }, { x1: 60, y1: 45, x2: 55, y2: 40 },
        // Manchas de ojos (más oscuras y con forma)
        { x1: 38, y1: 45, x2: 42, y2: 45 }, { x1: 38, y1: 50, x2: 42, y2: 50 }, // Mancha izquierda
        { x1: 58, y1: 45, x2: 62, y2: 45 }, { x1: 58, y1: 50, x2: 62, y2: 50 }, // Mancha derecha
        // Nariz (triángulo invertido)
        { x1: 50, y1: 55, x2: 48, y2: 58 }, { x1: 48, y1: 58, x2: 52, y2: 58 }, { x1: 52, y1: 58, x2: 50, y2: 55 },
        // Hocico (forma de "U" invertida)
        { x1: 45, y1: 55, x2: 55, y2: 55 },
        // Ojos y bigotes (más detallados)
        { type: "circle", x1: 40, y1: 47, radius: 1 }, { type: "circle", x1: 60, y1: 47, radius: 1 },
        { x1: 45, y1: 55, x2: 35, y2: 53 }, { x1: 45, y1: 56, x2: 35, y2: 56 },
        { x1: 55, y1: 55, x2: 65, y2: 53 }, { x1: 55, y1: 56, x2: 65, y2: 56 }
    ],

    "ZORRO": [
        // Cabeza (forma más triangular)
        { x1: 50, y1: 65, x2: 35, y2: 50 }, { x1: 35, y1: 50, x2: 50, y2: 35 },
        { x1: 50, y1: 35, x2: 65, y2: 50 }, { x1: 65, y1: 50, x2: 50, y2: 65 },
        // Hocico (más puntiagudo)
        { x1: 50, y1: 60, x2: 45, y2: 55 }, { x1: 45, y1: 55, x2: 50, y2: 50 },
        { x1: 50, y1: 50, x2: 55, y2: 55 }, { x1: 55, y1: 55, x2: 50, y2: 60 },
        // Nariz
        { x1: 50, y1: 52, x2: 50, y2: 54 },
        // Orejas puntiagudas (con detalle interior)
        { x1: 45, y1: 35, x2: 40, y2: 25 }, { x1: 40, y1: 25, x2: 48, y2: 30 },
        { x1: 55, y1: 35, x2: 60, y2: 25 }, { x1: 60, y1: 25, x2: 52, y2: 30 },
        { x1: 44, y1: 30, x2: 46, y2: 28 }, { x1: 56, y1: 30, x2: 54, y2: 28 }, // Detalle interior
        // Ojos y bigotes
        { type: "circle", x1: 42, y1: 45, radius: 1 }, { type: "circle", x1: 58, y1: 45, radius: 1 },
        { x1: 45, y1: 55, x2: 35, y2: 53 }, { x1: 45, y1: 56, x2: 35, y2: 56 },
        { x1: 55, y1: 55, x2: 65, y2: 53 }, { x1: 55, y1: 56, x2: 65, y2: 56 }
    ],

    "LOBO": [
        // Cara (más angulosa y con hocico alargado)
        { x1: 50, y1: 65, x2: 35, y2: 50 }, { x1: 35, y1: 50, x2: 50, y2: 35 },
        { x1: 50, y1: 35, x2: 65, y2: 50 }, { x1: 65, y1: 50, x2: 50, y2: 65 },
        // Hocico alargado y aullando
        { x1: 50, y1: 60, x2: 45, y2: 50 }, { x1: 45, y1: 50, x2: 50, y2: 45 },
        { x1: 50, y1: 45, x2: 55, y2: 50 }, { x1: 55, y1: 50, x2: 50, y2: 60 },
        { x1: 50, y1: 60, x2: 50, y2: 70 }, // Boca abierta
        { x1: 48, y1: 68, x2: 52, y2: 68 }, // Dientes (simulados)
        // Orejas (más grandes y puntiagudas)
        { x1: 45, y1: 35, x2: 40, y2: 25 }, { x1: 40, y1: 25, x2: 48, y2: 30 },
        { x1: 55, y1: 35, x2: 60, y2: 25 }, { x1: 60, y1: 25, x2: 52, y2: 30 },
        // Ojos
        { type: "circle", x1: 42, y1: 45, radius: 1.5 }, { type: "circle", x1: 58, y1: 45, radius: 1.5 }
    ],

    "OSO": [
        // Cabeza (más definida y peluda)
        { type: "circle", x1: 50, y1: 50, radius: 20 },
        { x1: 30, y1: 45, x2: 32, y2: 42 }, { x1: 32, y1: 42, x2: 35, y2: 45 }, // Pelaje en el contorno
        // Orejas redondas (con detalle interior)
        { type: "circle", x1: 40, y1: 35, radius: 8 }, { type: "circle", x1: 40, y1: 35, radius: 4 }, // Oreja izq
        { type: "circle", x1: 60, y1: 35, radius: 8 }, { type: "circle", x1: 60, y1: 35, radius: 4 }, // Oreja der
        // Hocico (más prominente)
        { type: "circle", x1: 50, y1: 58, radius: 7 },
        { type: "circle", x1: 50, y1: 55, radius: 2 }, // Nariz
        // Ojos
        { type: "circle", x1: 45, y1: 48, radius: 1.5 }, { type: "circle", x1: 55, y1: 48, radius: 1.5 }
    ],

    "TIGRE": [
        // Cabeza (más cuadrada y fuerte)
        { type: "circle", x1: 50, y1: 50, radius: 25 },
        // Hocico (más amplio)
        { x1: 40, y1: 55, x2: 60, y2: 55 }, { x1: 40, y1: 55, x2: 35, y2: 60 },
        { x1: 60, y1: 55, x2: 65, y2: 60 }, { x1: 35, y1: 60, x2: 65, y2: 60 },
        // Ojos y Nariz
        { type: "circle", x1: 42, y1: 45, radius: 2 }, { type: "circle", x1: 58, y1: 45, radius: 2 },
        { x1: 50, y1: 58, x2: 50, y2: 60 },
        // Rayas (más variadas y angulares)
        { x1: 35, y1: 35, x2: 40, y2: 30 }, { x1: 40, y1: 30, x2: 45, y2: 35 }, // Raya superior izq
        { x1: 65, y1: 35, x2: 60, y2: 30 }, { x1: 60, y1: 30, x2: 55, y2: 35 }, // Raya superior der
        { x1: 30, y1: 50, x2: 35, y2: 50 }, { x1: 30, y1: 52, x2: 35, y2: 52 }, // Rayas laterales
        { x1: 70, y1: 50, x2: 65, y2: 50 }, { x1: 70, y1: 52, x2: 65, y2: 52 }
    ],

    "LEON": [
        // Cabeza (más grande para la melena)
        { type: "circle", x1: 50, y1: 50, radius: 25 },
        // Melena (líneas radiales para simular pelaje)
        { x1: 50, y1: 25, x2: 40, y2: 20 }, { x1: 50, y1: 25, x2: 60, y2: 20 },
        { x1: 50, y1: 75, x2: 40, y2: 80 }, { x1: 50, y1: 75, x2: 60, y2: 80 },
        { x1: 25, y1: 50, x2: 20, y2: 40 }, { x1: 25, y1: 50, x2: 20, y2: 60 },
        { x1: 75, y1: 50, x2: 80, y2: 40 }, { x1: 75, y1: 50, x2: 80, y2: 60 },
        // Cara interna (hocico y boca)
        { type: "circle", x1: 50, y1: 50, radius: 15 },
        { x1: 50, y1: 55, x2: 45, y2: 58 }, { x1: 45, y1: 58, x2: 55, y2: 58 }, { x1: 55, y1: 58, x2: 50, y2: 55 }, // Boca
        { type: "circle", x1: 50, y1: 52, radius: 1.5 }, // Nariz
        // Ojos
        { type: "circle", x1: 45, y1: 45, radius: 1.5 }, { type: "circle", x1: 55, y1: 45, radius: 1.5 }
    ],

    "ELEFANTE": [
        // Cabeza (con más forma)
        { type: "circle", x1: 50, y1: 50, radius: 20 },
        // Trompa (más curva y con arrugas)
        { x1: 50, y1: 60, x2: 55, y2: 70 }, { x1: 55, y1: 70, x2: 50, y2: 75 },
        { x1: 50, y1: 75, x2: 45, y2: 70 }, { x1: 45, y1: 70, x2: 50, y2: 60 },
        { x1: 50, y1: 65, x2: 50, y2: 68 }, { x1: 48, y1: 72, x2: 52, y2: 72 }, // Arrugas de la trompa
        // Orejas (grandes y colgantes)
        { x1: 35, y1: 40, x2: 25, y2: 55 }, { x1: 25, y2: 55, x2: 35, y2: 65 }, { x1: 35, y1: 65, x2: 40, y2: 55 }, { x1: 40, y2: 55, x2: 35, y2: 40 }, // Oreja 1
        { x1: 65, y1: 40, x2: 75, y2: 55 }, { x1: 75, y2: 55, x2: 65, y2: 65 }, { x1: 65, y1: 65, x2: 60, y2: 55 }, { x1: 60, y2: 55, x2: 65, y2: 40 }, // Oreja 2
        // Ojo
        { type: "circle", x1: 45, y1: 45, radius: 1.5 }
    ],

    "JIRAFA": [
        // Cuello largo (con grosor y manchas)
        { x1: 48, y1: 80, x2: 48, y2: 30 }, { x1: 52, y1: 80, x2: 52, y2: 30 }, // Grosor del cuello
        { x1: 48, y1: 70, x2: 52, y2: 70 }, { x1: 48, y1: 55, x2: 52, y2: 55 }, // Líneas de las manchas
        // Cabeza (más definida y con osiconos)
        { type: "circle", x1: 50, y1: 25, radius: 8 },
        { x1: 48, y1: 20, x2: 48, y2: 15 }, { x1: 52, y1: 20, x2: 52, y2: 15 }, // Osiconos
        { type: "circle", x1: 50, y1: 15, radius: 1 },
        // Hocico y ojos
        { x1: 45, y1: 30, x2: 55, y2: 30 }, // Hocico
        { type: "circle", x1: 47, y1: 27, radius: 1 }, { type: "circle", x1: 53, y1: 27, radius: 1 } // Ojos
    ],

    "MONO": [
        // Cuerpo (más curvado)
        { type: "circle", x1: 50, y1: 55, radius: 20 },
        // Cabeza (más pequeña y con cara)
        { type: "circle", x1: 50, y1: 30, radius: 10 },
        { type: "circle", x1: 50, y1: 32, radius: 5 }, // Cara interna
        // Orejas (redondas y prominentes)
        { type: "circle", x1: 40, y1: 25, radius: 5 }, { type: "circle", x1: 60, y1: 25, radius: 5 },
        // Cola (más larga y enroscada)
        { x1: 60, y1: 65, x2: 70, y2: 60 }, { x1: 70, y2: 60, x2: 75, y2: 70 }, { x1: 75, y2: 70, x2: 70, y2: 75 },
        // Brazos y piernas (simulados con líneas)
        { x1: 40, y1: 50, x2: 35, y2: 45 }, { x1: 60, y1: 50, x2: 65, y2: 45 },
        { x1: 45, y1: 70, x2: 40, y2: 75 }, { x1: 55, y1: 70, x2: 60, y2: 75 }
    ],

    "KOALA": [
        // Cuerpo (más peludo)
        { type: "circle", x1: 50, y1: 50, radius: 25 },
        { x1: 30, y1: 45, x2: 32, y2: 42 }, { x1: 32, y1: 42, x2: 35, y2: 45 }, // Pelaje en el contorno
        // Orejas grandes y peludas
        { type: "circle", x1: 40, y1: 35, radius: 10 }, { type: "circle", x1: 40, y1: 35, radius: 5 }, // Oreja izq
        { type: "circle", x1: 60, y1: 35, radius: 10 }, { type: "circle", x1: 60, y1: 35, radius: 5 }, // Oreja der
        // Nariz grande y aplanada
        { x1: 50, y1: 55, x2: 45, y2: 58 }, { x1: 45, y1: 58, x2: 55, y2: 58 }, { x1: 55, y1: 58, x2: 50, y2: 55 },
        // Ojos
        { type: "circle", x1: 45, y1: 48, radius: 1.5 }, { type: "circle", x1: 55, y1: 48, radius: 1.5 }
    ],

    "PINGUINO": [
        // Cuerpo ovalado (con vientre blanco y alas)
        { x1: 50, y1: 80, x2: 50, y2: 30 }, { x1: 40, y1: 80, x2: 40, y2: 35 }, { x1: 60, y1: 80, x2: 60, y2: 35 },
        { x1: 40, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 60, y2: 35 }, // Cabeza y cuerpo
        { x1: 45, y1: 70, x2: 55, y2: 70 }, // Base del vientre
        { x1: 45, y1: 70, x2: 45, y2: 45 }, { x1: 55, y1: 70, x2: 55, y2: 45 }, // Contorno del vientre
        { x1: 40, y1: 50, x2: 35, y2: 55 }, { x1: 35, y1: 55, x2: 40, y2: 60 }, // Ala izq
        { x1: 60, y1: 50, x2: 65, y2: 55 }, { x1: 65, y1: 55, x2: 60, y2: 60 }, // Ala der
        // Ojos y pico (más detallados)
        { type: "circle", x1: 47, y1: 40, radius: 1 }, { type: "circle", x1: 53, y1: 40, radius: 1 }, // Ojos
        { x1: 50, y1: 42, x2: 48, y2: 45 }, { x1: 48, y1: 45, x2: 52, y2: 45 }, { x1: 52, y1: 45, x2: 50, y2: 42 } // Pico
    ],

    "BUHO": [
        // Cuerpo (más plumoso y forma de corazón invertido en la cara)
        { type: "circle", x1: 50, y1: 50, radius: 25 },
        { x1: 40, y1: 40, x2: 60, y2: 40 }, { x1: 40, y1: 40, x2: 35, y2: 50 }, // Cara en forma de corazón
        { x1: 60, y1: 40, x2: 65, y2: 50 }, { x1: 35, y1: 50, x2: 65, y2: 50 },
        // Ojos grandes (con brillo y párpados)
        { type: "circle", x1: 42, y1: 45, radius: 8 }, { type: "circle", x1: 42, y1: 45, radius: 2 }, // Ojo izq con brillo
        { type: "circle", x1: 58, y1: 45, radius: 8 }, { type: "circle", x1: 58, y1: 45, radius: 2 }, // Ojo der con brillo
        { x1: 38, y1: 42, x2: 46, y2: 42 }, { x1: 54, y1: 42, x2: 62, y2: 42 }, // Párpados
        // Pico (pequeño y puntiagudo)
        { x1: 50, y1: 52, x2: 48, y2: 55 }, { x1: 48, y1: 55, x2: 52, y2: 55 }, { x1: 52, y1: 55, x2: 50, y2: 52 }
    ],

    "AGUILA": [
        // Cuerpo y cabeza (más robustos)
        { x1: 50, y1: 40, x2: 50, y2: 30 }, { x1: 45, y1: 30, x2: 55, y2: 30 }, // Cabeza
        { x1: 50, y1: 40, x2: 45, y2: 50 }, { x1: 45, y1: 50, x2: 50, y2: 60 }, // Cuerpo
        { x1: 50, y1: 60, x2: 55, y2: 50 }, { x1: 55, y1: 50, x2: 50, y2: 40 },
        // Alas (más grandes y plumosas)
        { x1: 45, y1: 45, x2: 20, y2: 40 }, { x1: 20, y1: 40, x2: 25, y2: 50 }, { x1: 25, y1: 50, x2: 30, y2: 55 }, // Ala izq
        { x1: 55, y1: 45, x2: 80, y2: 40 }, { x1: 80, y1: 40, x2: 75, y2: 50 }, { x1: 75, y1: 50, x2: 70, y2: 55 }, // Ala der
        // Pico y ojo
        { x1: 50, y1: 35, x2: 48, y2: 38 }, { x1: 48, y1: 38, x2: 50, y2: 40 }, { x1: 50, y1: 40, x2: 52, y2: 38 }, { x1: 52, y1: 38, x2: 50, y2: 35 }, // Pico
        { type: "circle", x1: 47, y1: 35, radius: 1 } // Ojo
    ],

    "DELFIN": [
        // Cuerpo (más elegante y curvado)
        { x1: 30, y1: 60, x2: 70, y2: 40 }, { x1: 70, y1: 40, x2: 75, y2: 45 }, // Lomo y morro
        { x1: 30, y1: 60, x2: 70, y2: 70 }, { x1: 70, y1: 70, x2: 75, y2: 65 }, // Vientre
        { x1: 75, y1: 45, x2: 80, y2: 55 }, { x1: 80, y1: 55, x2: 75, y2: 65 }, // Transición a la cola
        // Cola (más ancha y bifurcada)
        { x1: 80, y1: 55, x2: 85, y2: 50 }, { x1: 85, y1: 50, x2: 85, y2: 60 }, { x1: 85, y1: 60, x2: 80, y2: 55 },
        // Aleta dorsal (curvada)
        { x1: 60, y1: 40, x2: 60, y2: 30 }, { x1: 60, y1: 30, x2: 55, y2: 35 }, { x1: 55, y1: 35, x2: 60, y2: 40 },
        // Aleta pectoral (sutil)
        { x1: 40, y1: 60, x2: 42, y2: 65 }
    ],

    "BALLENA": [
        // Cuerpo (más masivo y redondeado)
        { x1: 20, y1: 60, x2: 80, y2: 60 }, { x1: 20, y1: 60, x2: 25, y2: 50 },
        { x1: 80, y1: 60, x2: 75, y2: 50 }, { x1: 25, y1: 50, x2: 75, y2: 50 }, // Contorno del cuerpo
        { x1: 30, y1: 55, x2: 70, y2: 55 }, // Línea de la barriga
        // Cola (grande y bifurcada)
        { x1: 70, y1: 55, x2: 80, y2: 45 }, { x1: 80, y2: 45, x2: 85, y2: 45 }, { x1: 85, y2: 45, x2: 80, y2: 55 }, // Lado superior de la cola
        { x1: 70, y1: 55, x2: 80, y2: 65 }, { x1: 80, y2: 65, x2: 85, y2: 65 }, { x1: 85, y2: 65, x2: 80, y2: 55 }, // Lado inferior de la cola
        // Soplete (líneas hacia arriba)
        { x1: 40, y1: 45, x2: 40, y2: 35 }, { x1: 42, y1: 45, x2: 42, y2: 35 }, { x1: 38, y1: 45, x2: 38, y2: 35 }
    ],

    "TIBURON": [
        // Cuerpo (más agresivo y aerodinámico)
        { x1: 20, y1: 60, x2: 80, y2: 55 }, { x1: 80, y1: 55, x2: 75, y2: 65 },
        { x1: 75, y2: 65, x2: 20, y2: 60 }, // Contorno del cuerpo
        { x1: 30, y1: 60, x2: 35, y2: 62 }, { x1: 60, y1: 58, x2: 65, y2: 60 }, // Branquias simuladas
        // Aleta dorsal (grande y puntiaguda)
        { x1: 50, y1: 50, x2: 50, y2: 40 }, { x1: 45, y1: 40, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 50, y2: 50 },
        // Aleta caudal (cola)
        { x1: 80, y1: 55, x2: 85, y2: 50 }, { x1: 85, y1: 50, x2: 80, y2: 60 }, { x1: 80, y1: 60, x2: 85, y2: 65 }, // Bifurcación
        // Ojo y boca con dientes
        { type: "circle", x1: 30, y1: 55, radius: 1 }, // Ojo
        { x1: 25, y1: 58, x2: 35, y2: 60 }, { x1: 35, y1: 60, x2: 40, y2: 58 } // Boca con dientes simulados
    ],

    "PULPO": [
        // Cabeza (más abultada)
        { type: "circle", x1: 50, y1: 40, radius: 15 },
        // Ojos
        { type: "circle", x1: 45, y1: 38, radius: 1 }, { type: "circle", x1: 55, y1: 38, radius: 1 },
        // Tentáculos (más curvos y con ventosas)
        { x1: 40, y1: 55, x2: 30, y2: 65 }, { x1: 30, y2: 65, x2: 35, y2: 70 }, { x1: 35, y2: 70, x2: 40, y2: 60 }, // Tentáculo 1
        { type: "circle", x1: 33, y1: 67, radius: 0.5 }, { type: "circle", x1: 37, y1: 62, radius: 0.5 }, // Ventosas
        { x1: 50, y1: 55, x2: 45, y2: 65 }, { x1: 45, y2: 65, x2: 50, y2: 70 }, { x1: 50, y2: 70, x2: 55, y2: 65 }, { x1: 55, y2: 65, x2: 50, y2: 55 }, // Tentáculo 2 (frontal)
        { type: "circle", x1: 47, y1: 67, radius: 0.5 }, { type: "circle", x1: 53, y1: 67, radius: 0.5 },
        { x1: 60, y1: 55, x2: 70, y2: 65 }, { x1: 70, y2: 65, x2: 65, y2: 70 }, { x1: 65, y2: 70, x2: 60, y2: 60 }, // Tentáculo 3
        { type: "circle", x1: 67, y1: 67, radius: 0.5 }, { type: "circle", x1: 63, y1: 62, radius: 0.5 }
    ],

    "CANGREJO": [
        // Cuerpo (más ancho y con textura)
        { x1: 30, y1: 60, x2: 70, y2: 60 }, { x1: 30, y1: 60, x2: 25, y2: 55 },
        { x1: 70, y1: 60, x2: 75, y2: 55 }, { x1: 25, y1: 55, x2: 75, y2: 55 }, // Parte superior
        { x1: 30, y1: 60, x2: 30, y2: 65 }, { x1: 70, y1: 60, x2: 70, y2: 65 }, { x1: 30, y1: 65, x2: 70, y2: 65 }, // Base del cuerpo
        // Ojos tallo (stalk eyes)
        { x1: 40, y1: 55, x2: 40, y2: 45 }, { type: "circle", x1: 40, y1: 45, radius: 1 },
        { x1: 60, y1: 55, x2: 60, y2: 45 }, { type: "circle", x1: 60, y1: 45, radius: 1 },
        // Patas (varias y articuladas)
        { x1: 25, y1: 60, x2: 20, y2: 65 }, { x1: 20, y2: 65, x2: 25, y2: 70 }, // Pata 1
        { x1: 35, y1: 65, x2: 30, y2: 70 }, { x1: 30, y2: 70, x2: 35, y2: 75 }, // Pata 2
        { x1: 75, y1: 60, x2: 80, y2: 65 }, { x1: 80, y2: 65, x2: 75, y2: 70 }, // Pata 3
        { x1: 65, y1: 65, x2: 70, y2: 70 }, { x1: 70, y2: 70, x2: 65, y2: 75 }, // Pata 4
        // Pinzas (más grandes y con detalles)
        { x1: 25, y1: 55, x2: 15, y2: 50 }, { x1: 15, y1: 50, x2: 20, y2: 45 }, { x1: 20, y1: 45, x2: 25, y2: 50 }, // Pinza izq (cierre)
        { x1: 18, y1: 50, x2: 23, y2: 50 }, // Detalle de cierre
        { x1: 75, y1: 55, x2: 85, y2: 50 }, { x1: 85, y1: 50, x2: 80, y2: 45 }, { x1: 80, y1: 45, x2: 75, y2: 50 }  // Pinza der (cierre)
    ],

    "MEDUSA": [
        // Cuerpo superior (forma de campana y con patrón)
        { x1: 50, y1: 40, x2: 35, y2: 45 }, { x1: 35, y1: 45, x2: 30, y2: 55 }, { x1: 30, y1: 55, x2: 40, y2: 60 },
        { x1: 40, y1: 60, x2: 60, y2: 60 }, { x1: 60, y1: 60, x2: 70, y2: 55 }, { x1: 70, y1: 55, x2: 65, y2: 45 },
        { x1: 65, y1: 45, x2: 50, y2: 40 }, // Contorno de la campana
        { x1: 40, y1: 48, x2: 60, y2: 48 }, // Línea interna
        // Tentáculos (más numerosos y ondulados)
        { x1: 40, y1: 60, x2: 35, y2: 70 }, { x1: 35, y2: 70, x2: 40, y2: 75 }, // Tentáculo 1
        { x1: 50, y1: 60, x2: 45, y2: 70 }, { x1: 45, y2: 70, x2: 50, y2: 75 }, // Tentáculo 2
        { x1: 60, y1: 60, x2: 65, y2: 70 }, { x1: 65, y2: 70, x2: 60, y2: 75 }, // Tentáculo 3
        { x1: 42, y1: 60, x2: 38, y2: 68 }, { x1: 38, y2: 68, x2: 42, y2: 72 }, // Tentáculo 4 (intermedio)
        { x1: 58, y1: 60, x2: 62, y2: 68 }, { x1: 62, y2: 68, x2: 58, y2: 72 }  // Tentáculo 5 (intermedio)
    ],

    "DINOSAURIO": [
        // Contorno de dinosaurio (cuello largo, cuerpo y patas robustas)
        { x1: 20, y1: 70, x2: 30, y2: 65 }, { x1: 30, y1: 65, x2: 40, y2: 68 }, // Pierna delantera
        { x1: 40, y1: 68, x2: 60, y2: 68 }, // Vientre
        { x1: 60, y1: 68, x2: 70, y2: 65 }, { x1: 70, y1: 65, x2: 75, y2: 70 }, // Pierna trasera y cola
        { x1: 75, y1: 70, x2: 80, y2: 65 }, { x1: 80, y1: 65, x2: 75, y2: 60 }, // Cola
        { x1: 60, y1: 68, x2: 65, y2: 55 }, { x1: 65, y1: 55, x2: 60, y2: 50 }, // Lomo
        { x1: 60, y1: 50, x2: 50, y2: 40 }, { x1: 50, y1: 40, x2: 45, y2: 35 }, { x1: 45, y1: 35, x2: 40, y2: 40 }, // Cuello
        { x1: 40, y1: 40, x2: 35, y2: 45 }, { x1: 35, y1: 45, x2: 30, y2: 50 }, { x1: 30, y1: 50, x2: 30, y2: 65 } // Cabeza y cuello
    ],

    "DRAGON": [
        // Cuerpo (más musculoso y con escamas)
        { 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 },
        { x1: 35, y1: 45, x2: 40, y2: 48 }, { x1: 45, y1: 45, x2: 50, y2: 48 }, // Escamas (simuladas)
        // Alas (más grandes y membranosas)
        { x1: 40, y1: 40, x2: 30, y2: 30 }, { x1: 30, y1: 30, x2: 40, y2: 25 }, { x1: 40, y1: 25, x2: 45, y2: 30 }, { x1: 45, y1: 30, x2: 40, y2: 40 }, // Ala izq
        { x1: 60, y1: 40, x2: 70, y2: 30 }, { x1: 70, y1: 30, x2: 60, y2: 25 }, { x1: 60, y1: 25, x2: 55, y2: 30 }, { x1: 55, y1: 30, x2: 60, y2: 40 }, // Ala der
        // Cola (larga y puntiaguda)
        { x1: 70, y1: 60, x2: 80, y2: 55 }, { x1: 80, y1: 55, x2: 85, y2: 60 }, { x1: 85, y1: 60, x2: 80, y2: 65 }, { x1: 80, y1: 65, x2: 75, y2: 60 },
        // Cabeza y cuernos
        { x1: 35, y1: 40, x2: 30, y2: 35 }, { x1: 30, y2: 35, x2: 35, y2: 30 }, // Cuerno izq
        { x1: 65, y1: 40, x2: 70, y2: 35 }, { x1: 70, y2: 35, x2: 65, y2: 30 }  // Cuerno der
    ],

    "UNICORNIO": [
        // Cuerpo de caballo (elegante y estilizado)
        { x1: 50, y1: 70, x2: 35, y2: 60 }, { x1: 35, y1: 60, x2: 30, y2: 45 }, // Cuello y pecho
        { x1: 30, y1: 45, x2: 35, y2: 35 }, { x1: 35, y1: 35, x2: 45, y2: 30 }, // Cabeza
        { x1: 45, y1: 30, x2: 55, y2: 30 }, { x1: 55, y1: 30, x2: 65, y2: 35 },
        { x1: 65, y1: 35, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 65, y2: 60 }, // Lomo
        { x1: 65, y1: 60, x2: 50, y2: 70 },
        // Cuerno (espiral y puntiagudo)
        { x1: 50, y1: 30, x2: 50, y2: 15 }, { x1: 48, y1: 15, x2: 52, y2: 15 }, // Punta
        { x1: 49, y1: 20, x2: 51, y2: 20 }, { x1: 49, y1: 25, x2: 51, y2: 25 }, // Espiral
        // Melena (líneas fluidas)
        { x1: 45, y1: 30, x2: 40, y2: 25 }, { x1: 40, y2: 25, x2: 35, y2: 30 }
    ],

    "SIRENA": [
        // Cuerpo (más curvado y femenino)
        { x1: 50, y1: 40, x2: 45, y2: 50 }, { x1: 45, y1: 50, x2: 50, y2: 60 }, // Torso
        { x1: 50, y1: 40, x2: 55, y2: 50 }, { x1: 55, y1: 50, x2: 50, y2: 60 },
        // Cola de pez (escamas y aleta bifurcada)
        { x1: 50, y1: 60, x2: 45, y2: 70 }, { x1: 45, y1: 70, x2: 55, y2: 70 }, { x1: 55, y1: 70, x2: 50, y2: 60 },
        { x1: 45, y1: 70, x2: 40, y2: 75 }, { x1: 40, y1: 75, x2: 45, y2: 80 }, { x1: 45, y1: 80, x2: 50, y2: 70 }, // Aleta inferior
        { x1: 55, y1: 70, x2: 60, y2: 75 }, { x1: 60, y1: 75, x2: 55, y2: 80 }, { x1: 55, y1: 80, x2: 50, y2: 70 },
        // Pelo largo
        { x1: 45, y1: 40, x2: 40, y2: 30 }, { x1: 40, y2: 30, x2: 35, y2: 45 }
    ],

    "HADA": [
        // Cuerpo (más delicado)
        { x1: 50, y1: 40, x2: 50, y2: 60 },
        { x1: 45, y1: 40, x2: 55, y2: 40 }, // Hombros
        // Alas (transparentes, con venas y formas más orgánicas)
        { x1: 40, y1: 50, x2: 30, y2: 45 }, { x1: 30, y1: 45, x2: 40, y2: 40 }, { x1: 40, y1: 40, x2: 45, y2: 45 }, { x1: 45, y1: 45, x2: 40, y2: 50 }, // Ala superior izq
        { x1: 35, y1: 50, x2: 25, y2: 55 }, { x1: 25, y1: 55, x2: 35, y2: 60 }, { x1: 35, y1: 60, x2: 40, y2: 55 }, { x1: 40, y2: 55, x2: 35, y2: 50 }, // Ala inferior izq
        { x1: 60, y1: 50, x2: 70, y2: 45 }, { x1: 70, y1: 45, x2: 60, y2: 40 }, { x1: 60, y1: 40, x2: 55, y2: 45 }, { x1: 55, y1: 45, x2: 60, y2: 50 }, // Ala superior der
        { x1: 65, y1: 50, x2: 75, y2: 55 }, { x1: 75, y1: 55, x2: 65, y2: 60 }, { x1: 65, y1: 60, x2: 60, y2: 55 }, { x1: 60, y2: 55, x2: 65, y2: 50 }, // Ala inferior der
        // Varita mágica (con estrella pequeña)
        { x1: 60, y1: 40, x2: 70, y2: 35 }, { x1: 68, y1: 35, x2: 70, y2: 30 }, { x1: 70, y2: 30, x2: 72, y2: 35 }, { x1: 72, y2: 35, x2: 70, y2: 35 }
    ],

    "MAGO": [
        // Cuerpo (con túnica)
        { x1: 50, y1: 40, x2: 50, y2: 60 }, { x1: 40, y1: 60, x2: 60, y2: 60 },
        { x1: 40, y1: 60, x2: 35, y2: 75 }, { x1: 60, y1: 60, x2: 65, y2: 75 }, { x1: 35, y1: 75, x2: 65, y2: 75 },
        // Sombrero de punta (más detallado)
        { x1: 40, y1: 60, x2: 60, y2: 60 }, // Base del sombrero
        { x1: 40, y1: 60, x2: 45, y2: 40 }, { x1: 60, y1: 60, x2: 55, y2: 40 }, // Lados
        { x1: 45, y1: 40, x2: 50, y2: 25 }, { x1: 50, y1: 25, x2: 55, y2: 40 }, // Parte superior puntiaguda
        // Varita mágica (con un brillo en la punta)
        { x1: 65, y1: 50, x2: 75, y2: 45 },
        { type: "circle", x1: 75, y1: 45, radius: 1.5 } // Brillo
    ],

    "GUERRERO": [
        // Armadura básica (torso, hombreras, piernas)
        { x1: 50, y1: 40, x2: 50, y2: 60 }, { x1: 40, y1: 60, x2: 60, y2: 60 },
        { x1: 40, y1: 60, x2: 40, y2: 75 }, { x1: 60, y1: 60, x2: 60, y2: 75 }, { x1: 40, y1: 75, x2: 60, y2: 75 }, // Piernas
        // Yelmo (con visera)
        { x1: 45, y1: 40, x2: 55, y2: 40 }, { x1: 45, y1: 40, x2: 40, y2: 35 }, { x1: 55, y1: 40, x2: 60, y2: 35 }, // Base del yelmo
        { x1: 40, y1: 35, x2: 60, y2: 35 },
        { x1: 45, y1: 38, x2: 55, y2: 38 }, // Visera
        // Hombros (con forma de armadura)
        { x1: 40, y1: 45, x2: 35, y2: 50 }, { x1: 35, y2: 50, x2: 40, y2: 55 },
        { x1: 60, y1: 45, x2: 65, y2: 50 }, { x1: 65, y2: 50, x2: 60, y2: 55 }
    ],

    "CABALLERO": [
        // Armadura (con más detalles y grebas)
        { x1: 50, y1: 40, x2: 50, y2: 60 }, { x1: 40, y1: 60, x2: 60, y2: 60 },
        { x1: 40, y1: 60, x2: 40, y2: 75 }, { x1: 60, y1: 60, x2: 60, y2: 75 }, { x1: 40, y1: 75, x2: 60, y2: 75 }, // Grebas
        { x1: 42, y1: 65, x2: 58, y2: 65 }, // Rodillera (línea)
        // Yelmo (con pluma)
        { x1: 45, y1: 40, x2: 55, y2: 40 }, { x1: 45, y1: 40, x2: 40, y2: 35 }, { x1: 55, y1: 40, x2: 60, y2: 35 },
        { x1: 40, y1: 35, x2: 60, y2: 35 },
        { x1: 50, y1: 35, x2: 50, y2: 25 }, { x1: 48, y1: 25, x2: 52, y2: 25 }, // Pluma
        // Espada (con guarda y pomo)
        { x1: 65, y1: 50, x2: 75, y2: 40 }, { x1: 75, y1: 40, x2: 78, y2: 43 }, { x1: 78, y2: 43, x2: 68, y2: 53 }, // Hoja
        { x1: 65, y1: 50, x2: 68, y2: 50 }, { x1: 68, y1: 50, x2: 68, y2: 53 }, { x1: 68, y1: 53, x2: 65, y2: 53 } // Guarda
    ],

    "PRINCESA": [
        // Cuerpo (más curvado)
        { x1: 50, y1: 40, x2: 50, y2: 60 },
        { x1: 45, y1: 40, x2: 55, y2: 40 }, // Hombros
        // Vestido (más voluminoso y con pliegues)
        { 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: 45, y1: 65, x2: 50, y2: 68 }, { x1: 50, y1: 68, x2: 55, y2: 65 }, // Pliegues
        // Corona (con gemas)
        { x1: 45, y1: 35, x2: 55, y2: 35 },
        { x1: 48, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 52, y2: 35 },
        { type: "circle", x1: 48, y1: 32, radius: 0.5 }, { type: "circle", x1: 52, y1: 32, radius: 0.5 } // Gemas
    ],

    "REINA": [
        // Cuerpo (similar a princesa, pero más formal)
        { x1: 50, y1: 40, x2: 50, y2: 60 },
        { x1: 45, y1: 40, x2: 55, y2: 40 },
        // Vestido (más regio y amplio)
        { 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: 65, x2: 45, y2: 68 }, { x1: 55, y1: 68, x2: 60, y2: 65 }, // Pliegues
        // Corona grande (con más picos y gemas)
        { x1: 40, y1: 35, x2: 60, y2: 35 },
        { x1: 42, y1: 35, x2: 45, y2: 30 }, { x1: 45, y1: 30, x2: 50, y2: 32 },
        { x1: 50, y1: 32, x2: 55, y2: 30 }, { x1: 55, y1: 30, x2: 58, y2: 35 },
        { type: "circle", x1: 45, y1: 32, radius: 0.8 }, { type: "circle", x1: 50, y1: 30, radius: 0.8 }, { type: "circle", x1: 55, y1: 32, radius: 0.8 } // Gemas
    ],

    "REY": [
        // Cuerpo (robusto y con capa)
        { x1: 50, y1: 40, x2: 50, y2: 60 }, { x1: 40, y1: 60, x2: 60, y2: 60 },
        { x1: 35, y1: 45, x2: 30, y2: 60 }, { x1: 30, y2: 60, x2: 35, y2: 70 }, // Capa izquierda
        { x1: 65, y1: 45, x2: 70, y2: 60 }, { x1: 70, y2: 60, x2: 65, y2: 70 }, // Capa derecha
        { x1: 40, y1: 70, x2: 60, y2: 70 }, // Base
        // Corona (con cruces pequeñas y gemas)
        { x1: 45, y1: 35, x2: 55, y2: 35 },
        { x1: 48, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 52, y2: 35 },
        { type: "circle", x1: 48, y1: 32, radius: 0.5 }, { type: "circle", x1: 52, y1: 32, radius: 0.5 },
        { x1: 47, y1: 37, x2: 47, y2: 39 }, { x1: 46, y1: 38, x2: 48, y2: 38 }, // Cruz izq
        { x1: 53, y1: 37, x2: 53, y2: 39 }, { x1: 52, y1: 38, x2: 54, y2: 38 }, // Cruz der
        // Cetro (más detallado)
        { x1: 65, y1: 50, x2: 75, y2: 40 }, { x1: 75, y1: 40, x2: 78, y2: 43 },
        { x1: 78, y2: 43, x2: 75, y2: 46 }, { x1: 75, y2: 46, x2: 65, y2: 56 }
    ],

    "CASTILLO": [
        // Base (con textura de piedra)
        { 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 },
        { x1: 25, y1: 65, x2: 30, y2: 68 }, { x1: 35, y1: 65, x2: 40, y2: 68 }, // Textura de piedra
        // Almenas (más definidas y con grosor)
        { x1: 20, y1: 40, x2: 20, y2: 35 }, { x1: 25, y1: 35, x2: 25, y2: 40 }, { x1: 20, y1: 35, x2: 25, y2: 35 },
        { x1: 30, y1: 40, x2: 30, y2: 35 }, { x1: 35, y1: 35, x2: 35, y2: 40 }, { x1: 30, y1: 35, x2: 35, y2: 35 },
        { x1: 40, y1: 40, x2: 40, y2: 35 }, { x1: 45, y1: 35, x2: 45, y2: 40 }, { x1: 40, y1: 35, x2: 45, y2: 35 },
        { x1: 75, y1: 40, x2: 75, y2: 35 }, { x1: 80, y1: 35, x2: 80, y2: 40 }, { x1: 75, y1: 35, x2: 80, y2: 35 },
        // Torre central (más alta y con almenas)
        { x1: 50, y1: 40, x2: 50, y2: 20 }, { x1: 60, y1: 40, x2: 60, y2: 20 }, { x1: 50, y1: 20, x2: 60, y2: 20 },
        { x1: 50, y1: 20, x2: 50, y2: 15 }, { x1: 55, y1: 15, x2: 55, y2: 20 }, { x1: 50, y1: 15, x2: 55, y2: 15 } // Almenas de torre
    ],

"ESPADA": [
    // Hoja (Afilada y con canal central)
    { x1: 50, y1: 10, x2: 45, y2: 15 }, { x1: 50, y1: 10, x2: 55, y2: 15 }, // Punta
    { x1: 45, y1: 15, x2: 45, y2: 60 }, { x1: 55, y1: 15, x2: 55, y2: 60 },
    { x1: 50, y1: 15, x2: 50, y2: 60 }, // Canal central (sangradera)
    // Guarda (Cross-guard más elaborada)
    { x1: 40, y1: 60, x2: 60, y2: 60 },
    { x1: 40, y1: 60, x2: 35, y2: 63 }, { x1: 60, y1: 60, x2: 65, y2: 63 },
    { x1: 45, y1: 60, x2: 45, y2: 65 }, { x1: 55, y1: 60, x2: 55, y2: 65 },
    { x1: 45, y1: 65, x2: 55, y2: 65 }, // Línea horizontal que une la guarda con la empuñadura (added)
    // Empuñadura (Grip con textura)
    { x1: 48, y1: 65, x2: 48, y2: 80 }, { x1: 52, y1: 65, x2: 52, y2: 80 },
    { x1: 48, y1: 70, x2: 52, y2: 70 }, { x1: 48, y1: 75, x2: 52, y2: 75 }, // Textura
    // Pomo (Pommel)
    { type: "circle", x1: 50, y1: 82, radius: 3 }
],

    "ESCUDO": [
        // Escudo (con borde y forma más orgánica)
        { 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 },
        { x1: 30, y1: 60, x2: 30, y2: 40 },
        { x1: 32, y1: 42, x2: 68, y2: 42 }, { x1: 68, y1: 42, x2: 68, y2: 58 }, // Borde interior
        { x1: 68, y1: 58, x2: 50, y2: 68 }, { x1: 50, y1: 68, x2: 32, y2: 58 }, { x1: 32, y1: 58, x2: 32, y2: 42 },
        // Emblema (cruz con centro)
        { x1: 40, y1: 45, x2: 60, y2: 45 }, { x1: 50, y1: 45, x2: 50, y2: 65 },
        { type: "circle", x1: 50, y1: 55, radius: 3 } // Centro de la cruz
    ],

    "ARCO": [
        // Arco (con grosor y curvatura)
        { x1: 30, y1: 60, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 70, y2: 60 },
        { x1: 32, y1: 58, x2: 50, y2: 32 }, { x1: 50, y1: 32, x2: 68, y2: 58 }, // Grosor
        // Cuerda (más fina y tensa)
        { x1: 30, y1: 60, x2: 70, y2: 60 },
        // Flecha (con punta y plumas)
        { x1: 50, y1: 45, x2: 80, y2: 45 }, // Cuerpo de la flecha
        { x1: 75, y1: 42, x2: 80, y2: 45 }, { x1: 80, y1: 45, x2: 75, y2: 48 }, // Punta
        { x1: 25, y1: 45, x2: 20, y2: 42 }, { x1: 20, y2: 42, x2: 20, y2: 48 }, { x1: 20, y2: 48, x2: 25, y2: 45 } // Plumas
    ],

    "FLECHA": [
        // Cuerpo de la flecha (más detallado)
        { x1: 20, y1: 50, x2: 80, y2: 50 },
        { x1: 20, y1: 50, x2: 22, y2: 48 }, { x1: 20, y1: 50, x2: 22, y2: 52 }, // Base del asta
        // Punta (más aguda y con base)
        { x1: 75, y1: 45, x2: 80, y2: 50 }, { x1: 80, y1: 50, x2: 75, y2: 55 },
        { x1: 75, y1: 45, x2: 75, y2: 55 }, // Base de la punta
        // Cola (plumas, más detalladas y en ángulo)
        { x1: 25, y1: 45, x2: 20, y2: 40 }, { x1: 20, y1: 40, x2: 20, y2: 50 }, { x1: 20, y1: 50, x2: 25, y2: 55 },
        { x1: 25, y1: 55, x2: 20, y2: 60 }, { x1: 20, y2: 60, x2: 20, y2: 50 }, { x1: 20, y2: 50, x2: 25, y2: 45 }
    ],

    "POCION": [
        // Frasco (más curvo y con etiqueta)
        { x1: 40, y1: 70, x2: 60, y2: 70 }, // Base
        { x1: 40, y1: 70, x2: 38, y2: 55 }, { x1: 60, y1: 70, x2: 62, y2: 55 }, // Curvas del cuerpo
        { x1: 38, y1: 55, x2: 38, y2: 45 }, { x1: 62, y1: 55, x2: 62, y2: 45 }, // Lados del cuerpo
        // Cuello
        { x1: 45, y1: 45, x2: 45, y2: 35 }, { x1: 55, y1: 45, x2: 55, y2: 35 },
        // Boca y tapón
        { x1: 48, y1: 35, x2: 52, y2: 35 }, { x1: 48, y1: 35, x2: 48, y2: 30 }, { x1: 52, y1: 35, x2: 52, y2: 30 }, // Tapón
        { x1: 48, y1: 30, x2: 52, y2: 30 },
        // Etiqueta (rectángulo en el cuerpo)
        { x1: 42, y1: 58, x2: 58, y2: 58 }, { x1: 42, y1: 58, x2: 42, y2: 65 },
        { x1: 58, y1: 58, x2: 58, y2: 65 }, { x1: 42, y1: 65, x2: 58, y2: 65 }
    ],

    "ANILLO": [
        // Anillo (con grosor y más forma)
        { type: "circle", x1: 50, y1: 50, radius: 20 },
        { type: "circle", x1: 50, y1: 50, radius: 18 }, // Grosor del anillo
        // Gema (más facetada y con brillo)
        { x1: 45, y1: 35, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 55, y2: 35 }, { x1: 55, y1: 35, x2: 45, y2: 35 }, // Forma de diamante
        { x1: 50, y1: 30, x2: 48, y2: 33 }, { x1: 50, y1: 30, x2: 52, y2: 33 } // Facetas
    ],

    "COLLAR": [
        // Cadena (más fina y con eslabones sutiles)
        { x1: 30, y1: 40, x2: 70, y2: 40 },
        { x1: 32, y1: 40, x2: 32, y2: 42 }, { x1: 35, y1: 40, x2: 35, y2: 42 }, // Eslabones
        { x1: 65, y1: 40, x2: 65, y2: 42 }, { x1: 68, y1: 40, x2: 68, y2: 42 },
        // Pendiente (más detallado)
        { x1: 45, y1: 40, x2: 50, y2: 50 }, { x1: 50, y1: 50, x2: 55, y2: 40 }, // Forma principal
        { x1: 50, y1: 50, x2: 50, y2: 60 }, { x1: 48, y1: 60, x2: 52, y2: 60 }, // Base del pendiente
        { x1: 47, y1: 52, x2: 53, y2: 52 } // Gema simulada
    ],

    "CORONA": [
        // Base (con grosor)
        { x1: 30, y1: 60, x2: 70, y2: 60 }, { x1: 30, y1: 60, x2: 32, y2: 63 }, // Grosor de la base
        { x1: 70, y1: 60, x2: 68, y2: 63 }, { x1: 32, y1: 63, x2: 68, y2: 63 },
        // Puntas (más agudas y con detalles)
        { x1: 30, y1: 60, x2: 35, y2: 45 }, { x1: 35, y1: 45, x2: 40, y2: 60 }, // Punta 1
        { x1: 35, y1: 50, x2: 38, y2: 48 }, // Detalle de punta
        { x1: 45, y1: 60, x2: 50, y2: 45 }, { x1: 50, y1: 45, x2: 55, y2: 60 }, // Punta 2
        { x1: 50, y1: 50, x2: 50, y2: 48 },
        { x1: 60, y1: 60, x2: 65, y2: 45 }, { x1: 65, y1: 45, x2: 70, y2: 60 }  // Punta 3
    ],

    "GEMA": [
        // Gema facetada (más compleja)
        { 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 exterior
        // Facetas internas (líneas de división)
        { x1: 50, y1: 30, x2: 50, y2: 70 }, { x1: 30, y1: 50, x2: 70, y2: 50 },
        { x1: 40, y1: 35, x2: 40, y2: 65 }, { x1: 60, y1: 35, x2: 60, y2: 65 },
        { x1: 35, y1: 40, x2: 65, y2: 40 }, { x1: 35, y1: 60, x2: 65, y2: 60 },
        // Brillo (pequeños puntos)
        { type: "circle", x1: 45, y1: 45, radius: 0.5 }, { type: "circle", x1: 55, y1: 45, radius: 0.5 }
    ],

    "TESORO": [
        // Cofre (con grosor y tapa semi-abierta)
        { x1: 30, y1: 60, x2: 70, y2: 60 }, { x1: 30, y1: 60, x2: 30, y2: 40 },
        { x1: 70, y1: 60, x2: 70, y2: 40 }, { x1: 30, y1: 40, x2: 70, y2: 40 }, // Cuerpo
        { x1: 32, y1: 62, x2: 68, y2: 62 }, { x1: 32, y1: 42, x2: 68, y2: 42 }, // Grosor del cuerpo
        { x1: 32, y1: 62, x2: 32, y2: 42 }, { x1: 68, y1: 62, x2: 68, y2: 42 },
        // Tapa (curva y con bisagras)
        { x1: 30, y1: 40, x2: 35, y2: 35 }, { x1: 70, y1: 40, x2: 75, y2: 35 },
        { x1: 35, y1: 35, x2: 75, y2: 35 }, // Borde de la tapa
        { x1: 30, y1: 40, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 70, y2: 40 }, // Curva de la tapa
        // Cerradura (más detallada)
        { x1: 50, y1: 45, x2: 50, y2: 55 }, { x1: 48, y1: 55, x2: 52, y2: 55 }, // Base de la cerradura
        { type: "circle", x1: 50, y1: 50, radius: 1 } // Agujero de la cerradura
    ],

    "MONEDA": [
        { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno exterior
        { type: "circle", x1: 50, y1: 50, radius: 18 }, // Borde interior
        // Signo de dólar (con más detalle y sombreado)
        { x1: 48, y1: 40, x2: 48, y2: 60 }, { x1: 52, y1: 40, x2: 52, y2: 60 }, // Barras verticales
        { x1: 45, y1: 45, x2: 55, y2: 45 }, { x1: 45, y1: 55, x2: 55, y2: 55 }, // Barras horizontales
        { x1: 49, y1: 40, x2: 49, y2: 60 }, { x1: 51, y1: 40, x2: 51, y2: 60 }, // Sombreado del dólar
        // Textura (pequeños puntos en el fondo)
        { type: "circle", x1: 40, y1: 40, radius: 0.2 }, { type: "circle", x1: 60, y1: 40, radius: 0.2 },
        { type: "circle", x1: 40, y1: 60, radius: 0.2 }, { type: "circle", x1: 60, y1: 60, radius: 0.2 }
    ],

    "MAPA": [
        // Mapa enrollado (con relieve y textura de papel)
        { 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
        // Bordes enrollados (más gruesos y con pliegues)
        { x1: 25, y1: 40, x2: 30, y2: 45 }, { x1: 25, y1: 55, x2: 30, y2: 60 }, // Lado izq
        { x1: 25, y1: 40, x2: 25, y2: 60 },
        { x1: 70, y1: 45, x2: 75, y2: 40 }, { x1: 70, y1: 55, x2: 75, y2: 60 }, // Lado der
        { x1: 75, y1: 40, x2: 75, y2: 60 },
        // Detalles internos (líneas de relieve o continentes)
        { x1: 40, y1: 45, x2: 50, y2: 50 }, { x1: 50, y1: 50, x2: 60, y2: 45 }, // Contorno de tierra
        { x1: 40, y1: 55, x2: 50, y2: 52 }, { x1: 50, y1: 52, x2: 60, y2: 55 }
    ],

    "BRUJULA": [
        { type: "circle", x1: 50, y1: 50, radius: 20 }, // Contorno exterior
        { type: "circle", x1: 50, y1: 50, radius: 18 }, // Borde interior
        // Aguja (más detallada, con dos colores simulados)
        { x1: 50, y1: 35, x2: 48, y2: 45 }, { x1: 48, y1: 45, x2: 50, y2: 50 }, // Punta norte
        { x1: 50, y1: 65, x2: 52, y2: 55 }, { x1: 52, y1: 55, x2: 50, y2: 50 }, // Punta sur
        // Marcas de dirección (N, S, E, O)
        { x1: 50, y1: 30, x2: 50, y2: 32 }, { x1: 50, y1: 68, x2: 50, y2: 70 },
        { x1: 30, y1: 50, x2: 32, y2: 50 }, { x1: 68, y1: 50, x2: 70, y2: 50 }
    ],

    "PERGAMINO": [
        // Pergamino enrollado (con textura de arrugas)
        { 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 }, // Cuerpo principal
        // Enrollado (más detallado)
        { x1: 25, y1: 40, x2: 30, y2: 45 }, { x1: 25, y1: 55, x2: 30, y2: 60 }, // Lado izq
        { x1: 25, y1: 40, x2: 25, y2: 60 }, { x1: 28, y1: 43, x2: 28, y2: 57 }, // Interior del enrollado
        { x1: 70, y1: 45, x2: 75, y2: 40 }, { x1: 70, y1: 55, x2: 75, y2: 60 }, // Lado der
        { x1: 75, y1: 40, x2: 75, y2: 60 }, { x1: 72, y1: 43, x2: 72, y2: 57 },
        // Texto simulado (líneas horizontales cortas)
        { x1: 35, y1: 48, x2: 65, y2: 48 }, { x1: 35, y1: 52, x2: 65, y2: 52 }
    ],

    "ANTORCHA": [
        // Palo (con textura de madera y más irregular)
        { x1: 50, y1: 80, x2: 50, y2: 60 }, { x1: 48, y1: 80, x2: 52, y2: 80 }, // Grosor de la base
        { x1: 49, y1: 75, x2: 49, y2: 70 }, { x1: 51, y1: 75, x2: 51, y2: 70 }, // Nudos de madera
        { x1: 47, y1: 65, x2: 47, y2: 60 }, { x1: 53, y1: 65, x2: 53, y2: 60 },
        // Base de la llama (con tela)
        { x1: 45, y1: 60, x2: 55, y2: 60 },
        { x1: 45, y1: 60, x2: 42, y2: 58 }, { x1: 55, y1: 60, x2: 58, y2: 58 }, // Pliegues de tela
        // Llama (más dinámica y con múltiples picos, simulando transparencia)
        { x1: 50, y1: 50, x2: 45, y2: 40 }, { x1: 45, y1: 40, x2: 50, y2: 30 }, { x1: 50, y1: 30, x2: 55, y2: 40 }, { x1: 55, y1: 40, x2: 50, y2: 50 }, // Contorno principal
        { x1: 48, y1: 45, x2: 50, y2: 40 }, { x1: 50, y1: 40, x2: 52, y2: 45 } // Llama interior
    ]
};

    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 (necesita bot)", '<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 (necesita bot)", '<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");

// --- NEW CUBIC ENGINE FUNCTIONALITIES START HERE ---

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

    // Add CSS rules to QBit.Styles for the Hide/Show Menus module
    QBit.Styles.addRules([
        `#${QBit.identifier} #hide-show-menu-container {
            background: linear-gradient(135deg, var(--light-blue), var(--accent-blue));
            border: 1px solid var(--border-blue);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
            color: var(--dark-text);
            border-radius: .25rem;
            padding: 5px;
            margin-top: 5px;
            cursor: default;
        }`,
        `#${QBit.identifier} #hide-show-menu-container div:first-child {
            color: var(--dark-blue-title);
        }`,
        `#${QBit.identifier} #element-selector {
            border: 1px solid var(--input-border-blue);
            background-color: var(--input-bg);
            color: var(--dark-text);
            padding: 5px;
            width: 100%;
            box-sizing: border-box;
            margin-bottom: 5px;
        }`,
        `#${QBit.identifier} #hide-show-menu-container .control-buttons button {
            padding: 5px 10px;
            border: none;
            border-radius: .25rem;
            cursor: pointer;
            transition: background-color 0.2s ease;
            width: 48%; /* Adjust for spacing */
            box-sizing: border-box;
        }`,
        `#${QBit.identifier} #show-element {
            background-color: var(--info);
            color: white;
        }`,
        `#${QBit.identifier} #show-element:hover {
            background-color: var(--info-hover);
        }`,
        `#${QBit.identifier} #hide-element {
            background-color: var(--danger);
            color: white;
        }`,
        `#${QBit.identifier} #hide-element:hover {
            background-color: var(--danger-hover);
        }`,
        // Define custom properties for consistency
        `:root {
            --light-blue: #e0f2f7;
            --accent-blue: #a7d9f7;
            --border-blue: #7cb9e8;
            --dark-blue-title: #004080;
            --input-border-blue: #80a4e8;
            --input-bg: #f8f8f8;
            --dark-text: #333;
            --info: #007bff;
            --info-hover: #0056b3;
            --danger: #dc3545;
            --danger-hover: #bd2130;
        }`
    ]);

    // Comprehensive list of common elements on Drawaria.online
    const allKnownElements = [

        // --- In-Game Specific Elements ---
        { selector: '#canvas', label: 'Canvas' },
        { selector: '#leftbar', label: 'Left Sidebar' },
        { selector: '#rightbar', label: 'Right Sidebar' },
        { selector: '#playerlist', label: 'Player List' },
        { selector: '#cyclestatus', label: 'Cycle Status' },
        { selector: '#votingbox', label: 'Voting Box' },
        { selector: '#passturnbutton', label: 'Pass Turn Button' },
        { selector: '.timer', label: 'Round Timer' },
        { selector: '#roomcontrols', label: 'Room Controls' },
        { selector: '#infotext', label: 'Info Text' },
        { selector: '#gesturespickerselector', label: 'Gestures Picker' },
        { selector: '#chatbox_messages', label: 'Chat Messages' },
        { selector: '#drawcontrols', label: 'Draw Controls' },
        { selector: '#turnresults', label: 'Turn Results' },
        { selector: '#roundresults', label: 'Round Results' },
        { selector: '#snapmessage_container', label: 'Snap Message Container' },
        { selector: '#accountbox', label: 'Account Box' },
        { selector: '#customvotingbox', label: 'Custom Voting Box' },
        { selector: '#showextmenu', label: 'Show Ext Menu Button' },
        { selector: '#playgroundroom_next', label: 'Playground Next Button' },
        { selector: '#homebutton', label: 'Home Button' },
        { selector: '.invbox', label: 'Invitation Box' },

        // --- Modals (can appear in both states) ---
        { selector: '#howtoplaydialog', label: 'How to Play' },
        { selector: '#newroomdialog', label: 'New Room Options' },
        { selector: '#musictracks', label: 'Music Tracks' },
        { selector: '#inventorydlg', label: 'Inventory' },
        { selector: '#extmenu', label: 'Extra Menu' },
        { selector: '#pressureconfigdlg', label: 'Pressure Settings' },
        { selector: '#palettechooser', label: 'Palette Chooser' },
        { selector: '#wordchooser', label: 'Word Chooser' },
        { selector: '#targetword', label: 'Target Word Info' },
        { selector: '#invitedlg', label: 'Invite Dialog' },
        { selector: '#reportdlg', label: 'Report Dialog' },
        { selector: '#turtabortedmsg', label: 'Turn Aborted Msg' },
        { selector: '#drawsettings', label: 'Draw Settings' },

        // Add more specific modal sub-elements for finer control
        { selector: '.modal-header', label: 'Header (Any)' },
        { selector: '.modal-body', label: 'Body (Any)' },
        { selector: '.modal-footer', label: 'Footer (Any)' },
        { selector: '.form-group', label: 'Form Group (Any)' },
        { selector: '.table', label: 'Table (Any)' },
        { selector: '.spinner-border', label: 'Spinner/Loading Icon (Any)' },
    ];


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

        #elementSelector;
        #mutationObserver;

        constructor() {
            super("Ocultar/Mostrar Menús", '<i class="fas fa-eye-slash"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.#setupObserver();
            // Initial population after interface is loaded
            setTimeout(() => this.#populateSelector(), 500);
        }

        #loadInterface() {
            const container = domMake.Tree("div", { id: "hide-show-menu-container" });
            container.appendChild(domMake.Tree("div", { style: "padding-bottom: 5px; text-align: center; font-weight: bold; cursor: default; font-size: 0.9em;" }, ["Menús de Drawaria"]));

            this.#elementSelector = domMake.Tree("select", { id: "element-selector" });
            container.appendChild(this.#elementSelector);

            const buttonRow = domMake.Tree("div", { class: "control-buttons", style: "display: flex; justify-content: space-between;" });
            const showButton = domMake.Button("Mostrar");
            showButton.id = "show-element";
            showButton.addEventListener('click', () => this.#toggleElementVisibility(false));

            const hideButton = domMake.Button("Ocultar");
            hideButton.id = "hide-element";
            hideButton.addEventListener('click', () => this.#toggleElementVisibility(true));

            buttonRow.appendAll(showButton, hideButton);
            container.appendChild(buttonRow);

            this.htmlElements.section.appendChild(container);
        }

        #populateSelector() {
            const currentSelectedValue = this.#elementSelector.value;
            this.#elementSelector.innerHTML = '';
            const addedSelectors = new Set();

            const placeholderOption = domMake.Tree('option', { value: '' }, ['-- Selecciona un elemento --']);
            this.#elementSelector.appendChild(placeholderOption);

            allKnownElements.forEach(item => {
                try {
                    if (document.querySelector(item.selector) && !addedSelectors.has(item.selector)) {
                        const option = domMake.Tree('option', { value: item.selector }, [item.label]);
                        this.#elementSelector.appendChild(option);
                        addedSelectors.add(item.selector);
                    }
                } catch (e) {
                    // Only log to console, avoid chat spam for selector errors
                    console.warn(`[HideShowMenus] Selector inválido: ${item.selector}. Error: ${e.message}`);
                }
            });

            if (currentSelectedValue && Array.from(this.#elementSelector.options).some(opt => opt.value === currentSelectedValue)) {
                this.#elementSelector.value = currentSelectedValue;
            } else {
                this.#elementSelector.value = '';
            }
            // Removed: this.notify("log", "Selector de elementos actualizado.");
            // This was the source of spam, no longer notifying chat for mere selector updates.
        }

        #toggleElementVisibility(hide) {
            const selectedValue = this.#elementSelector.value;
            if (!selectedValue) {
                this.notify("warning", "No hay elemento seleccionado.");
                return;
            }

            try {
                document.querySelectorAll(selectedValue).forEach(el => {
                    if (hide) {
                        if (el.style.display && el.style.display !== 'none') {
                            el.dataset.originalDisplay = el.style.display;
                        }
                        el.style.display = 'none';
                        el.style.visibility = 'hidden';
                        if (selectedValue.includes('.modal-backdrop')) {
                             el.remove(); // Remove modal backdrop if hiding it
                        }
                        this.notify("info", `Ocultando: ${selectedValue}`);
                    } else {
                        if (el.dataset.originalDisplay) {
                            el.style.display = el.dataset.originalDisplay;
                            delete el.dataset.originalDisplay;
                        } else {
                            el.style.display = '';
                        }
                        el.style.visibility = '';
                        this.notify("info", `Mostrando: ${selectedValue}`);
                    }
                });
            } catch (e) {
                this.notify("error", `Error al ${hide ? 'ocultar' : 'mostrar'} el elemento ${selectedValue}: ${e.message}`);
            }
        }

        #setupObserver() {
            if (this.#mutationObserver) {
                this.#mutationObserver.disconnect();
            }

            this.#mutationObserver = new MutationObserver(() => {
                clearTimeout(this.#mutationObserver._timer);
                this.#mutationObserver._timer = setTimeout(() => {
                    this.#populateSelector();
                }, 500);
            });

            this.#mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
        }
    }
})("QBit");

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

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

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

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

        #loadInterface() {
            const row = domMake.Row();
            const exportButton = domMake.Button("Exportar Chat (TXT)");
            exportButton.title = "Exporta todos los mensajes del chat a un archivo de texto.";

            exportButton.addEventListener("click", () => this.#exportChatMessages());

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

        #exportChatMessages() {
            const chatbox = document.getElementById('chatbox_messages');
            if (!chatbox) {
                this.notify("warning", "Contenedor de chat no encontrado.");
                return;
            }

            const messages = chatbox.querySelectorAll('div.chatmessage');
            let exportedMessages = [];

            messages.forEach(message => {
                let timestamp = message.dataset.ts ? new Date(parseInt(message.dataset.ts)).toLocaleTimeString() : 'N/A';
                if (message.classList.contains('systemchatmessage') || message.classList.contains('systemchatmessage5')) {
                    exportedMessages.push(`[${timestamp}] [Sistema] ${message.textContent.trim().replace(/^System: /, '')}`);
                } else if (message.classList.contains('playerchatmessage-highlightable') || message.classList.contains('chatmessage')) {
                    const playerName = message.querySelector('.playerchatmessage-name')?.textContent?.trim() || 'Desconocido';
                    const playerMessage = message.querySelector('.playerchatmessage-text')?.textContent?.trim() || '';
                    exportedMessages.push(`[${timestamp}] ${playerName}: ${playerMessage}`);
                }
            });

            if (exportedMessages.length === 0) {
                this.notify("info", "No hay mensajes en el chat para exportar.");
                return;
            }

            const blob = new Blob([exportedMessages.join('\n')], { type: 'text/plain;charset=utf-8' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `drawaria_chat_${new Date().toISOString().slice(0, 10)}.txt`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            this.notify("success", "Chat exportado exitosamente.");
        }
    }
})("QBit");

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

    // Re-declare parseServerUrl and parseRoomId if they are not globally accessible outside BotClient scope
    function parseServerUrl(any) {
        var prefix = String(any).length == 1 ? `sv${any}.` : ""; // Expects a single digit server ID
        return `wss://${prefix}drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`;
    }

    function parseRoomId(any) {
        // Extract the main room ID part, before any optional .server_id
        const match = String(any).match(/^([a-f0-9-]+)(?:\.\d+)?$/i);
        if (match && match[1]) {
            return match[1];
        }
        // If it's a direct room ID like "12345", then that's the ID.
        // If it's a full URL, attempt to get last segment as ID.
        const urlMatch = String(any).match(/([a-f0-9.-]+?)$/gi);
        if (urlMatch && urlMatch[0]) {
            return urlMatch[0];
        }
        return String(any); // Fallback to original if no specific ID extracted
    }

    // AÑADIDO: RE-DECLARACIÓN DE parseSocketIOEvent para su accesibilidad
    function parseSocketIOEvent(prefix_length, event_data) {
        try {
            return JSON.parse(event_data.slice(prefix_length));
        } catch (error) {
            // Puedes añadir un console.error aquí para depuración si es necesario
            // console.error("Error parsing socket event data:", error, "Data:", event_data);
            return null; // Retorna null o un array vacío si falla el parseo
        }
    }
    // FIN AÑADIDO

    // Reference to original emits object (if it's not global)
    const emits = _io.emits; // Assuming _io is global as per original script

    // Redefine BotClient class to inject into QBit's context
    // This is necessary because we are modifying its methods for room joining.
    // Ensure the original BotClient is available for modification.
    const OriginalBotClient = QBit.findGlobal("BotClient"); // Get the original class reference

    if (OriginalBotClient) {
        // Override/extend methods of the original BotClient prototype
        // This is safer than re-declaring the whole class if other modules rely on its specific constructor
        // or static properties.

        // Store original methods to call them if needed or as a fallback
        const originalBotClientConnect = OriginalBotClient.prototype.connect;
        const originalBotClientEnterRoom = OriginalBotClient.prototype.enterRoom;
        const originalBotClientDisconnect = OriginalBotClient.prototype.disconnect;
        const originalBotClientReconnect = OriginalBotClient.prototype.reconnect;

        Object.assign(OriginalBotClient.prototype, {
            // New or modified internal method to handle socket opening and initial commands
            // Renamed to avoid conflicts and clearly separate concerns.
            _onSocketOpenHandler(event) {
                const localThis = this;
                clearInterval(localThis.interval_id); // Clear any old interval
                localThis.interval_id = setInterval(function () {
                    if (!localThis.getReadyState()) {
                        clearInterval(localThis.interval_id);
                        localThis.notify("info", `Bot ${localThis.name} desconectado (ping fallido).`);
                        return;
                    }
                    localThis.send(2); // Keep-alive ping
                }, localThis.interval_ms);

                // ONLY send startplay AFTER the socket is confirmed open
                if (localThis.room.id) { // Ensure there's a room ID set before attempting to start play
                    localThis.send(emits.startplay(localThis.room, localThis.name, localThis.avatar));
                    localThis.notify("success", `Bot ${localThis.name} conectado y en sala ${localThis.room.id}.`);
                } else {
                    localThis.notify("warning", `Bot ${localThis.name} conectado, pero sin ID de sala para iniciar juego.`);
                }
            },

// ... dentro de (function BotClientModifications() { ... })("QBit"); ...
// ... busca Object.assign(OriginalBotClient.prototype, { ...
// ... y dentro de ese objeto, busca _onSocketMessageHandler y reemplázalo: ...

            _onSocketMessageHandler(message_event) {
                var prefix = String(message_event.data).match(/(^\d+)/gi)?.[0] || "";
                var data = parseSocketIOEvent(prefix.length, message_event.data) || [];

                if (data && data.length === 1) {
                    if (data[0].players) this.room.players = data[0].players;
                }
                if (data && data.length > 1) {
                    var event = data.shift();

                    // Special handling for raw 'drawcmd' to dispatch a custom event
                    if (event === "drawcmd") {
                        this.customObservers.forEach((listener) => {
                            if (listener.event === "bc_drawcommand") { // Dispatch as bc_drawcommand for DrawingReplay etc.
                                if (listener.callback) listener.callback(data);
                            }
                        });
                    }

                    // Dispatch any other event normally
                    this.customObservers.forEach((listener) => {
                        if (listener.event === event) if (listener.callback) listener.callback(data);
                    });
                }
            },

// ... el resto de BotClientModifications continúa ...

            _onSocketCloseHandler(event) {
                clearInterval(this.interval_id);
                this.socket = null; // Ensure socket reference is cleared
                this.notify("info", `Bot ${this.name} socket cerrado. Código: ${event.code}, Razón: ${event.reason}`);
                // The global `sockets` array is managed by WebSocket.prototype.send override, no need to manually splice here.
            },

            _onSocketErrorHandler(event) {
                this.notify("error", `Error de socket para bot ${this.name}.`);
                console.error(`WebSocket Error for ${this.name}:`, event);
                clearInterval(this.interval_id);
                this.socket = null;
            },

            // Overriding connect method
            connect(serverUrlSegment = "") {
                if (this.getReadyState()) {
                    // Already connected. Disconnect first to ensure a clean new connection.
                    this.notify("info", `Bot ${this.name} ya está conectado. Desconectando para reconectar.`);
                    this.disconnect();
                }

                const fullServerUrl = parseServerUrl(serverUrlSegment);
                this.socket = new WebSocket(fullServerUrl);

                // Bind handlers to 'this' context of the BotClient instance
                this.socket.addEventListener("open", this._onSocketOpenHandler.bind(this));
                this.socket.addEventListener("message", this._onSocketMessageHandler.bind(this));
                this.socket.addEventListener("close", this._onSocketCloseHandler.bind(this));
                this.socket.addEventListener("error", this._onSocketErrorHandler.bind(this));

                this.notify("info", `Bot ${this.name} intentando conectar a: ${fullServerUrl}`);
            },

            // Overriding enterRoom method
            enterRoom(fullRoomIdOrUrl) {
                this.room.id = parseRoomId(fullRoomIdOrUrl); // Gets "uuid" part
                let serverIdSegment = "";
                const parts = String(fullRoomIdOrUrl).split('.');
                // Check if the last part is a number and indicates a server ID
                if (parts.length > 1 && !isNaN(parseInt(parts[parts.length - 1]))) {
                    serverIdSegment = parts[parts.length - 1];
                }
                this.connect(serverIdSegment); // Connect using only the server ID part
                // The `startplay` command will be sent automatically once the socket opens (in _onSocketOpenHandler)
            },

            // Overriding disconnect method
            disconnect() {
                if (!this.getReadyState()) {
                    this.notify("info", `Bot ${this.name} ya está desconectado.`);
                    return;
                }
                clearInterval(this.interval_id); // Clear ping interval
                this.send(41); // Explicitly send disconnect message
                this.socket.close(); // Close the WebSocket connection
                this.socket = null; // Clear the socket reference
                this.notify("info", `Bot ${this.name} se ha desconectado de la sala.`);
            },

            // Overriding reconnect method - now primarily re-enters the current room
            reconnect() {
                if (this.room.id) {
                    this.notify("info", `Bot ${this.name} intentando reconectar a la sala ${this.room.id}.`);
                    this.enterRoom(this.room.id); // Re-use enterRoom logic
                } else {
                    this.notify("warning", `Bot ${this.name} no tiene una sala establecida para reconectar.`);
                }
            }
        });
    } else {
        console.error("BotClient class not found for modification. Join room functionality may not work.");
    }
})("QBit");

// --- START UPDATED MODULE: MoreColorPalettes (ACTUALIZADO para añadir colores externos) ---
(function MoreColorPalettes() {
    const QBit = globalThis[arguments[0]];

    const LOCAL_STORAGE_KEY = 'cubicEngineCustomColors';
    const DEFAULT_CUSTOM_COLORS = [
        { name: "Teal", hex: "#008080" },
        { name: "Lime", hex: "#AAFF00" },
        { name: "Cyan", hex: "#00FFFF" },
        { name: "Magenta", hex: "#FF00FF" },
        { name: "Olive", hex: "#808000" },
        { name: "Maroon", hex: "#800000" }
    ];

    QBit.Styles.addRules([
        `#${QBit.identifier} .custom-color-button {
            box-shadow: 0 0 2px rgba(0,0,0,0.3);
            cursor: pointer;
            border: 1px solid transparent; /* default border */
        }`,
        `#${QBit.identifier} .custom-color-button.custom-active-color {
            box-shadow: 0 0 5px 2px var(--info); /* Highlight for active custom color */
            border: 1px solid var(--info);
        }`,
        // Ensure Drawaria's native triangle transitions smoothly
        `#colorpicker-cursor {
            transition: left 0.1s ease-out;
        }`
    ]);

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

        #customColors = [];
        #colorButtonsContainer;
        #colorInput;
        #drawControlsObserver;
        #gameTriangleElement = null;
        #proxyGameButton = null; // The game's native button we'll use to proxy clicks

        constructor() {
            super("Paletas de Color", '<i class="fas fa-palette"></i>');
            this.#onStartup();
        }

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

        #loadInterface() {
            const row1 = domMake.Row();
            {
                const addColorLabel = domMake.Tree("label", {}, ["Añadir Color:"]);
                this.#colorInput = domMake.Tree("input", { type: "color", value: "#FF0000" });
                const addColorButton = domMake.Button("Añadir");
                addColorButton.addEventListener("click", () => this.#addNewCustomColor(this.#colorInput.value));
                row1.appendAll(addColorLabel, this.#colorInput, addColorButton);
            }
            this.htmlElements.section.appendChild(row1);

            const row2 = domMake.Row();
            {
                const clearAllColorsButton = domMake.Button("Limpiar Todos");
                clearAllColorsButton.addEventListener("click", () => this.#clearAllCustomColors());
                row2.appendChild(clearAllColorsButton);
            }
            this.htmlElements.section.appendChild(row2);

            const row3 = domMake.Row();
            this.#colorButtonsContainer = domMake.IconList(); // Using IconList for flex display
            row3.appendChild(this.#colorButtonsContainer);
            this.htmlElements.section.appendChild(row3);
        }

        #loadCustomColors() {
            try {
                const storedColors = localStorage.getItem(LOCAL_STORAGE_KEY);
                this.#customColors = storedColors ? JSON.parse(storedColors) : [...DEFAULT_CUSTOM_COLORS];
            } catch (e) {
                this.notify("error", `Error al cargar colores: ${e.message}. Usando colores por defecto.`);
                this.#customColors = [...DEFAULT_CUSTOM_COLORS];
            }
            this.#renderCustomColorButtons();
        }

        #saveCustomColors() {
            try {
                localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(this.#customColors));
                this.notify("success", "Colores personalizados guardados.");
            } catch (e) {
                this.notify("error", `Error al guardar colores: ${e.message}`);
            }
        }

        #renderCustomColorButtons() {
            this.#colorButtonsContainer.innerHTML = ''; // Clear existing buttons
            this.#customColors.forEach(color => {
                this.#createColorButton(color.hex, color.name);
            });
        }

        #addNewCustomColor(hexColor) {
            // Check for duplicates before adding
            if (this.#customColors.some(color => color.hex.toLowerCase() === hexColor.toLowerCase())) {
                this.notify("info", `El color ${hexColor} ya existe en tu paleta.`);
                return;
            }
            const newColor = { name: `Custom-${hexColor}`, hex: hexColor };
            this.#customColors.push(newColor);
            this.#saveCustomColors();
            this.#createColorButton(newColor.hex, newColor.name); // Add single button
            this.notify("info", `Color ${hexColor} añadido.`);
        }

        // Nuevo método para añadir colores desde otros módulos
        addCustomColorFromExternal(hexColor) {
            this.#addNewCustomColor(hexColor);
        }


        #clearAllCustomColors() {
            if (confirm("¿Estás seguro de que quieres eliminar todos los colores personalizados?")) {
                this.#customColors = [...DEFAULT_CUSTOM_COLORS]; // Reset to defaults
                this.#saveCustomColors();
                this.#renderCustomColorButtons();
                this.notify("info", "Colores personalizados reiniciados a los valores por defecto.");
            }
        }

        #createColorButton(hexColor, name) {
            const newButton = domMake.Tree("div", {
                class: "drawcontrols-button drawcontrols-color custom-color-button",
                style: `background-color: ${hexColor};`,
                title: name,
                "data-hex": hexColor
            });

            newButton.addEventListener('click', (event) => this.#handleCustomColorClick(newButton));
            this.#colorButtonsContainer.appendChild(newButton);
        }

        #findGameElements() {
            // Find the game's native color picker triangle
            if (!this.#gameTriangleElement || !document.body.contains(this.#gameTriangleElement)) {
                this.#gameTriangleElement = document.getElementById('colorpicker-cursor');
            }

            // Find a suitable proxy button from the game's original palette
            if (!this.#proxyGameButton || !document.body.contains(this.#proxyGameButton)) {
                const drawControls = document.getElementById('drawcontrols-colors') || document.getElementById('drawcontrols');
                if (drawControls) {
                    // Get first non-custom, non-colorpicker button that is a color
                    this.#proxyGameButton = drawControls.querySelector('.drawcontrols-button.drawcontrols-color:not(.drawcontrols-colorpicker):not(.custom-color-button)');
                }
            }
        }

        #handleCustomColorClick(clickedButton) {
            this.#findGameElements();

            if (!this.#proxyGameButton) {
                this.notify("warning", "No se encontró un botón de color de juego para proxy. La funcionalidad puede ser limitada.");
                return;
            }

            const customColor = clickedButton.dataset.hex;
            const originalProxyColor = this.#proxyGameButton.style.backgroundColor;

            // Step 1: Set the proxy button's background to our custom color
            this.#proxyGameButton.style.backgroundColor = customColor;

            // Step 2: Simulate a click on the proxy button. This makes the game's internal logic think one of its own
            // buttons was clicked, updating the actual drawing color and moving its triangle.
            this.#proxyGameButton.click();

            // Step 3: Use requestAnimationFrame to ensure the game's triangle movement completes,
            // then immediately revert the proxy button's color and move the triangle to our custom button.
            requestAnimationFrame(() => {
                this.#proxyGameButton.style.backgroundColor = originalProxyColor; // Restore visual of proxy button

                // Manually move Drawaria's triangle element
                this.#updateTrianglePosition(clickedButton);

                // Manage active visual state for custom buttons
                document.querySelectorAll('.custom-color-button.custom-active-color').forEach(btn => {
                    btn.classList.remove('custom-active-color');
                });
                clickedButton.classList.add('custom-active-color');

                // Ensure native game buttons lose their active state (the game handles this implicitly by proxy click)
            });
        }

        #updateTrianglePosition(targetButton) {
            const triangle = this.#gameTriangleElement;
            if (!triangle || !targetButton) return;

            const buttonContainer = document.getElementById('drawcontrols-colors') || document.getElementById('drawcontrols');
            if (!buttonContainer) return;

            const buttonRect = targetButton.getBoundingClientRect();
            const containerRect = buttonContainer.getBoundingClientRect();

            const buttonCenterRelativeToContainer = (buttonRect.left - containerRect.left) + (buttonRect.width / 2);
            const triangleWidth = triangle.offsetWidth || 8;
            const newLeft = buttonCenterRelativeToContainer - (triangleWidth / 2);

            triangle.style.left = `${newLeft}px`;
        }

        #setupDrawControlsObserver() {
            // We need to observe the .drawcontrols-colors container to find game buttons
            // and attach listeners to them, so that when a native color is picked, our custom
            // buttons get their 'active' class removed.
            const observerTarget = document.getElementById('drawcontrols-colors') || document.getElementById('drawcontrols');
            if (!observerTarget) {
                this.notify("warning", "Contenedor de controles de dibujo no encontrado. Los colores personalizados pueden no funcionar bien.");
                // Retry finding later
                setTimeout(() => this.#setupDrawControlsObserver(), 1000);
                return;
            }

            this.#drawControlsObserver = new MutationObserver((mutations) => {
                mutations.forEach(mutation => {
                    if (mutation.type === 'childList' || mutation.type === 'attributes') {
                        // Re-evaluate game buttons if DOM changes, in case they are dynamically added/removed
                        // or their active state changes.
                        this.#addListenersToGameColorButtons();
                    }
                });
            });

            this.#drawControlsObserver.observe(observerTarget, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style'] });

            // Initial setup for existing buttons
            this.#addListenersToGameColorButtons();
        }

        #addListenersToGameColorButtons() {
            this.#findGameElements(); // Ensure latest references

            // Add listeners to all native game color buttons
            const gameColorButtons = document.querySelectorAll('.drawcontrols-button.drawcontrols-color:not(.custom-color-button)');
            gameColorButtons.forEach(gameBtn => {
                // Remove existing listener to prevent duplicates if called multiple times by observer
                gameBtn.removeEventListener('click', this.#handleGameColorClick);
                gameBtn.addEventListener('click', this.#handleGameColorClick.bind(this));
            });
        }

        #handleGameColorClick() {
            // When a native game color button is clicked, remove the custom-active-color class from our buttons
            document.querySelectorAll('.custom-color-button.custom-active-color').forEach(customBtn => {
                customBtn.classList.remove('custom-active-color');
            });
            // The game's native triangle will move automatically for its own buttons.
        }
    }
})("QBit");
// --- END UPDATED MODULE: MoreColorPalettes ---



// --- START UPDATED MODULE: AutodrawV2 (ACTUALIZADO con Modo Formas) ---
(function AutodrawV2() {
    const QBit = globalThis[arguments[0]];

    QBit.Styles.addRules([
        `#${QBit.identifier} .autodraw-controls .cheat-row {
            display: flex;
            width: 100%;
            margin-bottom: 5px;
        }`,
        `#${QBit.identifier} .autodraw-controls .cheat-row > * {
            flex: 1;
            margin: 0 2px;
            text-align: center;
        }`,
        `#${QBit.identifier} .autodraw-controls input[type="number"],
         #${QBit.identifier} .autodraw-controls input[type="file"] {
            width: 100%;
            padding: 5px;
            box-sizing: border-box;
            border: 1px solid var(--CE-color);
            border-radius: .25rem;
            background-color: var(--CE-bg_color);
            color: var(--CE-color);
        }`,
        `#${QBit.identifier} .autodraw-controls .btn {
            width: 100%;
            padding: 5px;
            box-sizing: border-box;
            background-color: var(--secondary); /* Grey button for controls */
        }`,
        `#${QBit.identifier} .autodraw-controls .btn.active {
            background-color: var(--success); /* Active state green */
        }`,
        `#${QBit.identifier} .autodraw-controls .btn i {
            margin-right: 5px;
        }`,
        `#${QBit.identifier} .autodraw-controls .effect-toggle.active {
            background-color: var(--info); /* Blue for active effect */
            color: white;
        }`,
        `#${QBit.identifier} .autodraw-controls .effect-toggle {
            background-color: var(--secondary);
            color: var(--dark);
        }`,
        `#${QBit.identifier} .autodraw-controls label {
            font-size: 0.85em;
            margin-bottom: 3px;
            display: block;
        }`
    ]);

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

        #previewCanvas; // This internal canvas is now crucial for image processing
        #originalCanvas; // The game's canvas (not used for image loading, but for dimensions)
        #imageData = null; // Raw pixel data from the loaded image
        #executionLine = []; // Array of drawing commands (lines/dots)
        #drawingActive = false; // Control drawing loop

        // Drawing Modes
        #currentDrawingMode = 'rainMode'; // Default mode
        #rainColumns = []; // For rain mode
        #spiralAngle = 0; // For spiral mode

        // UI Element References for settings
        #imageSizeInput;
        #brushSizeInput;
        #pixelSizeInput;
        #offsetXInput;
        #offsetYInput;
        #drawingSpeedInput;
        #modeButtons = {}; // To manage active state of mode buttons
        #imageFileInput; // Reference to the file input

        // Default Settings
        #defaultSettings = {
            imageSize: 4,
            brushSize: 32,
            pixelSize: 1,
            offsetX: 10,
            offsetY: 0,
            drawingSpeed: 10
        };

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

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

        #loadInterface() {
            const container = domMake.Tree("div", { class: "autodraw-controls" });

            // Image Loader
            const imageLoadRow = domMake.Row();
            this.#imageFileInput = domMake.Tree("input", { type: "file", id: "autodraw-image-input", title: "Cargar Imagen (PNG/JPG)" });
            this.#imageFileInput.addEventListener("change", (e) => this.#readImage(e.target));
            imageLoadRow.appendChild(this.#imageFileInput);
            container.appendChild(imageLoadRow);

            // Drawing Settings - Row 1 (Image Size, Brush Size, Pixel Size)
            const settingsRow1 = domMake.Row();
            this.#imageSizeInput = domMake.Tree("input", { type: "number", min: "1", max: "20", value: this.#defaultSettings.imageSize, title: "Tamaño de Imagen (1=grande, 20=pequeña)" });
            this.#brushSizeInput = domMake.Tree("input", { type: "number", min: "1", max: "100", value: this.#defaultSettings.brushSize, title: "Tamaño del Pincel" });
            this.#pixelSizeInput = domMake.Tree("input", { type: "number", min: "1", max: "50", value: this.#defaultSettings.pixelSize, title: "Espacio entre Píxeles" });
            settingsRow1.appendAll(
                domMake.Tree("div", {}, [domMake.Tree("label", {}, ["Tamaño Img:"]), this.#imageSizeInput]),
                domMake.Tree("div", {}, [domMake.Tree("label", {}, ["Tamaño Pincel:"]), this.#brushSizeInput]),
                domMake.Tree("div", {}, [domMake.Tree("label", {}, ["Espacio Px:"]), this.#pixelSizeInput])
            );
            container.appendChild(settingsRow1);

            // Drawing Settings - Row 2 (Offset X, Offset Y, Drawing Speed)
            const settingsRow2 = domMake.Row();
            this.#offsetXInput = domMake.Tree("input", { type: "number", min: "-50", max: "150", value: this.#defaultSettings.offsetX, title: "Desplazamiento X (0-100)" });
            this.#offsetYInput = domMake.Tree("input", { type: "number", min: "-50", max: "150", value: this.#defaultSettings.offsetY, title: "Desplazamiento Y (0-100)" });
            this.#drawingSpeedInput = domMake.Tree("input", { type: "number", min: "1", max: "100", value: this.#defaultSettings.drawingSpeed, title: "Velocidad de Dibujo (ms/línea)" });

            settingsRow2.appendAll(
                domMake.Tree("div", {}, [domMake.Tree("label", {}, ["Offset X:"]), this.#offsetXInput]),
                domMake.Tree("div", {}, [domMake.Tree("label", {}, ["Offset Y:"]), this.#offsetYInput]),
                domMake.Tree("div", {}, [domMake.Tree("label", {}, ["Vel. Dibujo (ms):"]), this.#drawingSpeedInput])
            );
            container.appendChild(settingsRow2);

            // Control Buttons (Start/Stop)
            const controlButtonsRow = domMake.Row();
            const startButton = domMake.Button('<i class="fas fa-play-circle"></i> Iniciar Dibujo');
            startButton.addEventListener("click", () => this.#startDrawing());
            const stopButton = domMake.Button('<i class="fas fa-stop-circle"></i> Detener Dibujo');
            stopButton.addEventListener("click", () => this.#stopDrawing());
            controlButtonsRow.appendAll(startButton, stopButton);
            container.appendChild(controlButtonsRow);

            // Drawing Modes
            const modesRow = domMake.Row();
            modesRow.style.marginTop = "10px";
            modesRow.style.flexWrap = "wrap";
            modesRow.style.gap = "5px";

            const addModeButton = (label, modeKey, iconClass) => {
                const button = domMake.Button(`<i class="${iconClass}"></i> ${label}`);
                button.classList.add("effect-toggle");
                button.addEventListener("click", () => this.#setDrawingMode(modeKey));
                this.#modeButtons[modeKey] = button;
                modesRow.appendChild(button);
            };

            addModeButton("Modo Lluvia", "rainMode", "fas fa-cloud-rain");
            addModeButton("Onda", "waveDraw", "fas fa-wave-square");
            addModeButton("Espiral", "spiralDraw", "fas fa-circle-notch");
            addModeButton("Píxel Aleatorio", "randomPixelDraw", "fas fa-dice");
            addModeButton("Modo Formas", "shapeDrawMode", "fas fa-bezier-curve"); // Nuevo botón para el modo formas
            container.appendChild(modesRow);


            this.htmlElements.section.appendChild(container); // AÑADIDO: Asegura que el contenedor principal esté añadido
        }

        #setInitialSettings() {
            this.#imageSizeInput.value = this.#defaultSettings.imageSize;
            this.#brushSizeInput.value = this.#defaultSettings.brushSize;
            this.#pixelSizeInput.value = this.#defaultSettings.pixelSize;
            this.#offsetXInput.value = this.#defaultSettings.offsetX;
            this.#offsetYInput.value = this.#defaultSettings.offsetY;
            this.#drawingSpeedInput.value = this.#defaultSettings.drawingSpeed;

            this.#setDrawingMode('rainMode'); // Activate rainMode by default
        }

        #setupCanvas() {
            this.#previewCanvas = document.createElement('canvas');
            this.#originalCanvas = document.getElementById('canvas'); // The game's drawing canvas

            if (this.#originalCanvas) {
                this.#previewCanvas.width = this.#originalCanvas.width;
                this.#previewCanvas.height = this.#originalCanvas.height;
            } else {
                this.#previewCanvas.width = 1000;
                this.#previewCanvas.height = 1000;
                this.notify("warning", "Canvas del juego no encontrado. Usando dimensiones por defecto para el lienzo interno.");
            }
        }

        #readImage(fileInput) {
            if (!fileInput.files || !fileInput.files[0]) {
                this.notify("warning", "No se seleccionó ninguna imagen.");
                this.#imageData = null; // Clear any previous image data
                return;
            }

            const FR = new FileReader();
            FR.addEventListener('load', (evt) => {
                const img = new Image();
                img.addEventListener('load', () => {
                    this.notify("info", "Imagen cargada. Procesando pixeles...");
                    const ctx = this.#previewCanvas.getContext('2d');
                    ctx.clearRect(0, 0, this.#previewCanvas.width, this.#previewCanvas.height);

                    ctx.drawImage(img, 0, 0, this.#previewCanvas.width, this.#previewCanvas.height);

                    this.#imageData = ctx.getImageData(0, 0, this.#previewCanvas.width, this.#previewCanvas.height);
                    this.notify("success", "Imagen lista para dibujar.");

                    if (this.#currentDrawingMode) {
                        this.#prepareDrawingCommands();
                    }

                });
                img.crossOrigin = 'anonymous';
                img.src = evt.target.result;
            });
            FR.readAsDataURL(fileInput.files[0]);
        }

        async #prepareDrawingCommands() {
            if (!this.#imageData) {
                this.notify("warning", "Carga una imagen primero.");
                return false;
            }

            this.#executionLine = [];

            const { width, height } = this.#imageData;
            const size = parseFloat(this.#imageSizeInput.value);
            const modifier = parseFloat(this.#pixelSizeInput.value);
            const thickness = parseFloat(this.#brushSizeInput.value);
            const offsetX = parseFloat(this.#offsetXInput.value);
            const offsetY = parseFloat(this.#offsetYInput.value);

            const toGameCoords = (x_pixel, y_pixel, originalImgWidth, originalImgHeight) => {
                const finalDrawWidth = 100 / size;
                const finalDrawHeight = 100 / size;

                const gameX = (x_pixel / originalImgWidth) * finalDrawWidth + offsetX;
                const gameY = (y_pixel / originalImgHeight) * finalDrawHeight + offsetY;
                return [gameX, gameY];
            };

            const getPixelColor = (x, y) => {
                const originalPxX = Math.floor(x * (this.#imageData.width / this.#previewCanvas.width));
                const originalPxY = Math.floor(y * (this.#imageData.height / this.#previewCanvas.height));

                if (originalPxX < 0 || originalPxX >= this.#imageData.width || originalPxY < 0 || originalPxY >= this.#imageData.height) return null;
                const index = (originalPxY * this.#imageData.width + originalPxX) * 4;
                const a = this.#imageData.data[index + 3];
                if (a < 20) return null;
                const r = this.#imageData.data[index + 0];
                const g = this.#imageData.data[index + 1];
                const b = this.#imageData.data[index + 2];
                return `rgb(${r},${g},${b})`;
            };


            if (this.#currentDrawingMode === 'rainMode') {
                for (let x = 0; x < width; x += modifier) {
                    let columnPixels = [];
                    for (let y = 0; y < height; y += modifier) {
                        const color = getPixelColor(x, y);
                        if (color) {
                            columnPixels.push({ x, y, color });
                        }
                    }
                    if (columnPixels.length > 0) {
                        this.#rainColumns.push({ x, pixels: columnPixels });
                    }
                }
                this.#shuffleArray(this.#rainColumns);

                for (let col of this.#rainColumns) {
                    let pixels = col.pixels;
                    if (pixels.length === 0) continue;

                    pixels.sort((a, b) => a.y - b.y);

                    let startPixel = pixels[0];
                    let prevPixel = pixels[0];

                    for (let i = 1; i < pixels.length; i++) {
                        let currentPixel = pixels[i];
                        if (currentPixel.y !== prevPixel.y + modifier || currentPixel.color !== prevPixel.color) {
                            this.#executionLine.push({
                                pos1: toGameCoords(startPixel.x, startPixel.y, width, height),
                                pos2: toGameCoords(prevPixel.x, prevPixel.y, width, height),
                                color: startPixel.color,
                                thickness
                            });
                            startPixel = currentPixel;
                        }
                        prevPixel = currentPixel;
                    }
                    this.#executionLine.push({
                        pos1: toGameCoords(startPixel.x, startPixel.y, width, height),
                        pos2: toGameCoords(prevPixel.x, prevPixel.y, width, height),
                        color: startPixel.color,
                        thickness
                    });
                }

            } else if (this.#currentDrawingMode === 'waveDraw') {
                const waveAmplitude = 15;
                const waveFrequency = 0.05;

                for (let y = 0; y < height; y += modifier) {
                    let startPixel = null;
                    let lastColor = null;

                    for (let x = 0; x < width; x += modifier) {
                        let currentX = x;
                        let currentY = y + waveAmplitude * Math.sin(x * waveFrequency);

                        const actualColor = getPixelColor(currentX, currentY);

                        if (actualColor) {
                            if (!startPixel) {
                                startPixel = { x: currentX, y: currentY, color: actualColor };
                                lastColor = actualColor;
                            } else if (actualColor !== lastColor) {
                                this.#executionLine.push({
                                    pos1: toGameCoords(startPixel.x, startPixel.y, width, height),
                                    pos2: toGameCoords(currentX, currentY, width, height),
                                    color: lastColor,
                                    thickness
                                });
                                startPixel = { x: currentX, y: currentY, color: actualColor };
                                lastColor = actualColor;
                            }
                        } else if (startPixel) {
                            this.#executionLine.push({
                                pos1: toGameCoords(startPixel.x, startPixel.y, width, height),
                                pos2: toGameCoords(currentX, currentY, width, height),
                                color: lastColor,
                                thickness
                            });
                            startPixel = null;
                            lastColor = null;
                        }
                    }
                    if (startPixel) {
                        this.#executionLine.push({
                            pos1: toGameCoords(startPixel.x, startPixel.y, width, height),
                            pos2: toGameCoords(width, y + waveAmplitude * Math.sin(width * waveFrequency), width, height),
                            color: lastColor,
                            thickness
                        });
                    }
                }

            } else if (this.#currentDrawingMode === 'spiralDraw') {
                const centerX = width / 2;
                const centerY = height / 2;
                const maxRadius = Math.min(width, height) / 2;
                const density = 0.5;

                for (let r = 0; r < maxRadius; r += modifier * density) {
                    const numPoints = Math.floor(2 * Math.PI * r / modifier);
                    if (numPoints === 0) continue;

                    let prevX = -1, prevY = -1;
                    let startPoint = null;
                    let lastColor = null;

                    for (let i = 0; i < numPoints; i++) {
                        const angle = (i / numPoints) * 2 * Math.PI;
                        const spiralX = centerX + r * Math.cos(angle);
                        const spiralY = centerY + r * Math.sin(angle);

                        const color = getPixelColor(spiralX, spiralY);

                        if (color) {
                            if (startPoint === null) {
                                startPoint = { x: spiralX, y: spiralY, color: color };
                                lastColor = color;
                            } else if (color !== lastColor) {
                                this.#executionLine.push({
                                    pos1: toGameCoords(startPoint.x, startPoint.y, width, height),
                                    pos2: toGameCoords(prevX, prevY, width, height),
                                    color: lastColor,
                                    thickness
                                });
                                startPoint = { x: spiralX, y: spiralY, color: color };
                                lastColor = color;
                            }
                            prevX = spiralX;
                            prevY = spiralY;
                        } else if (startPoint !== null) {
                            this.#executionLine.push({
                                pos1: toGameCoords(startPoint.x, startPoint.y, width, height),
                                pos2: toGameCoords(prevX, prevY, width, height),
                                color: lastColor,
                                thickness
                            });
                            startPoint = null;
                        }
                    }
                    if (startPoint) {
                         this.#executionLine.push({
                            pos1: toGameCoords(startPoint.x, startPoint.y, width, height),
                            pos2: toGameCoords(prevX, prevY, width, height),
                            color: lastColor,
                            thickness
                        });
                    }
                }

            } else if (this.#currentDrawingMode === 'randomPixelDraw') {
                let allPixels = [];
                for (let y = 0; y < height; y += modifier) {
                    for (let x = 0; x < width; x += modifier) {
                        const color = getPixelColor(x, y);
                        if (color) {
                            allPixels.push({ x, y, color });
                        }
                    }
                }
                this.#shuffleArray(allPixels);

                allPixels.forEach(p => {
                    this.#executionLine.push({
                        pos1: toGameCoords(p.x, p.y, width, height),
                        pos2: toGameCoords(p.x + modifier / 2, p.y + modifier / 2, width, height),
                        color: p.color,
                        thickness
                    });
                });
            } else if (this.#currentDrawingMode === 'shapeDrawMode') {
                const shapeDetectorClass = this.findGlobal("ShapeDetector");
                if (!shapeDetectorClass || !shapeDetectorClass.siblings || shapeDetectorClass.siblings.length === 0) {
                    this.notify("error", "El módulo 'Detector de Formas' no está activo. Asegúrate de que está cargado.");
                    return false;
                }
                const shapeDetectorInstance = shapeDetectorClass.siblings[0];

                if (!shapeDetectorInstance || typeof shapeDetectorInstance.analyzeImageDataForShapes !== 'function') {
                    this.notify("error", "El módulo 'Detector de Formas' no está listo o le falta el método 'analyzeImageDataForShapes'.");
                    return false;
                }

                this.notify("info", "Analizando imagen para formas con Detector de Formas...");
                const { drawingCommands: shapeCommands } = await shapeDetectorInstance.analyzeImageDataForShapes(
                    this.#imageData,
                    this.#imageData.width,
                    this.#imageData.height,
                    false
                );

                if (shapeCommands.length === 0) {
                    this.notify("warning", "No se detectaron formas significativas en la imagen para dibujar.");
                    return false;
                }

                shapeCommands.forEach(cmd => {
                    this.#executionLine.push({
                        pos1: [cmd.x1, cmd.y1], // Ya vienen en coords 0-100 del juego
                        pos2: [cmd.x2, cmd.y2],
                        color: this.htmlElements.colorInput?.value || "#000000",
                        thickness: this.#brushSizeInput.value
                    });
                });
                this.notify("success", `Modo Formas: Se prepararon ${this.#executionLine.length} líneas desde formas detectadas.`);
            }


            this.notify("info", `Comandos de dibujo preparados para el modo '${this.#currentDrawingMode}': ${this.#executionLine.length} líneas.`);
            return true;
        }

        #shuffleArray(array) {
            for (let i = array.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [array[i], array[j]] = [array[j], array[i]];
            }
        }

        async #startDrawing() {
            const commandsPrepared = await this.#prepareDrawingCommands();
            if (!commandsPrepared) {
                return;
            }

            const botManager = this.findGlobal("BotClientManager")?.siblings[0];
            if (!botManager || botManager.children.length === 0) {
                this.notify("warning", "Necesitas al menos 1 bot activo en 'BotClientManager' para dibujar.");
                return;
            }

            const activeBots = botManager.children.filter(b => b.bot && b.bot.getReadyState());
            if (activeBots.length === 0) {
                this.notify("warning", "Ningún bot está conectado y listo para dibujar. Conecta un bot primero.");
                return;
            }

            this.#drawingActive = true;
            this.notify("info", `Iniciando dibujo con ${activeBots.length} bots...`);

            const delayMs = parseInt(this.#drawingSpeedInput.value);
            let currentLineIndex = 0;

            while (this.#drawingActive && currentLineIndex < this.#executionLine.length) {
                const line = this.#executionLine[currentLineIndex];
                const botIndex = currentLineIndex % activeBots.length;
                const botInterface = activeBots[botIndex];

                if (botInterface && botInterface.bot && botInterface.bot.getReadyState()) {
                    botInterface.bot.emit(
                        "line",
                        -1,
                        line.pos1[0], line.pos1[1],
                        line.pos2[0], line.pos2[1],
                        true,
                        line.thickness,
                        line.color,
                        false
                    );
                    currentLineIndex++;
                } else {
                    this.notify("warning", `Bot ${botInterface ? botInterface.getName() : 'desconocido'} no está listo. Saltando...`);
                    currentLineIndex++;
                }

                await new Promise(resolve => setTimeout(resolve, delayMs));
            }

            if (!this.#drawingActive) {
                this.notify("info", `Dibujo detenido manualmente. Completado ${currentLineIndex} de ${this.#executionLine.length} líneas.`);
            } else {
                this.notify("success", "Dibujo completado!");
            }
            this.#drawingActive = false;
        }

        #stopDrawing() {
            this.#drawingActive = false;
        }

        #setDrawingMode(mode) {
            this.#currentDrawingMode = mode;
            for (const key in this.#modeButtons) {
                if (this.#modeButtons.hasOwnProperty(key)) {
                    this.#modeButtons[key].classList.toggle("active", key === mode);
                }
            }
            this.notify("info", `Modo de dibujo cambiado a: '${mode}'`);

            if (this.#imageData && this.#imageData.data && this.#imageData.data.length > 0) {
                this.#prepareDrawingCommands();
            }
        }
    }
})("QBit");
// --- END UPDATED MODULE: AutodrawV2 ---



// --- START UPDATED CUBIC ENGINE FUNCTIONALITIES ---



(function BugGeneratorModule() {
    const QBit = globalThis[arguments[0]]; // Corrected access to QBit

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

        #lagInterval = null;
        #secretSpamInterval = null;
        #bugInterval = null;
        #playerChaosInterval = null;
        #visualGlitchInterval = null;


        constructor() {
            super("Generador de Errores (necesita bot)", '<i class="fas fa-bug"></i>');
            this.#onStartup();
        }

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

        #loadInterface() {
            // Row for Lag controls
            const lagRow = domMake.Row();
            const lagButton = domMake.Button('<i class="fas fa-dizzy"></i> Iniciar Lag');
            lagButton.addEventListener("click", () => this.#toggleLag(lagButton));
            lagButton.title = "Envía una ráfaga de comandos de dibujo complejos para causar lag en la sala. Requiere un bot activo.";
            lagRow.appendChild(lagButton);
            this.htmlElements.section.appendChild(lagRow);

            // Row for Bug/Secret
            const bugSecretRow = domMake.Row();
            const bugButton = domMake.Button('<i class="fas fa-gamepad"></i> Bug Experiencia');
            bugButton.addEventListener("click", () => this.#toggleBugExperience(bugButton));
            bugButton.title = "Envía comandos disruptivos de movimiento y gestos para intentar bugear la experiencia de otros jugadores. Requiere un bot activo.";
            bugSecretRow.appendChild(bugButton);

            // NEW Row for Player Chaos and Visual Glitch
            const chaosRow = domMake.Row();
            const playerChaosButton = domMake.Button('<i class="fas fa-running"></i> Caos de Jugador');
            playerChaosButton.addEventListener("click", () => this.#togglePlayerChaos(playerChaosButton));
            playerChaosButton.title = "Causa caos de movimiento y estado al bot: Mueve el avatar, hace gestos, activa/desactiva AFK y cambia banderas de estado rápidamente. Requiere un bot activo.";
            chaosRow.appendChild(playerChaosButton);

            const visualGlitchButton = domMake.Button('<i class="fas fa-ghost"></i> Glitch Visual');
            visualGlitchButton.addEventListener("click", () => this.#toggleVisualGlitch(visualGlitchButton));
            visualGlitchButton.title = "Bugea la experiencia visual de otros jugadores: Spawnea/despawnear avatares, cambia propiedades, y spammea comandos de objetos/mensajes. Requiere un bot activo.";
            chaosRow.appendChild(visualGlitchButton);
            this.htmlElements.section.appendChild(chaosRow);

            const secretButton = domMake.Button('<i class="fas fa-mask"></i> Secret (Spam Visua)');
            secretButton.addEventListener("click", () => this.#toggleSecretSpam(secretButton));
            secretButton.title = "Envía una gran cantidad de comandos de dibujo sin parar y de todos los colores para ralentizar la sala. Requiere un bot activo.";
            bugSecretRow.appendChild(secretButton);
            this.htmlElements.section.appendChild(bugSecretRow);
        }

        /**
         * Retrieves the currently selected bot instance from BotClientManager.
         * Falls back to the first available bot if none is explicitly selected.
         * Notifies the user if no bot is active or connected.
         * @returns {object|null} The active bot instance, or null if none found/ready.
         */
        #getBot() {
            const botManagerClass = this.findGlobal("BotClientManager");
            if (!botManagerClass || !botManagerClass.siblings || botManagerClass.siblings.length === 0) {
                this.notify("warning", "No hay instancias activas de 'BotClientManager'. Por favor, crea uno desde 'CubeEngine'.");
                return null;
            }

            // CORRECTED LINE: Access the first (and likely only) instance of BotClientManager
            const botManagerInstance = botManagerClass.siblings[0];

//          if (!botManagerInstance || !botManagerInstance.children || botManagerInstance.children.length === 0) {
//              this.notify("warning", "No hay bots activos en 'BotClientManager'. Por favor, crea y conecta uno.");
//              return null;
//          }

            const botClientInterfaces = botManagerInstance.children;
            let activeBotClientInterface = null;

            const selectedBotInput = document.querySelector('input[name="botClient"]:checked');
            if (selectedBotInput) {
                activeBotClientInterface = botClientInterfaces.find(bci => bci.htmlElements.input === selectedBotInput);
            }

            // CORRECTED LINE: Ensure we always assign a single instance, not an array
            if (!activeBotClientInterface && botClientInterfaces.length > 0) {
                activeBotClientInterface = botClientInterfaces[0];
                this.notify("info", `No se seleccionó un bot. Usando el primer bot disponible: ${activeBotClientInterface.getName()}.`);
            }

//          if (!activeBotClientInterface || !activeBotClientInterface.bot || !activeBotClientInterface.bot.getReadyState()) {
//              this.notify("warning", `El bot "${activeBotClientInterface ? activeBotClientInterface.getName() : 'desconocido'}" no está conectado y listo para enviar comandos.`);
//              return null;
//          }
          return activeBotClientInterface.bot;
      }

        /**
         * Toggles sending of large, random drawing commands to induce lag.
         * @param {HTMLElement} button - The button element to toggle its text/class.
         */
        #toggleLag(button) {
            if (this.#lagInterval) {
                clearInterval(this.#lagInterval);
                this.#lagInterval = null;
                button.classList.remove("active");
                button.textContent = 'Iniciar Lag';
                this.notify("info", "Generador de Lag Detenido.");
            } else {
                const bot = this.#getBot();
                if (!bot) return;

                button.classList.add("active");
                button.textContent = 'Detener Lag';
                this.notify("info", "Generador de Lag Iniciado (enviando comandos de dibujo agresivos).");

                let counter = 0;
                this.#lagInterval = setInterval(() => {
                    if (!bot.getReadyState()) {
                        this.notify("warning", "Bot desconectado, deteniendo Lag.");
                        this.#toggleLag(button); // Stop the interval
                        return;
                    }

                    // Occasionally clear the canvas for maximum disruption
                    if (counter % 50 === 0) { // Clear every ~1.25 seconds
                        bot.emit("clear");
                        this.notify("log", "Lag: Enviando comando 'Clear'!");
                    }

                    // Send multiple large, random lines per tick
                    for (let i = 0; i < 5; i++) { // Send 5 lines per interval tick
                        const x1 = Math.random() * 100;
                        const y1 = Math.random() * 100;
                        const x2 = Math.random() * 100;
                        const y2 = Math.random() * 100;
                        const size = Math.floor(Math.random() * 70) + 20; // Larger size: 20-89
                        const color = `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`;

                        bot.emit("line", -1, x1, y1, x2, y2, true, size, color, false);
                    }

                    counter++;
                    if (counter % 20 === 0) { // Log every 20 intervals
                        this.notify("log", `Lag: ${counter * 5} líneas enviadas.`);
                    }
                }, 25); // Send a command every 25ms (40 ticks/sec * 5 lines/tick = 200 lines/sec)
            }
        }


        /**
         * Toggles sending rapid avatar movements and gestures to disrupt other players' experience.
         * @param {HTMLElement} button - The button element to toggle its text/class.
         */
        #toggleBugExperience(button) {
            if (this.#bugInterval) {
                clearInterval(this.#bugInterval);
                this.#bugInterval = null;
                button.classList.remove("active");
                button.textContent = 'Bug Experiencia';
                this.notify("info", "Deteniendo 'Bugear Experiencia'.");
            } else {
                const bot = this.#getBot();
                if (!bot) return;

                button.classList.add("active");
                button.textContent = 'Detener Bug';
                this.notify("info", "Iniciando 'Bugear Experiencia': El bot enviará ráfagas de movimientos y gestos. Esto puede ser molesto para otros.");

                let count = 0;
                this.#bugInterval = setInterval(() => {
                    if (!bot.getReadyState()) {
                        this.notify("warning", "Bot desconectado, deteniendo 'Bugear Experiencia'.");
                        this.#toggleBugExperience(button);
                        return;
                    }

                    // Rapidly change avatar position
                    const randomX = Math.random() * 100;
                    const randomY = Math.random() * 100;
                    bot.emit("moveavatar", randomX, randomY);

                    // Spam random gestures
                    const randomGesture = Math.floor(Math.random() * 32); // Assuming 0-31 are valid gestures
                    bot.emit("sendgesture", randomGesture);

                    count++;
                    if (count >= 9000) { // Limit for a period to prevent infinite loop
                        this.notify("info", "'Bugear Experiencia' completado (200 acciones). Deteniendo.");
                        this.#toggleBugExperience(button);
                    }
                }, 100); // Every 100ms
            }
        }

        /**
         * Toggles sending rapid avatar movements and gestures to disrupt other players' experience.
         * @param {HTMLElement} button - The button element to toggle its text/class.
         */
        #togglePlayerChaos(button) { // Renamed function
            if (this.#playerChaosInterval) {
                clearInterval(this.#playerChaosInterval);
                this.#playerChaosInterval = null;
                button.classList.remove("active");
                button.textContent = 'Caos de Jugador';
                this.notify("info", "Deteniendo 'Caos de Jugador'.");
            } else {
                const bot = this.#getBot();
                if (!bot) return;

                button.classList.add("active");
                button.textContent = 'Detener Caos';
                this.notify("info", "Iniciando 'Caos de Jugador' (Agresivo): El bot enviará ráfagas de movimientos, gestos, AFK y cambios de estado. Esto puede ser muy molesto para otros.");

                let count = 0;
                this.#playerChaosInterval = setInterval(() => {
                    if (!bot.getReadyState()) {
                        this.notify("warning", "Bot desconectado, deteniendo 'Caos de Jugador'.");
                        this.#togglePlayerChaos(button);
                        return;
                    }

                    // Rapidly change avatar position
                    const randomX = Math.random() * 100;
                    const randomY = Math.random() * 100;
                    bot.emit("moveavatar", randomX, randomY);

                    // Spam random gestures
                    const randomGesture = Math.floor(Math.random() * 32); // Assuming 0-31 are valid gestures
                    bot.emit("sendgesture", randomGesture);

                    // Toggle AFK status repeatedly
                    bot.emit("playerafk"); // This toggles the AFK state

                    // Toggle a random status flag
                    const randomFlagId = Math.floor(Math.random() * 5); // Assuming 0-4 are valid flags
                    const randomFlagState = Math.random() < 0.5;
                    bot.emit("setstatusflag", randomFlagId, randomFlagState);

                    count++;
                    if (count >= 750) { // Increased actions for longer/more intense effect
                        this.notify("info", "'Caos de Jugador' completado (750 acciones). Deteniendo.");
                        this.#togglePlayerChaos(button);
                    }
                }, 100); // Slightly faster execution (100ms)
            }
        }

   /**
         * Toggles aggressive visual disruptions including avatar spawning, properties, and UI spam.
         * @param {HTMLElement} button - The button element to toggle its text/class.
         */
        #toggleVisualGlitch(button) { // NEW Function
            if (this.#visualGlitchInterval) {
                clearInterval(this.#visualGlitchInterval);
                this.#visualGlitchInterval = null;
                button.classList.remove("active");
                button.textContent = 'Glitch Visual';
                this.notify("info", "Deteniendo 'Glitch Visual'.");
            } else {
                const bot = this.#getBot();
                if (!bot) return;

                button.classList.add("active");
                button.textContent = 'Detener Glitch';
                this.notify("info", "Iniciando 'Glitch Visual' (Extremo): El bot forzará cambios de avatar, spam de chat y interrupciones de UI. Puede causar freezes.");

                let count = 0;
                this.#visualGlitchInterval = setInterval(() => {
                    if (!bot.getReadyState()) {
                        this.notify("warning", "Bot desconectado, deteniendo 'Glitch Visual'.");
                        this.#toggleVisualGlitch(button);
                        return;
                    }

                    // Toggle avatar spawn/despawn aggressively
                    bot.emit("spawnavatar"); // Toggles spawn/despawn state
                    bot.emit("setavatarprop"); // Rapidly changes avatar properties (e.g., rounded)

                    // Spam random chat messages (very disruptive)
                    const chatMessages = [
                        "!! GLITCH DETECTED !!", "ERROR CODE 404: REALITY NOT FOUND", "SYSTEM OVERLOAD",
                        "// VISUAL ANOMALY //", "PACKET CORRUPTION", "DISCONNECTING...", "RECALIBRATING... X_X",
                        "SCREEN_SHAKE_ACTIVE", "DATA STREAM INTERRUPTED", "SERVER REBOOTING (FAKE)"
                    ];
                    const randomChatMessage = chatMessages[Math.floor(Math.random() * chatMessages.length)];
                    bot.emit("chatmsg", randomChatMessage);

                    // Spam vote kicks on random players (causes pop-ups, non-destructive kick)
                    const playersInRoom = bot.room.players || [];
                    const otherPlayers = playersInRoom.filter(p => p.id !== bot.id && p.id !== 0); // Exclude self and system/non-player ID 0
                    if (otherPlayers.length > 0) {
                        const randomPlayer = otherPlayers[Math.floor(Math.random() * otherPlayers.length)];
                        bot.emit("sendvotekick", randomPlayer.id);
                        this.notify("log", `Glitch: Votekick spam a ${randomPlayer.name}`);
                    }

                    // Spam general sendvote (interferes with any active voting UIs)
                    bot.emit("sendvote");

                    // Spam settoken (causes token animations) to random players
                    if (otherPlayers.length > 0) {
                        const randomPlayerForToken = otherPlayers[Math.floor(Math.random() * otherPlayers.length)];
                        const randomTokenId = Math.floor(Math.random() * 9); // Assuming 0-8 are valid token IDs
                        bot.emit("settoken", randomPlayerForToken.id, randomTokenId);
                        this.notify("log", `Glitch: Token spam a ${randomPlayerForToken.name}`);
                    }


                    count++;
                    if (count >= 1000) { // Very long/intense duration
                        this.notify("info", "'Glitch Visual' completado (1000 acciones). Deteniendo.");
                        this.#toggleVisualGlitch(button);
                    }
                }, 200); // Slightly faster execution (100ms)
            }
        }


        /**
         * Toggles sending a massive amount of random-colored drawing commands to slow down the room.
         * @param {HTMLElement} button - The button element to toggle its text/class.
         */
        #toggleSecretSpam(button) {
            if (this.#secretSpamInterval) {
                clearInterval(this.#secretSpamInterval);
                this.#secretSpamInterval = null;
                button.classList.remove("active");
                button.textContent = 'Secret (Spam Visua)';
                this.notify("info", "Spam Visual 'Secret' Detenido.");
            } else {
                const bot = this.#getBot();
                if (!bot) return;

                button.classList.add("active");
                button.textContent = 'Detener Secret';
                this.notify("info", "Spam Visual 'Secret' Iniciado (inundando la sala con dibujos).");

                let counter = 0;
                this.#secretSpamInterval = setInterval(() => {
                    if (!bot.getReadyState()) {
                        this.notify("warning", "Bot desconectado, deteniendo Spam Visual 'Secret'.");
                        this.#toggleSecretSpam(button);
                        return;
                    }

                    // Send many small, random-colored lines quickly
                    for (let i = 0; i < 10; i++) { // Send 10 lines per interval tick for high intensity
                        const x1 = Math.random() * 100;
                        const y1 = Math.random() * 100;
                        const x2 = x1 + (Math.random() * 2 - 1) * 5; // Small displacement
                        const y2 = y1 + (Math.random() * 2 - 1) * 5;
                        const size = Math.floor(Math.random() * 3) + 1; // Very small size
                        const color = `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`; // Random color

                        bot.emit("line", -1, x1, y1, x2, y2, true, size, color, false);
                    }

                    counter += 10;
                    if (counter % 1000 === 0) {
                        this.notify("log", `Secret: ${counter} comandos enviados.`);
                    }
                }, 100); // Slightly faster execution (100ms)
            }
        }
    }
})("QBit");

// --- END UPDATED CUBIC ENGINE FUNCTIONALITIES ---

(function GameLogModule() {
const QBit = globalThis[arguments[0]]; // Corrected access to QBit
class GameLog extends QBit {
    static dummy1 = QBit.register(this);
    static dummy2 = QBit.bind(this, "CubeEngine");

    #gameLog = []; // Stores log entries
    #logDisplayElement;
    #isLoggingActive = true; // Default to active logging

    constructor() {
        super("Registro del Juego", '<i class="fas fa-clipboard-list"></i>');
        this.#onStartup();
    }

    #onStartup() {
        this.#loadInterface();
        this.#setupLogHooks();
        this.notify("info", "Registro de Juego iniciado.");
    }

    #loadInterface() {
        const container = domMake.Tree("div");

        // Toggle Logging Button
        const toggleRow = domMake.Row();
        const toggleButton = domMake.Button("Desactivar Registro");
        toggleButton.addEventListener("click", () => this.#toggleLogging(toggleButton));
        toggleRow.appendChild(toggleButton);
        container.appendChild(toggleRow);

        // Log Display Area
        const displayRow = domMake.Row();
        this.#logDisplayElement = domMake.Tree("div", {
            style: `
                max-height: 250px;
                overflow-y: auto;
                border: 1px solid var(--CE-color);
                padding: 5px;
                font-size: 0.75em;
                background-color: var(--CE-bg_color);
                color: var(--CE-color);
                margin-top: 5px;
            `
        }, ["Registro de eventos vacío."]);
        displayRow.appendChild(this.#logDisplayElement);
        container.appendChild(displayRow);

        // Control Buttons
        const controlRow = domMake.Row();
        const clearButton = domMake.Button("Limpiar Log");
        clearButton.addEventListener("click", () => this.#clearLog());
        controlRow.appendChild(clearButton);

        const exportTxtButton = domMake.Button("Exportar TXT");
        exportTxtButton.addEventListener("click", () => this.#exportLog('txt'));
        controlRow.appendChild(exportTxtButton);

        const exportJsonButton = domMake.Button("Exportar JSON");
        exportJsonButton.addEventListener("click", () => this.#exportLog('json'));
        controlRow.appendChild(exportJsonButton);
        container.appendChild(controlRow);

        this.htmlElements.section.appendChild(container);
    }

    #setupLogHooks() {
        // Hook into incoming WebSocket events (using _io.events where possible)
        if (globalThis._io && globalThis._io.events) {
            // Example of hooking:
            const eventsToLog = [
                "bc_chatmessage", "uc_turn_begindraw", "uc_turn_selectword",
                "bc_round_results", "bc_turn_results", "bc_votekick",
                "bc_clientnotify", "bc_announcement", "bc_extannouncement",
                "mc_roomplayerschange" // To see player list changes
            ];

            eventsToLog.forEach(eventName => {
                const originalEventCallback = globalThis._io.events[eventName];
                globalThis._io.events[eventName] = (...args) => {
                    this.#logEvent(eventName, args);
                    if (originalEventCallback) {
                        originalEventCallback.apply(this, args);
                    }
                };
            });
        }

        // Also observe the actual chatbox for messages to ensure all chat is captured,
        // as some might not pass through _io.events in a way we can easily intercept.
        const chatboxMessages = document.getElementById("chatbox_messages");
        if (chatboxMessages) {
            const chatObserver = new MutationObserver((mutations) => {
                if (!this.#isLoggingActive) return;
                mutations.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1 && node.classList.contains('chatmessage')) {
                            this.#logChatMessage(node);
                        }
                    });
                });
            });
            chatObserver.observe(chatboxMessages, { childList: true });
        }
    }

    #logEvent(type, data) {
        if (!this.#isLoggingActive) return;
        const timestamp = new Date().toISOString();
        this.#gameLog.push({ timestamp, type, data: JSON.parse(JSON.stringify(data)) }); // Deep copy data
        this.#updateLogDisplay();
    }

    #logChatMessage(messageNode) {
        if (!this.#isLoggingActive) return;
        const timestamp = messageNode.dataset.ts ? new Date(parseInt(messageNode.dataset.ts)).toISOString() : new Date().toISOString();
        let entry = { timestamp, type: "chatmsg" };

        if (messageNode.classList.contains('systemchatmessage') || messageNode.classList.contains('systemchatmessage5')) {
            entry.subtype = "system";
            entry.content = messageNode.textContent.trim();
        } else {
            entry.subtype = "player";
            entry.playerName = messageNode.querySelector('.playerchatmessage-name')?.textContent?.trim() || 'Unknown';
            entry.playerId = messageNode.querySelector('.playerchatmessage-name')?.parentElement?.dataset?.playerid || 'N/A';
            entry.content = messageNode.querySelector('.playerchatmessage-text')?.textContent?.trim() || '';
            entry.isSelf = messageNode.classList.contains('playerchatmessage-selfname');
        }
        this.#gameLog.push(entry);
        this.#updateLogDisplay();
    }

    #updateLogDisplay() {
        // Display only the last N messages to avoid performance issues
        const maxDisplayEntries = 50;
        const entriesToDisplay = this.#gameLog.slice(-maxDisplayEntries);

        this.#logDisplayElement.innerHTML = ''; // Clear previous content
        entriesToDisplay.forEach(entry => {
            const logLine = domMake.Tree("div", {
                style: `
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    color: ${entry.type.includes('error') ? 'var(--danger)' : entry.type.includes('warning') ? 'var(--warning)' : entry.type.includes('system') ? 'var(--info)' : 'var(--CE-color)'};
                `,
                title: JSON.stringify(entry) // Show full details on hover
            });
            let displayTxt = `[${new Date(entry.timestamp).toLocaleTimeString()}] `;
            if (entry.type === "chatmsg") {
                if (entry.subtype === "system") {
                    displayTxt += `[SISTEMA] ${entry.content}`;
                } else {
                    displayTxt += `[CHAT] ${entry.playerName} (${entry.playerId}): ${entry.content}`;
                }
            } else if (entry.type === "uc_turn_begindraw" && entry.data && entry.data) {
                displayTxt += `[TURNO] Comienza dibujo. Palabra: ${entry.data[1] || 'Desconocida'}`;
            } else if (entry.type === "uc_turn_selectword" && entry.data && entry.data) {
                displayTxt += `[TURNO] Seleccionar palabra: [${entry.data[2]?.join(', ') || 'N/A'}]`;
            } else if (entry.type === "bc_round_results") {
                displayTxt += `[RONDA] Resultados de ronda.`; // Too much data to display directly
            } else if (entry.type === "bc_turn_results") {
                displayTxt += `[TURNO] Resultados de turno.`;
            } else {
                displayTxt += `[${entry.type}] ${JSON.stringify(entry.data).substring(0, 50)}...`;
            }
            logLine.textContent = displayTxt;
            this.#logDisplayElement.appendChild(logLine);
        });
        // Scroll to bottom
        this.#logDisplayElement.scrollTop = this.#logDisplayElement.scrollHeight;
    }

    #toggleLogging(button) {
        this.#isLoggingActive = !this.#isLoggingActive;
        button.classList.toggle("active", !this.#isLoggingActive);
        button.textContent = this.#isLoggingActive ? "Desactivar Registro" : "Activar Registro";
        this.notify("info", `Registro de Juego: ${this.#isLoggingActive ? 'Activo' : 'Inactivo'}`);
    }

    #clearLog() {
        if (confirm("¿Estás seguro de que quieres limpiar todo el registro del juego?")) {
            this.#gameLog = [];
            this.#updateLogDisplay();
            this.notify("info", "Registro de Juego limpiado.");
        }
    }

    #exportLog(format) {
        if (this.#gameLog.length === 0) {
            this.notify("warning", "No hay datos en el registro para exportar.");
            return;
        }

        let dataString;
        let mimeType;
        let filename = `drawaria_game_log_${new Date().toISOString().slice(0, 10)}`;

        if (format === 'json') {
            dataString = JSON.stringify(this.#gameLog, null, 2);
            mimeType = 'application/json';
            filename += '.json';
        } else { // Default to TXT
            dataString = this.#gameLog.map(entry => {
                const time = new Date(entry.timestamp).toLocaleTimeString();
                if (entry.type === "chatmsg") {
                    if (entry.subtype === "system") {
                        return `[${time}] [SISTEMA] ${entry.content}`;
                    } else {
                        return `[${time}] [CHAT] ${entry.playerName} (${entry.playerId}): ${entry.content}`;
                    }
                } else if (entry.type === "uc_turn_begindraw" && entry.data && entry.data) {
                    return `[${time}] [TURNO_INICIO] Palabra: ${entry.data[1] || 'Desconocida'}`;
                } else if (entry.type === "uc_turn_selectword" && entry.data && entry.data) {
                    return `[${time}] [TURNO_PALABRA] Opciones: [${entry.data[2]?.join(', ') || 'N/A'}]`;
                } else if (entry.type === "bc_round_results") {
                    return `[${time}] [RONDA_FIN] Resultados: ${JSON.stringify(entry.data[0].map(p => ({name: p[1], score: p[2]})))}`;
                }
                return `[${time}] [${entry.type}] ${JSON.stringify(entry.data)}`;
            }).join('\n');
            mimeType = 'text/plain';
            filename += '.txt';
        }

        const blob = new Blob([dataString], { type: mimeType });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
        this.notify("success", `Log exportado como ${filename}.`);
    }
}
})("QBit");


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

    // Define token names for better readability. These are from Drawaria's common.js.
    const TOKEN_NAMES = {
        0: "Thumbs Up",
        1: "Heart",
        2: "Paint Brush",
        3: "Cocktail",
        4: "Peace Sign",
        5: "Feather",
        6: "Trophy",
        7: "Mug",
        8: "Gift"
    };

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

        #profileUrlInput;
        #extractedDataDisplay;
        #downloadButton;
        #lastExtractedData = null; // Store data for download

        constructor() {
            super("Extractor de Perfil (Pegar URL de perfil)", '<i class="fas fa-id-card"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.notify("info", "Módulo Extractor de Perfil cargado.");
        }

        #loadInterface() {
            const container = domMake.Tree("div");

            // URL Input Row
            const urlRow = domMake.Row();
            this.#profileUrlInput = domMake.Tree("input", {
                type: "text",
                placeholder: "https://drawaria.online/profile/?uid=...)",
                style: "width: 100%; padding: 5px; box-sizing: border-box;"
            });
            urlRow.appendChild(this.#profileUrlInput);
            container.appendChild(urlRow);

            // Search Button Row
            const searchRow = domMake.Row();
            const searchButton = domMake.Button('<i class="fas fa-search"></i> Buscar Perfil');
            searchButton.addEventListener("click", () => this.#fetchAndExtractProfile());
            searchRow.appendChild(searchButton);
            container.appendChild(searchRow);

            // Extracted Data Display Area
            const displayRow = domMake.Row();
            this.#extractedDataDisplay = domMake.Tree("div", {
                style: `
                    max-height: 400px;
                    overflow-y: auto;
                    border: 1px solid var(--CE-color);
                    padding: 8px;
                    font-size: 0.85em;
                    background-color: var(--CE-bg_color);
                    color: var(--CE-color);
                    margin-top: 5px;
                    white-space: pre-wrap; /* Preserve whitespace and wrap lines */
                    font-family: monospace; /* For better readability of structured data */
                `
            }, ["Datos del perfil aparecerán aquí."]);
            displayRow.appendChild(this.#extractedDataDisplay);
            container.appendChild(displayRow);

            // Download Button Row
            const downloadRow = domMake.Row();
            this.#downloadButton = domMake.Button('<i class="fas fa-download"></i> Descargar Datos (JSON)');
            this.#downloadButton.disabled = true; // Disabled until data is extracted
            this.#downloadButton.addEventListener("click", () => this.#downloadExtractedData());
            downloadRow.appendChild(this.#downloadButton);
            container.appendChild(downloadRow);

            this.htmlElements.section.appendChild(container);
        }

        /**
         * Fetches the profile page HTML and extracts data.
         */
        async #fetchAndExtractProfile() {
            const profileUrl = this.#profileUrlInput.value.trim();
            if (!profileUrl) {
                this.notify("warning", "Por favor, introduce una URL de perfil.");
                return;
            }

            // Basic URL validation
            const uidMatch = profileUrl.match(/uid=([a-f0-9-]+)/i);
            if (!uidMatch || !uidMatch[1]) {
                this.notify("error", "URL inválida. No se pudo extraer el UID. Asegúrate de que es una URL de perfil de Drawaria (ej. https://drawaria.online/profile/?uid=...).");
                return;
            }
            const uid = uidMatch[1];


            this.notify("info", `Extrayendo datos de: ${profileUrl}...`);
            this.#extractedDataDisplay.textContent = "Cargando...";
            this.#downloadButton.disabled = true;

            // Declare DOMParser once here so it's accessible to all inner parsing blocks
            const parser = new DOMParser();

            try {
                // --- 1. Fetch Main Profile Page ---
                const profileResponse = await fetch(profileUrl);
                if (!profileResponse.ok) {
                    throw new Error(`Error HTTP (${profileUrl}): ${profileResponse.status} ${profileResponse.statusText}`);
                }
                const profileHtmlContent = await profileResponse.text();
                // Pass the parser instance to the parsing function
                const extracted = this.#parseMainProfileHTML(profileHtmlContent, parser);
                extracted.uid = uid; // Ensure UID is set

                // --- 2. Fetch Gallery Count (from HTML page) ---
                const galleryPageUrl = `https://drawaria.online/gallery/?uid=${uid}`;
                try {
                    const galleryResponse = await fetch(galleryPageUrl);
                    if (galleryResponse.ok) {
                        const galleryHtmlContent = await galleryResponse.text();
                        // Use the shared parser instance
                        const galleryDoc = parser.parseFromString(galleryHtmlContent, 'text/html');
                        // Count all .grid-item elements within the .grid container
                        extracted.galleryImagesCount = galleryDoc.querySelectorAll('.grid .grid-item.galleryimage').length;
                    } else {
                        extracted.galleryImagesCount = `Error (${galleryResponse.status})`;
                        this.notify("warning", `Fallo al cargar la página de galería: ${galleryResponse.status}`);
                    }
                } catch (e) {
                    extracted.galleryImagesCount = `Error al parsear galería (${e.message.substring(0, 50)})`;
                    this.notify("warning", `Fallo al consultar página de galería: ${e.message}`);
                }

                // --- 3. Fetch Friends Count (from HTML page) ---
                const friendsPageUrl = `https://drawaria.online/friends/?uid=${uid}`;
                try {
                    const friendsResponse = await fetch(friendsPageUrl);
                    if (friendsResponse.ok) {
                        const friendsHtmlContent = await friendsResponse.text();
                        // Use the shared parser instance
                        const friendsDoc = parser.parseFromString(friendsHtmlContent, 'text/html');
                        extracted.friendsCount = friendsDoc.querySelectorAll('#friendscontainer .friendcard').length || 0;
                    } else {
                        extracted.friendsCount = `Error (${friendsResponse.status})`;
                        this.notify("warning", `Fallo al cargar la página de amigos: ${friendsResponse.status}`);
                    }
                } catch (e) {
                    extracted.friendsCount = `Error al parsear amigos (${e.message.substring(0, 50)})`;
                    this.notify("warning", `Fallo al consultar página de amigos: ${e.message}`);
                }

                // --- 4. Fetch Palettes Count (from HTML page) ---
                const palettesPageUrl = `https://drawaria.online/palettes/?uid=${uid}`;
                try {
                    const palettesResponse = await fetch(palettesPageUrl);
                    if (palettesResponse.ok) {
                        const palettesHtmlContent = await palettesResponse.text();
                        // Use the shared parser instance
                        const palettesDoc = parser.parseFromString(palettesHtmlContent, 'text/html');
                        extracted.palettesCount = palettesDoc.querySelectorAll('.palettelist .rowitem').length || 0;
                    } else {
                        extracted.palettesCount = `Error (${palettesResponse.status})`;
                        this.notify("warning", `Fallo al cargar la página de paletas: ${palettesResponse.status}`);
                    }
                } catch (e) {
                    extracted.palettesCount = `Error al parsear paletas (${e.message.substring(0, 50)})`;
                    this.notify("warning", `Fallo al consultar página de paletas: ${e.message}`);
                }


                // Final check: if primary player name was not found, notify as invalid profile
                // We re-parse here just for this specific final check, using the same parser instance.
                const doc = parser.parseFromString(profileHtmlContent, 'text/html');
                if (extracted.playerName === 'N/A' && !doc.querySelector('h1')) {
                     this.#extractedDataDisplay.textContent = "No se pudo encontrar el perfil o extraer datos. Asegúrate de que la URL es correcta y el perfil existe.";
                     this.#lastExtractedData = null;
                     this.#downloadButton.disabled = true;
                     this.notify("error", "Perfil no encontrado o datos no extraíbles.");
                     return;
                 }


                // Display extracted data
                this.#lastExtractedData = extracted;
                this.#displayExtractedData();
                this.#downloadButton.disabled = false;
                this.notify("success", "Datos del perfil extraídos exitosamente.");

            } catch (error) {
                this.notify("error", `Fallo general al cargar o procesar el perfil: ${error.message}`);
                this.#extractedDataDisplay.textContent = `Error: ${error.message}`;
                this.#lastExtractedData = null;
            }
        }

        /**
         * Parses the HTML content of the main profile page and extracts relevant information.
         * @param {string} htmlContent - The HTML content of the profile page.
         * @param {DOMParser} parser - The shared DOMParser instance.
         * @returns {object} Extracted data.
         */
        #parseMainProfileHTML(htmlContent, parser) { // Accept parser instance
            const doc = parser.parseFromString(htmlContent, 'text/html');
            const extracted = {};

            // --- Player Info (from profile page) ---
            const playerInfoAnchor = doc.querySelector('h1 a[href*="profile/?uid="]');
            if (playerInfoAnchor) {
                extracted.avatarUrl = playerInfoAnchor.querySelector('img.turnresults-avatar')?.src || 'N/A';
                // Player name is the text content of the anchor AFTER the image
                const playerNameNode = Array.from(playerInfoAnchor.childNodes).find(node => node.nodeType === Node.TEXT_NODE && node.textContent.trim().length > 0);
                extracted.playerName = playerNameNode?.textContent.trim() || 'N/A';
            } else {
                extracted.playerName = doc.querySelector('h1')?.textContent.trim() || 'N/A'; // Fallback to just H1 text if no anchor
                extracted.avatarUrl = 'N/A';
            }

            // --- Level & Experience (from profile page) ---
            extracted.level = doc.getElementById('levelval')?.textContent.trim() || 'N/A'; // Kept for JSON export, not displayed in text output
            extracted.experience = doc.getElementById('exp-val')?.textContent.trim() || 'N/A';

            // --- Pictionary / Guessing Stats (from profile page) ---
            extracted.pictionaryStats = {};
            const playStatsTableBody = doc.querySelector('#playstats table tbody');
            if (playStatsTableBody) {
                playStatsTableBody.querySelectorAll('tr').forEach(row => {
                    const label = row.querySelector('td:first-child')?.textContent.trim();
                    const value = row.querySelector('td:last-child')?.textContent.trim();
                    if (label && value) {
                        const cleanLabel = label.replace(/[:\s]/g, '').toLowerCase(); // "Total score:" -> "totalscore"
                        extracted.pictionaryStats[cleanLabel] = value;
                    }
                });
            }

            // --- Playground Accolades (Tokens) (from profile page) ---
            extracted.accusedTokens = {};
            const tokensTableBody = doc.querySelector('#tokens table tbody');
            if (tokensTableBody) {
                tokensTableBody.querySelectorAll('i[data-tokenid]').forEach(iconElement => {
                    const tokenId = parseInt(iconElement.dataset.tokenid);
                    const tokenName = TOKEN_NAMES[tokenId] || `Unknown Token ${tokenId}`;
                    const count = parseInt(iconElement.textContent.trim()) || 0; // Text content holds the number
                    extracted.accusedTokens[tokenName] = count;
                });
            }

            return extracted;
        }

        /**
         * Formats and displays the extracted data in the UI.
         */
        #displayExtractedData() {
            if (!this.#lastExtractedData) {
                this.#extractedDataDisplay.textContent = "No hay datos para mostrar.";
                return;
            }

            let displayTxt = `--- Datos del Perfil ---\n`;
            displayTxt += `  UID: ${this.#lastExtractedData.uid}\n`;
            displayTxt += `  Nombre del Jugador: ${this.#lastExtractedData.playerName}\n`;
            // Level is removed from text display, but still in #lastExtractedData for JSON export
            displayTxt += `  Experiencia: ${this.#lastExtractedData.experience}\n`;
            displayTxt += `  URL del Avatar: ${this.#lastExtractedData.avatarUrl}\n`;
            // GalleryImagesCount is removed from text display, but still in #lastExtractedData for JSON export
            displayTxt += `  Cantidad de Amigos: ${this.#lastExtractedData.friendsCount}\n`;
            displayTxt += `  Cantidad de Paletas: ${this.#lastExtractedData.palettesCount}\n\n`;

            displayTxt += `--- Estadísticas de Pictionary / Adivinanza ---\n`;
            if (Object.keys(this.#lastExtractedData.pictionaryStats).length > 0) {
                for (const key in this.#lastExtractedData.pictionaryStats) {
                    const displayKey = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
                    displayTxt += `  ${displayKey}: ${this.#lastExtractedData.pictionaryStats[key]}\n`;
                }
            } else {
                displayTxt += `  No se encontraron estadísticas detalladas de Pictionary.\n`;
            }
            displayTxt += `\n`;

            displayTxt += `--- Menciones de Homenaje (Tokens) ---\n`;
            if (Object.keys(this.#lastExtractedData.accusedTokens).length > 0) {
                for (const tokenName in this.#lastExtractedData.accusedTokens) {
                    displayTxt += `  ${tokenName}: ${this.#lastExtractedData.accusedTokens[tokenName]}\n`;
                }
            } else {
                displayTxt += `  No se encontraron Menciones de Homenaje.\n`;
            }

            this.#extractedDataDisplay.textContent = displayTxt;
        }

        /**
         * Downloads the extracted data as a JSON file.
         */
        #downloadExtractedData() {
            if (!this.#lastExtractedData) {
                this.notify("warning", "No hay datos extraídos para descargar.");
                return;
            }

            const dataStr = JSON.stringify(this.#lastExtractedData, null, 2);
            const blob = new Blob([dataStr], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const playerNameForFilename = this.#lastExtractedData.playerName.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 30); // Clean for filename
            const filename = `drawaria_profile_${playerNameForFilename}_${this.#lastExtractedData.uid ? this.#lastExtractedData.uid.substring(0, 8) : 'data'}.json`;

            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            this.notify("success", `Datos del perfil descargados como ${filename}.`);
        }
    }
})("QBit");

// NEW UPTADES


(function RoomNavigatorModule() {
    const QBit = globalThis[arguments[0]]; // Corrected access to QBit
// Helper to fetch JSON (re-declaring if not globally accessible or just for clarity)
function fetchJson(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.onload = () => {
            if (xhr.status >= 200 && xhr.status < 300) {
                try {
                    let parsedData = JSON.parse(xhr.responseText);
                    // Handle potential double-encoded JSON
                    if (typeof parsedData === 'string') {
                        parsedData = JSON.parse(parsedData);
                    }
                    resolve(parsedData);
                } catch (e) {
                    reject(new Error('Fallo al analizar la respuesta JSON: ' + e.message + ` (Raw: ${xhr.responseText.substring(0, 100)}...)`));
                }
            } else {
                reject(new Error(`La respuesta de la red no fue correcta, estado: ${xhr.status} ${xhr.statusText}`));
            }
        };
        xhr.onerror = () => reject(new Error('Fallo la solicitud de red. Revisa tu conexión o el servidor.'));
        xhr.send();
    });
}

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

    #roomListContainer;
    #refreshButton;
    #loadingIndicator;
    #filterNameInput;
    #filterMinPlayersInput;
    #filterMaxPlayersInput;
    #roomDataCache = []; // Store fetched raw room data

    constructor() {
        super("Navegador de Salas", '<i class="fas fa-search-location"></i>');
        this.#onStartup();
    }

    #onStartup() {
        this.#loadInterface();
        this.#fetchAndApplyFilters(); // Initial fetch and display
    }

    #loadInterface() {
        const container = domMake.Tree("div");

        // Refresh and Loading Row
        const headerRow = domMake.Row();
        headerRow.style.marginBottom = "10px";

        this.#refreshButton = domMake.Button('<i class="fas fa-sync-alt"></i> Actualizar Salas');
        this.#refreshButton.title = "Actualiza la lista de salas disponibles.";
        this.#refreshButton.addEventListener("click", () => this.#fetchAndApplyFilters());
        headerRow.appendChild(this.#refreshButton);

        this.#loadingIndicator = domMake.Tree("span", { style: "margin-left: 10px; color: var(--info); display: none;" }, ['Cargando...']);
        headerRow.appendChild(this.#loadingIndicator);
        container.appendChild(headerRow);

        // Filters Row
        const filtersRow = domMake.Row();
        filtersRow.style.flexWrap = "wrap";
        filtersRow.style.gap = "5px";

        this.#filterNameInput = domMake.Tree("input", { type: "text", placeholder: "Filtrar por nombre", style: "flex: 1 1 120px;" });
        this.#filterNameInput.addEventListener("input", () => this.#applyFiltersAndDisplayRooms());
        filtersRow.appendChild(this.#filterNameInput);

        this.#filterMinPlayersInput = domMake.Tree("input", { type: "number", min: "0", placeholder: "Min Jugadores", style: "width: 80px;" });
        this.#filterMinPlayersInput.addEventListener("input", () => this.#applyFiltersAndDisplayRooms());
        filtersRow.appendChild(this.#filterMinPlayersInput);

        this.#filterMaxPlayersInput = domMake.Tree("input", { type: "number", min: "0", placeholder: "Max Jugadores", style: "width: 80px;" });
        this.#filterMaxPlayersInput.addEventListener("input", () => this.#applyFiltersAndDisplayRooms());
        filtersRow.appendChild(this.#filterMaxPlayersInput);

        container.appendChild(filtersRow);

        // Room List Display Area
        this.#roomListContainer = domMake.Tree("div", {
            class: "room-list-display",
            style: `
                display: grid;
                grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
                gap: 10px;
                padding: 5px;
                max-height: 400px; /* Limits height and adds scrollbar */
                overflow-y: auto;
                border: 1px solid var(--CE-color);
                border-radius: .25rem;
                margin-top: 10px;
            `
        });
        container.appendChild(this.#roomListContainer);

        this.htmlElements.section.appendChild(container);
    }

    async #fetchAndApplyFilters() {
        this.#roomListContainer.innerHTML = '';
        this.#loadingIndicator.style.display = 'inline';
        this.#refreshButton.disabled = true;

        try {
            const roomData = await fetchJson('https://drawaria.online/getroomlist');
            if (!Array.isArray(roomData)) {
                 throw new Error('La respuesta no es un array de salas válido.');
            }
            this.#roomDataCache = roomData; // Cache the raw data
            this.notify("info", `Se encontraron ${roomData.length} salas.`);
            this.#applyFiltersAndDisplayRooms();
        } catch (error) {
            this.notify("error", `Error al cargar la lista de salas: ${error.message}`);
            this.#roomListContainer.appendChild(domMake.TextNode("Error al cargar las salas. Inténtalo de nuevo."));
            console.error("Fetch room list error:", error);
        } finally {
            this.#loadingIndicator.style.display = 'none';
            this.#refreshButton.disabled = false;
        }
    }

    #applyFiltersAndDisplayRooms() {
        let filteredRooms = [...this.#roomDataCache]; // Start with cached data

        const nameFilter = this.#filterNameInput.value.toLowerCase();
        const minPlayers = parseInt(this.#filterMinPlayersInput.value);
        const maxPlayers = parseInt(this.#filterMaxPlayersInput.value);

        if (nameFilter) {
            filteredRooms = filteredRooms.filter(room => {
                const roomName = room[3] ? room[3].toLowerCase() : ''; // Access roomName by index 3
                return roomName.includes(nameFilter);
            });
        }

        if (!isNaN(minPlayers) && minPlayers >= 0) {
            filteredRooms = filteredRooms.filter(room => room[1] >= minPlayers); // Access currentPlayers by index 1
        }

        if (!isNaN(maxPlayers) && maxPlayers >= 0) {
            filteredRooms = filteredRooms.filter(room => room[1] <= maxPlayers); // Access currentPlayers by index 1
        }

        this.#displayRooms(filteredRooms);
    }


    #displayRooms(rooms) {
        this.#roomListContainer.innerHTML = '';
        if (rooms.length === 0) {
            this.#roomListContainer.appendChild(domMake.TextNode("No hay salas que coincidan con los filtros."));
            return;
        }

        rooms.forEach(roomArray => {
            // Structure observed from the provided JSON example:
            // [0] roomId: string (e.g., "f0e1c44b-fc49-4160-91c9-b297fb662692" or "f49bf487-e96a-45a9-9616-c4b71662ac50.3")
            // [1] currentPlayers: number
            // [2] maxPlayers: number
            // [3] roomName: string (e.g., "жду друзей", "sos :)", or "")
            // [4] gameModeType: number (2 for public, 3 for private/friend/custom)
            // [5] unknown_number: number (e.g., 273052, 4176 - seems like a server-side counter or ID)
            // [6] flags_array: Array (e.g., [null,true,null,null,null,true] or [null,true])
            //      - flags_array[0]: boolean (possibly password protected if true)
            //      - flags_array[1]: boolean (this flag seems always true in sample, not a public/private indicator)
            // [7] roundsPlayed: number
            // [8] serverId: number or null (e.g., 5 or null if main server, part of room ID for specific servers)

            const roomId = roomArray[0];
            const currentPlayers = roomArray[1];
            const maxPlayers = roomArray[2];
            const roomName = roomArray[3];
            const gameModeType = roomArray[4];
            const flags = roomArray[6]; // Flags are at index 6
            const roundsPlayed = roomArray[7];
            const serverId = roomArray[8];

            let roomModeLabel = 'Desconocido';
            if (gameModeType === 2) {
                roomModeLabel = 'Público';
            } else if (gameModeType === 3) {
                roomModeLabel = 'Amigos/Privado';
            }

            // Access flags_array[0] for password protected status
            const isPasswordProtected = flags && flags.length > 0 && flags[0] === true;

            const isFull = currentPlayers >= maxPlayers;
            const statusColor = isFull ? 'var(--danger)' : 'var(--success)';
            const joinableStatus = isFull ? 'LLENA' : 'DISPONIBLE';

            const roomCard = domMake.Tree("div", {
                class: "room-card",
                style: `
                    border: 1px solid var(--CE-color);
                    border-radius: .25rem;
                    padding: 8px;
                    background-color: var(--CE-bg_color);
                    display: flex;
                    flex-direction: column;
                    justify-content: space-between;
                    gap: 5px;
                    font-size: 0.85em;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                `
            });

            const nodesToAppend = [
                domMake.Tree("div", { style: "font-weight: bold; color: var(--dark-blue-title); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;", title: roomName }, [`Sala: ${roomName || '(Sin Nombre)'}`]),
                domMake.Tree("div", {}, [`Jugadores: ${currentPlayers}/${maxPlayers}`]),
                domMake.Tree("div", {}, [`Rondas jugadas: ${roundsPlayed || 'N/A'}`]),
                domMake.Tree("div", {}, [`Modo: ${roomModeLabel}`]),
                isPasswordProtected ? domMake.Tree("div", {style: "color: var(--warning);"}, [`Contraseña: Sí`]) : null,
                domMake.Tree("div", { style: `color: ${statusColor}; font-weight: bold;` }, [`Estado: ${joinableStatus}`])
            ].filter(node => node instanceof Node);

            roomCard.appendAll(...nodesToAppend);

            const joinButton = domMake.Button("Unirse");
            joinButton.classList.add("btn-primary");
            joinButton.style.width = "100%";
            joinButton.style.marginTop = "5px";
            // joinButton.disabled = isFull; // REMOVED: Allow joining even if full
            joinButton.addEventListener("click", () => this.#joinRoom(roomId, serverId));
            roomCard.appendChild(joinButton);

            this.#roomListContainer.appendChild(roomCard);
        });
    }

    #joinRoom(roomId, serverId) {
        let fullRoomIdentifier = roomId;
        // Construct full room ID, e.g., "uuid.serverId"
        if (serverId !== null && serverId !== undefined && !String(roomId).includes(`.${serverId}`)) {
            fullRoomIdentifier = `${roomId}.${serverId}`;
        }
        const roomUrl = `https://drawaria.online/room/${fullRoomIdentifier}`;
        window.location.assign(roomUrl); // Navigate to the room
    }
}

})("QBit");


(function DrawingAssistantModule() {
    const QBit = globalThis[arguments[0]]; // Corrected access to QBit

    // Styles for the overlay canvas and UI elements
    QBit.Styles.addRules([
        `#drawing-assistant-overlay {
            position: absolute;
            top: 0;
            left: 0;
            z-index: 1000; /* Above game canvas, below main UI elements */
            pointer-events: none; /* Crucial to allow clicks to pass through to game canvas */
        }`,
        `#drawing-assistant-grid-toggle.active { background-color: var(--info); color: white; }`,
        `#drawing-assistant-symmetry-toggle.active { background-color: var(--info); color: white; }`,
        `#drawing-assistant-pixel-perfect-toggle.active { background-color: var(--info); color: white; }`,
        `#drawing-assistant-controls input[type="number"],
         #drawing-assistant-controls input[type="color"] {
            width: 100%; padding: 5px; box-sizing: border-box;
            border: 1px solid var(--CE-color); border-radius: .25rem;
            background-color: var(--CE-bg_color); color: var(--CE-color);
         }`,
        `#drawing-assistant-controls ._row > * { margin: 0 2px; }`
    ]);

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

        #overlayCanvas;
        #overlayCtx;
        #gameCanvas; // Reference to the actual game canvas

        #isSymmetryActive = false;
        #isPixelPerfectActive = false;
        #isGridVisible = false;

        #drawingColor = "#000000"; // Default drawing color
        #drawingThickness = 5;    // Default drawing thickness

        // Event listeners (need to manage their lifecycle)
        #mouseMoveListener = null;
        #mouseDownListener = null;
        #mouseUpListener = null;

        constructor() {
            super("Asistente de Dibujo", '<i class="fas fa-drafting-compass"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#findGameCanvas();
            this.#setupOverlayCanvas();
            this.#loadInterface();
            this.#hookGameDrawingEvents();
            this.notify("info", "Asistente de Dibujo cargado. Asegúrate de tener un bot activo para usar las herramientas de dibujo.");
        }

        #findGameCanvas() {
            this.#gameCanvas = document.getElementById('canvas');
            if (!this.#gameCanvas) {
                this.notify("error", "Canvas del juego no encontrado. Algunas funciones de dibujo no estarán disponibles.");
            }
        }

        #setupOverlayCanvas() {
            this.#overlayCanvas = domMake.Tree('canvas', { id: 'drawing-assistant-overlay' });
            if (this.#gameCanvas) {
                this.#overlayCanvas.width = this.#gameCanvas.width;
                this.#overlayCanvas.height = this.#gameCanvas.height;
                this.#overlayCanvas.style.width = this.#gameCanvas.style.width; // Match CSS size
                this.#overlayCanvas.style.height = this.#gameCanvas.style.height;
                this.#gameCanvas.parentNode.insertBefore(this.#overlayCanvas, this.#gameCanvas.nextSibling); // Place right after game canvas
            } else {
                // Fallback dimensions, but core functions won't work well without game canvas
                this.#overlayCanvas.width = 1000;
                this.#overlayCanvas.height = 1000;
                this.#overlayCanvas.style.width = '700px';
                this.#overlayCanvas.style.height = '700px';
                document.body.appendChild(this.#overlayCanvas);
            }
            this.#overlayCtx = this.#overlayCanvas.getContext('2d');
            this.#updateOverlaySizeAndPosition();

            // Handle window resize to keep overlay aligned
            window.addEventListener('resize', this.#updateOverlaySizeAndPosition.bind(this));
        }

        #updateOverlaySizeAndPosition() {
            if (!this.#gameCanvas || !this.#overlayCanvas) return;

            const gameCanvasRect = this.#gameCanvas.getBoundingClientRect();

            this.#overlayCanvas.style.top = `${gameCanvasRect.top}px`;
            this.#overlayCanvas.style.left = `${gameCanvasRect.left}px`;
            this.#overlayCanvas.style.width = `${gameCanvasRect.width}px`;
            this.#overlayCanvas.style.height = `${gameCanvasRect.height}px`;

            // If game canvas dimensions change (e.g. initial load), update actual canvas resolution
            if (this.#overlayCanvas.width !== this.#gameCanvas.width) {
                 this.#overlayCanvas.width = this.#gameCanvas.width;
            }
            if (this.#overlayCanvas.height !== this.#gameCanvas.height) {
                 this.#overlayCanvas.height = this.#gameCanvas.height;
            }

            this.#clearOverlay();
            if (this.#isGridVisible) {
                this.#drawGrid();
            }
            if (this.#isSymmetryActive) {
                this.#drawSymmetryLines();
            }
        }

        #clearOverlay() {
            this.#overlayCtx.clearRect(0, 0, this.#overlayCanvas.width, this.#overlayCanvas.height);
        }

        #loadInterface() {
            const container = domMake.Tree("div", { id: "drawing-assistant-controls" });

            // Drawing parameters (Color, Thickness)
            const paramsRow = domMake.Row();
            paramsRow.style.gap = "5px";

            const colorInput = domMake.Tree("input", { type: "color", value: this.#drawingColor, title: "Color de Dibujo" });
            colorInput.addEventListener("change", (e) => this.#drawingColor = e.target.value);
            paramsRow.appendAll(domMake.Tree("label", {}, ["Color:"]), colorInput);

            const thicknessInput = domMake.Tree("input", { type: "number", min: "1", max: "100", value: this.#drawingThickness, title: "Grosor de Dibujo" });
            thicknessInput.addEventListener("change", (e) => this.#drawingThickness = parseInt(e.target.value));
            paramsRow.appendAll(domMake.Tree("label", {}, ["Grosor:"]), thicknessInput);
            container.appendChild(paramsRow);

            // Geometric Shapes
            const shapesRow = domMake.Row();
            shapesRow.style.gap = "5px";

            const drawLineButton = domMake.Button('<i class="fas fa-grip-lines"></i> Línea');
            drawLineButton.addEventListener("click", () => this.#enableShapeDrawing('line'));
            shapesRow.appendChild(drawLineButton);

            const drawRectButton = domMake.Button('<i class="fas fa-vector-square"></i> Rect.');
            drawRectButton.addEventListener("click", () => this.#enableShapeDrawing('rect'));
            shapesRow.appendChild(drawRectButton);

            const drawCircleButton = domMake.Button('<i class="fas fa-circle"></i> Círculo');
            drawCircleButton.addEventListener("click", () => this.#enableShapeDrawing('circle'));
            shapesRow.appendChild(drawCircleButton);
            container.appendChild(shapesRow);

            // Toggles (Grid, Symmetry, Pixel Perfect)
            const togglesRow = domMake.Row();
            togglesRow.style.gap = "5px";

            const toggleGridButton = domMake.Button('<i class="fas fa-th"></i> Cuadrícula');
            toggleGridButton.id = "drawing-assistant-grid-toggle";
            toggleGridButton.addEventListener("click", () => this.#toggleGrid(toggleGridButton));
            togglesRow.appendChild(toggleGridButton);

            const toggleSymmetryButton = domMake.Button('<i class="fas fa-arrows-alt-h"></i> Simetría');
            toggleSymmetryButton.id = "drawing-assistant-symmetry-toggle";
            toggleSymmetryButton.addEventListener("click", () => this.#toggleSymmetry(toggleSymmetryButton));
            togglesRow.appendChild(toggleSymmetryButton);

            const togglePixelPerfectButton = domMake.Button('<i class="fas fa-compress-arrows-alt"></i> Píxel Perfect');
            togglePixelPerfectButton.id = "drawing-assistant-pixel-perfect-toggle";
            togglePixelPerfectButton.addEventListener("click", () => this.#togglePixelPerfect(togglePixelPerfectButton));
            togglesRow.appendChild(togglePixelPerfectButton);
            container.appendChild(togglesRow);

            // Collaborative Drawing Trigger
            const collabRow = domMake.Row();
            const startCollabDrawButton = domMake.Button('<i class="fas fa-users-cog"></i> Iniciar Dibujo Colaborativo');
            startCollabDrawButton.title = "Activa el módulo Autodraw V2 para que los bots colaboren en el dibujo (requiere imagen cargada en Autodraw V2).";
            startCollabDrawButton.addEventListener("click", () => this.#triggerAutodrawV2Collab());
            collabRow.appendChild(startCollabDrawButton);
            container.appendChild(collabRow);


            this.htmlElements.section.appendChild(container);
        }

        /**
         * Generic helper to get the active bot.
         * @returns {object|null} The active bot instance, or null.
         */
        #getBot() {
            const botManagerClass = this.findGlobal("BotClientManager");
            if (!botManagerClass || !botManagerClass.siblings || botManagerClass.siblings.length === 0) {
                this.notify("warning", "No hay instancias activas de 'BotClientManager'. Por favor, crea uno desde 'CubeEngine'.");
                return null;
            }
            // Access the first (and likely only) instance of BotClientManager
            const botManagerInstance = botManagerClass.siblings[0];

//          if (!botManagerInstance || !botManagerInstance.children || botManagerInstance.children.length === 0) {
//              this.notify("warning", "No hay bots activos en 'BotClientManager'. Por favor, crea y conecta uno.");
//              return null;
//          }

            const botClientInterfaces = botManagerInstance.children;
            let activeBotClientInterface = null;

            const selectedBotInput = document.querySelector('input[name="botClient"]:checked');
            if (selectedBotInput) {
                activeBotClientInterface = botClientInterfaces.find(bci => bci.htmlElements.input === selectedBotInput);
            }
            // Fallback to the first available bot if no specific bot is selected or found
            if (!activeBotClientInterface && botClientInterfaces.length > 0) {
                activeBotClientInterface = botClientInterfaces[0]; // Corrected to get the first instance
                this.notify("info", `No se seleccionó un bot. Usando el primer bot disponible: ${activeBotClientInterface.getName()}.`);
            }

//          if (!activeBotClientInterface || !activeBotClientInterface.bot || !activeBotClientInterface.bot.getReadyState()) {
//              this.notify("warning", `El bot "${activeBotClientInterface ? activeBotClientInterface.getName() : 'desconocido'}" no está conectado y listo para enviar comandos.`);
//              return null;
//          }
            return activeBotClientInterface.bot;
        }

        #hookGameDrawingEvents() {
            if (!this.#gameCanvas) return;

            // Remove existing listeners to prevent duplicates
            this.#gameCanvas.removeEventListener('mousedown', this.#mouseDownListener);
            this.#gameCanvas.removeEventListener('mousemove', this.#mouseMoveListener);
            this.#gameCanvas.removeEventListener('mouseup', this.#mouseUpListener);
            this.#gameCanvas.removeEventListener('mouseout', this.#mouseUpListener);

            let isDrawing = false;
            let lastX = 0, lastY = 0;

            const sendLineCommand = (startX, startY, endX, endY) => {
                const bot = this.#getBot();
                if (!bot) return;

                // Scale coordinates from canvas pixels to game's 0-100 range
                const rect = this.#gameCanvas.getBoundingClientRect();
                const scaleX = 100 / rect.width;
                const scaleY = 100 / rect.height;

                let gameX1 = startX * scaleX;
                let gameY1 = startY * scaleY;
                let gameX2 = endX * scaleX;
                let gameY2 = endY * scaleY;

                // Apply Pixel Perfect snapping if active
                if (this.#isPixelPerfectActive) {
                    const snapSize = 2; // Snap to 2% grid, adjust as needed
                    gameX1 = Math.round(gameX1 / snapSize) * snapSize;
                    gameY1 = Math.round(gameY1 / snapSize) * snapSize;
                    gameX2 = Math.round(gameX2 / snapSize) * snapSize;
                    gameY2 = Math.round(gameY2 / snapSize) * snapSize;
                }

                // Ensure coordinates are within 0-100 bounds
                gameX1 = Math.max(0, Math.min(100, gameX1));
                gameY1 = Math.max(0, Math.min(100, gameY1));
                gameX2 = Math.max(0, Math.min(100, gameX2));
                gameY2 = Math.max(0, Math.min(100, gameY2));


                bot.emit("line", -1, gameX1, gameY1, gameX2, gameY2, true, this.#drawingThickness, this.#drawingColor, false);

                // If symmetry is active, send mirrored commands
                if (this.#isSymmetryActive) {
                    const midX = 50; // Center of the canvas (game's 0-100 scale)
                    const mirroredGameX1 = midX + (midX - gameX1);
                    const mirroredGameX2 = midX + (midX - gameX2);
                    bot.emit("line", -1, mirroredGameX1, gameY1, mirroredGameX2, gameY2, true, this.#drawingThickness, this.#drawingColor, false);
                }
            };

            this.#mouseDownListener = (e) => {
                isDrawing = true;
                const rect = this.#gameCanvas.getBoundingClientRect();
                lastX = e.clientX - rect.left;
                lastY = e.clientY - rect.top;
                // Start a new path on overlay if drawing for visualization
                this.#overlayCtx.beginPath();
                this.#overlayCtx.moveTo(lastX, lastY);
            };

            this.#mouseMoveListener = (e) => {
                if (!isDrawing) return;
                const rect = this.#gameCanvas.getBoundingClientRect();
                const currentX = e.clientX - rect.left;
                const currentY = e.clientY - rect.top;

                sendLineCommand(lastX, lastY, currentX, currentY);

                // Draw on overlay for visual feedback
                this.#overlayCtx.lineTo(currentX, currentY);
                this.#overlayCtx.strokeStyle = this.#drawingColor;
                this.#overlayCtx.lineWidth = this.#drawingThickness;
                this.#overlayCtx.lineCap = 'round';
                this.#overlayCtx.lineJoin = 'round';
                this.#overlayCtx.stroke();
                this.#overlayCtx.beginPath(); // Start new path to prevent connecting old points
                this.#overlayCtx.moveTo(currentX, currentY);


                lastX = currentX;
                lastY = currentY;
            };

            this.#mouseUpListener = () => {
                isDrawing = false;
                this.#clearOverlay(); // Clear temporary drawing from overlay
                if (this.#isGridVisible) this.#drawGrid(); // Redraw static guides
                if (this.#isSymmetryActive) this.#drawSymmetryLines(); // Redraw static guides
            };

            this.#gameCanvas.addEventListener('mousedown', this.#mouseDownListener);
            this.#gameCanvas.addEventListener('mousemove', this.#mouseMoveListener);
            this.#gameCanvas.addEventListener('mouseup', this.#mouseUpListener);
            this.#gameCanvas.addEventListener('mouseout', this.#mouseUpListener); // Stop drawing if mouse leaves canvas
        }

        // --- Geometric Shape Drawing ---
        #enableShapeDrawing(shapeType) {
            this.notify("info", `Modo '${shapeType}' activado. Haz clic en el lienzo para dibujar.`);
            const bot = this.#getBot();
            if (!bot) return;

            let startCoords = null;
            let currentShapeOverlayListener = null; // Renamed to avoid confusion with `currentShapeOverlay` variable

            const drawShapePreview = (x1, y1, x2, y2) => {
                this.#clearOverlay(); // Clear previous preview
                if (this.#isGridVisible) this.#drawGrid(); // Redraw static guides
                if (this.#isSymmetryActive) this.#drawSymmetryLines();

                const ctx = this.#overlayCtx;
                ctx.strokeStyle = this.#drawingColor;
                ctx.lineWidth = 1; // Thinner for preview
                ctx.setLineDash([5, 5]); // Dashed line for preview
                ctx.beginPath();

                const width = x2 - x1;
                const height = y2 - y1;

                if (shapeType === 'line') {
                    ctx.moveTo(x1, y1);
                    ctx.lineTo(x2, y2);
                } else if (shapeType === 'rect') {
                    ctx.rect(x1, y1, width, height);
                } else if (shapeType === 'circle') {
                    // Calculate radius, ensuring it's not negative
                    const dx = x2 - x1;
                    const dy = y2 - y1;
                    const radius = Math.sqrt(dx * dx + dy * dy);
                    ctx.arc(x1, y1, radius, 0, 2 * Math.PI);
                }
                ctx.stroke();
                ctx.setLineDash([]); // Reset line dash after drawing preview
            };

            const onClick = (e) => {
                const rect = this.#gameCanvas.getBoundingClientRect();
                const currentX = e.clientX - rect.left;
                const currentY = e.clientY - rect.top;

                if (!startCoords) {
                    startCoords = { x: currentX, y: currentY };
                    this.notify("info", "Haz clic de nuevo para definir el final de la forma.");

                    // Start live preview on mousemove
                    currentShapeOverlayListener = (moveEvent) => {
                        const moveRect = this.#gameCanvas.getBoundingClientRect();
                        const moveX = moveEvent.clientX - moveRect.left;
                        const moveY = moveEvent.clientY - moveRect.top;
                        drawShapePreview(startCoords.x, startCoords.y, moveX, moveY);
                    };
                    this.#gameCanvas.addEventListener('mousemove', currentShapeOverlayListener);

                } else {
                    // Second click: draw the shape
                    const bot = this.#getBot();
                    if (!bot) { // Check if bot is still available
                        this.notify("warning", "Bot no disponible, no se puede dibujar la forma.");
                        this.#gameCanvas.removeEventListener('click', onClick);
                        this.#gameCanvas.removeEventListener('mousemove', currentShapeOverlayListener);
                        this.#clearOverlay();
                        return;
                    }

                    const scaleX = 100 / rect.width;
                    const scaleY = 100 / rect.height;

                    const x1 = startCoords.x * scaleX;
                    const y1 = startCoords.y * scaleY;
                    const x2 = currentX * scaleX;
                    const y2 = currentY * scaleY;

                    const thickness = this.#drawingThickness;
                    const color = this.#drawingColor;

                    if (shapeType === 'line') {
                        bot.emit("line", -1, x1, y1, x2, y2, true, thickness, color, false);
                    } else if (shapeType === 'rect') {
                        // Draw 4 lines for rectangle
                        bot.emit("line", -1, x1, y1, x2, y1, true, thickness, color, false); // Top
                        bot.emit("line", -1, x2, y1, x2, y2, true, thickness, color, false); // Right
                        bot.emit("line", -1, x2, y2, x1, y2, true, thickness, color, false); // Bottom
                        bot.emit("line", -1, x1, y2, x1, y1, true, thickness, color, false); // Left
                    } else if (shapeType === 'circle') {
                        const centerX = x1;
                        const centerY = y1;
                        const dx = x2 - x1;
                        const dy = y2 - y1;
                        const radius = Math.sqrt(dx * dx + dy * dy); // Radius in game coordinates (0-100)

                        const segments = 48; // More segments for a smoother circle
                        for (let i = 0; i < segments; i++) {
                            const angle1 = (i / segments) * Math.PI * 2;
                            const angle2 = ((i + 1) / segments) * Math.PI * 2;
                            const cx1 = centerX + radius * Math.cos(angle1);
                            const cy1 = centerY + radius * Math.sin(angle1);
                            const cx2 = centerX + radius * Math.cos(angle2);
                            const cy2 = centerY + radius * Math.sin(angle2);
                            bot.emit("line", -1, cx1, cy1, cx2, cy2, true, thickness, color, false);
                        }
                    }

                    // Clean up and disable shape drawing
                    this.#gameCanvas.removeEventListener('click', onClick);
                    this.#gameCanvas.removeEventListener('mousemove', currentShapeOverlayListener);
                    this.#clearOverlay(); // Clear final preview
                    this.notify("success", `${shapeType} dibujado.`);
                    startCoords = null; // Reset for next shape
                }
            };
            this.#gameCanvas.addEventListener('click', onClick);
        }

        // --- Grid Overlay ---
        #toggleGrid(button) {
            this.#isGridVisible = !this.#isGridVisible;
            button.classList.toggle("active", this.#isGridVisible);
            this.#clearOverlay();
            if (this.#isGridVisible) {
                this.#drawGrid();
                this.notify("info", "Cuadrícula visible.");
            } else {
                this.notify("info", "Cuadrícula oculta.");
            }
            // Redraw symmetry lines if active
            if (this.#isSymmetryActive) this.#drawSymmetryLines();
        }

        #drawGrid() {
            if (!this.#gameCanvas) return;
            const ctx = this.#overlayCtx;
            const rect = this.#gameCanvas.getBoundingClientRect();
            const cellSize = 50; // px, adjust for desired grid density

            ctx.strokeStyle = "rgba(100, 100, 100, 0.5)";
            ctx.lineWidth = 1;
            ctx.setLineDash([2, 2]); // Dashed grid lines

            // Vertical lines
            for (let x = 0; x <= rect.width; x += cellSize) {
                ctx.beginPath();
                ctx.moveTo(x, 0);
                ctx.lineTo(x, rect.height);
                ctx.stroke();
            }

            // Horizontal lines
            for (let y = 0; y <= rect.height; y += cellSize) {
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(rect.width, y);
                ctx.stroke();
            }
            ctx.setLineDash([]); // Reset line dash
        }

        // --- Symmetry Mode ---
        #toggleSymmetry(button) {
            this.#isSymmetryActive = !this.#isSymmetryActive;
            button.classList.toggle("active", this.#isSymmetryActive);
            this.#clearOverlay();
            if (this.#isGridVisible) this.#drawGrid(); // Redraw grid if active
            if (this.#isSymmetryActive) {
                this.#drawSymmetryLines();
                this.notify("info", "Modo Simetría Activo.");
            } else {
                this.notify("info", "Modo Simetría Inactivo.");
            }
        }

        #drawSymmetryLines() {
            if (!this.#gameCanvas) return;
            const ctx = this.#overlayCtx;
            const rect = this.#gameCanvas.getBoundingClientRect();

            // Center vertical line
            ctx.strokeStyle = "rgba(255, 0, 0, 0.7)"; // Red for symmetry line
            ctx.lineWidth = 2;
            ctx.setLineDash([5, 5]); // Dashed line
            ctx.beginPath();
            ctx.moveTo(rect.width / 2, 0);
            ctx.lineTo(rect.width / 2, rect.height);
            ctx.stroke();
            ctx.setLineDash([]); // Reset line dash
        }

        // --- Pixel Perfect / Snap to Grid Drawing ---
        #togglePixelPerfect(button) {
            this.#isPixelPerfectActive = !this.#isPixelPerfectActive;
            button.classList.toggle("active", this.#isPixelPerfectActive);
            this.notify("info", `Modo 'Píxel Perfect' ${this.#isPixelPerfectActive ? 'Activado' : 'Desactivado'}.`);
        }

        // --- Collaborative Drawing Trigger ---
        #triggerAutodrawV2Collab() {
            const autodrawV2Class = this.findGlobal("AutodrawV2");
            if (!autodrawV2Class || !autodrawV2Class.siblings || autodrawV2Class.siblings.length === 0) {
                 this.notify("warning", "El módulo 'Autodraw V2' no está activo o no se encontró. No se puede iniciar el dibujo colaborativo.");
                 return;
            }
            const autodrawV2Instance = autodrawV2Class.siblings[0];

            if (autodrawV2Instance && typeof autodrawV2Instance.startDrawing === 'function') {
                // Assuming AutodrawV2.startDrawing handles bot distribution internally
                autodrawV2Instance.startDrawing();
                this.notify("info", "Iniciando dibujo colaborativo a través del módulo Autodraw V2.");
            } else {
                this.notify("warning", "La instancia del módulo 'Autodraw V2' no está lista. Asegúrate de que Autodraw V2 se inicializó correctamente.");
            }
        }
    }
})("QBit");


// END NEW UPTADES



// --- START NEW MODULE: ImageAnalyzer (ACTUALIZADO con Copy/Download/Add to Palette) ---
(function ImageAnalyzerModule() {
    const QBit = globalThis[arguments[0]];

    QBit.Styles.addRules([
        `#image-analyzer-container {
            display: flex;
            flex-direction: column;
            gap: 10px;
            padding: 5px;
            border: 1px solid var(--CE-color);
            border-radius: .25rem;
            background-color: var(--CE-bg_color);
        }`,
        `#image-analyzer-container input[type="text"],
         #image-analyzer-container button {
            width: 100%;
            padding: 5px;
            box-sizing: border-box;
         }`,
        `#image-preview-canvas {
            border: 1px dashed var(--CE-color);
            max-width: 100%;
            height: auto;
            display: block;
            margin: 5px auto;
        }`,
        `#dominant-colors-display {
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
            margin-top: 5px;
        }`,
        `#dominant-colors-display .color-swatch {
            width: 30px;
            height: 30px;
            border: 1px solid #ccc;
            border-radius: 3px;
            cursor: pointer;
            box-shadow: 0 0 3px rgba(0,0,0,0.2);
        }`,
        `#analysis-results {
            background-color: var(--CE-bg_color);
            border: 1px solid var(--CE-color);
            padding: 8px;
            margin-top: 10px;
            font-size: 0.8em;
            max-height: 150px;
            overflow-y: auto;
            white-space: pre-wrap;
            font-family: monospace;
        }`,
        `#image-analyzer-container .action-buttons {
            display: flex;
            gap: 5px;
            margin-top: 5px;
        }`,
        `#image-analyzer-container .action-buttons button {
            flex: 1;
        }`
    ]);

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

        #imageUrlInput;
        #loadAndAnalyzeButton;
        #imagePreviewCanvas;
        #imagePreviewCtx;
        #dominantColorsDisplay;
        #analysisResultsDisplay;
        #copyResultsButton;
        #downloadResultsButton;

        constructor() {
            super("Analizador de Imágenes", '<i class="fas fa-camera-retro"></i>');
            this.#onStartup();
        }

        #onStartup() {
            this.#loadInterface();
            this.notify("info", "Módulo Analizador de Imágenes cargado.");
            this.#loadAndAnalyzeButton.disabled = false;
            this.#loadAndAnalyzeButton.textContent = 'Cargar y Analizar';
            this.#copyResultsButton.disabled = true;
            this.#downloadResultsButton.disabled = true;
        }

        #loadInterface() {
            const container = domMake.Tree("div", { id: "image-analyzer-container" });

            this.#imageUrlInput = domMake.Tree("input", {
                type: "text",
                placeholder: "Pegar URL de imagen (ej. avatar)",
                value: "https://drawaria.online/avatar/cache/1a5f4450-7153-11ef-acaf-250da20bac69.jpg"
            });
            container.appendChild(this.#imageUrlInput);

            this.#loadAndAnalyzeButton = domMake.Button('<i class="fas fa-chart-pie"></i> Cargar y Analizar');
            this.#loadAndAnalyzeButton.addEventListener("click", () => this.#loadImageAndAnalyze());
            container.appendChild(this.#loadAndAnalyzeButton);

            this.#imagePreviewCanvas = domMake.Tree("canvas", { id: "image-preview-canvas" });
            container.appendChild(this.#imagePreviewCanvas);
            this.#imagePreviewCtx = this.#imagePreviewCanvas.getContext('2d');

            container.appendChild(domMake.Tree("div", {}, ["Colores Dominantes (clic para añadir a Paletas):"]));
            this.#dominantColorsDisplay = domMake.Tree("div", { id: "dominant-colors-display" });
            container.appendChild(this.#dominantColorsDisplay);

            this.#analysisResultsDisplay = domMake.Tree("pre", { id: "analysis-results" }, ["Resultados del análisis aparecerán aquí."]);
            container.appendChild(this.#analysisResultsDisplay);

            // Action Buttons Row (Copy/Download)
            const actionButtonsRow = domMake.Row({ class: "action-buttons" });
            this.#copyResultsButton = domMake.Button('<i class="fas fa-copy"></i> Copiar');
            this.#copyResultsButton.addEventListener("click", () => this.#copyResultsToClipboard());
            actionButtonsRow.appendChild(this.#copyResultsButton);

            this.#downloadResultsButton = domMake.Button('<i class="fas fa-download"></i> Descargar');
            this.#downloadResultsButton.addEventListener("click", () => this.#downloadResults());
            actionButtonsRow.appendChild(this.#downloadResultsButton);
            container.appendChild(actionButtonsRow);


            this.htmlElements.section.appendChild(container);
        }

        async #loadImageAndAnalyze() {
            const imageUrl = this.#imageUrlInput.value.trim();
            if (!imageUrl) {
                this.notify("warning", "Por favor, introduce una URL de imagen.");
                return;
            }

            this.notify("info", "Cargando imagen para análisis...");
            this.#analysisResultsDisplay.textContent = "Cargando...";
            this.#dominantColorsDisplay.innerHTML = '';
            this.#imagePreviewCtx.clearRect(0, 0, this.#imagePreviewCanvas.width, this.#imagePreviewCanvas.height);
            this.#copyResultsButton.disabled = true;
            this.#downloadResultsButton.disabled = true;

            const img = new window.Image();
            img.crossOrigin = "Anonymous"; // Crucial for CORS
            img.src = imageUrl;

            img.onload = async () => {
                try {
                    const maxWidth = 300;
                    const maxHeight = 300;
                    let width = img.width;
                    let height = img.height;

                    if (width > maxWidth || height > maxHeight) {
                        if (width / maxWidth > height / maxHeight) {
                            height = height * (maxWidth / width);
                            width = maxWidth;
                        } else {
                            width = width * (maxHeight / height);
                            height = maxHeight;
                        }
                    }

                    this.#imagePreviewCanvas.width = width;
                    this.#imagePreviewCanvas.height = height;
                    this.#imagePreviewCtx.drawImage(img, 0, 0, width, height);

                    const imageData = this.#imagePreviewCtx.getImageData(0, 0, width, height);
                    const pixels = imageData.data;

                    const results = {};

                    const colorMap = new Map();
                    const sampleStep = Math.max(1, Math.floor(pixels.length / 4 / 5000));

                    for (let i = 0; i < pixels.length; i += 4 * sampleStep) {
                        const r = pixels[i];
                        const g = pixels[i + 1];
                        const b = pixels[i + 2];
                        const a = pixels[i + 3];

                        if (a > 20) {
                            const colorKey = `${r},${g},${b}`;
                            colorMap.set(colorKey, (colorMap.get(colorKey) || 0) + 1);
                        }
                    }

                    const sortedColors = Array.from(colorMap.entries())
                        .sort((a, b) => b[1] - a[1])
                        .slice(0, 5);

                    results.dominantColors = sortedColors.map(([rgbStr, count]) => {
                        const [r, g, b] = rgbStr.split(',').map(Number);
                        return { r, g, b, hex: `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}` };
                    });

                    this.#dominantColorsDisplay.innerHTML = '';
                    results.dominantColors.forEach(color => {
                        const swatch = domMake.Tree("div", {
                            class: "color-swatch",
                            style: `background-color: ${color.hex};`,
                            title: `Clic para añadir ${color.hex} a Paletas de Color.`
                        });
                        swatch.addEventListener('click', () => this.#addDominantColorToPalette(color.hex));
                        this.#dominantColorsDisplay.appendChild(swatch);
                    });

                    let totalBrightness = 0;
                    let nonTransparentPixelCount = 0;
                    for (let i = 0; i < pixels.length; i += 4) {
                        const r = pixels[i];
                        const g = pixels[i + 1];
                        const b = pixels[i + 2];
                        const a = pixels[i + 3];
                        if (a > 0) {
                            totalBrightness += (0.299 * r + 0.587 * g + 0.114 * b);
                            nonTransparentPixelCount++;
                        }
                    }
                    results.averageBrightness = nonTransparentPixelCount > 0 ? (totalBrightness / nonTransparentPixelCount).toFixed(2) : 'N/A';
                    results.imageDimensions = `${width}x${height}`;
                    results.totalPixels = width * height;
                    results.nonTransparentPixels = nonTransparentPixelCount;

                    let resultsText = "--- Resultados del Análisis de Imagen ---\n";
                    resultsText += `Dimensiones: ${results.imageDimensions} píxeles\n`;
                    resultsText += `Píxeles no transparentes: ${results.nonTransparentPixels}\n`;
                    resultsText += `Brillo promedio: ${results.averageBrightness}\n`;
                    resultsText += `Colores Dominantes (HEX): ${results.dominantColors.map(c => c.hex).join(', ')}\n`;
                    resultsText += "\n¡Análisis completado!";
                    this.#analysisResultsDisplay.textContent = resultsText;

                    this.notify("success", "Análisis de imagen completado.");
                    this.#copyResultsButton.disabled = false;
                    this.#downloadResultsButton.disabled = false;

                } catch (e) {
                    if (e.name === "SecurityError" || (e.message && e.message.includes("tainted"))) {
                        this.notify("error", "Error de CORS: No se pudo acceder a los píxeles de la imagen. La imagen debe estar en el mismo origen o permitir CORS.");
                        this.#analysisResultsDisplay.textContent = "Error: No se pudo leer la imagen debido a restricciones de seguridad (CORS).";
                    } else {
                        this.notify("error", `Error al analizar la imagen: ${e.message}`);
                        this.#analysisResultsDisplay.textContent = `Error: ${e.message}`;
                        console.error("Image analysis error:", e);
                    }
                }
            };

            img.onerror = () => {
                this.notify("error", "Fallo al cargar la imagen. ¿URL correcta o problema de red?");
                this.#analysisResultsDisplay.textContent = "Error: Fallo al cargar la imagen.";
            };
        }

        // --- Nuevas funciones de Utilidad ---
        async #copyResultsToClipboard() {
            const resultsText = this.#analysisResultsDisplay.textContent;
            if (!resultsText.trim()) {
                this.notify("warning", "No hay resultados para copiar.");
                return;
            }
            try {
                await navigator.clipboard.writeText(resultsText);
                this.notify("success", "Resultados copiados al portapapeles.");
            } catch (err) {
                this.notify("error", `Error al copiar: ${err.message}`);
                console.error("Copy to clipboard failed:", err);
            }
        }

        #downloadResults() {
            const resultsText = this.#analysisResultsDisplay.textContent;
            if (!resultsText.trim()) {
                this.notify("warning", "No hay resultados para descargar.");
                return;
            }

            const blob = new Blob([resultsText], { type: 'text/plain;charset=utf-8' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `drawaria_image_analysis_${Date.now()}.txt`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
            this.notify("success", "Resultados descargados como TXT.");
        }

        #addDominantColorToPalette(hexColor) {
            const moreColorPalettesModule = this.findGlobal("MoreColorPalettes");
            if (moreColorPalettesModule && moreColorPalettesModule.siblings && moreColorPalettesModule.siblings.length > 0) {
                const paletteInstance = moreColorPalettesModule.siblings[0]; // Assuming first instance
                if (paletteInstance && typeof paletteInstance.addCustomColorFromExternal === 'function') {
                    paletteInstance.addCustomColorFromExternal(hexColor);
                    this.notify("info", `Color ${hexColor} enviado a 'Paletas de Color'.`);
                } else {
                    this.notify("warning", "El módulo 'Paletas de Color' no está listo o le falta la función para añadir colores.");
                }
            } else {
                this.notify("warning", "El módulo 'Paletas de Color' no se encontró o no está activo.");
            }
        }
    }
})("QBit");
// --- END NEW MODULE: ImageAnalyzer ---

})();