From fdb571ac6b84dead6f097138931af7c4a5c780fe Mon Sep 17 00:00:00 2001 From: SwingTheVine Date: Tue, 17 Feb 2026 01:24:36 -0500 Subject: [PATCH] Added color filter table --- dist/BlueMarble-For-GreasyFork.user.css | 105 +++++++ dist/BlueMarble-For-GreasyFork.user.js | 353 +++++++++++++++++++++++- dist/BlueMarble-Standalone.user.js | 4 +- dist/BlueMarble.user.css | 2 +- dist/BlueMarble.user.js | 4 +- docs/README.md | 2 +- package-lock.json | 4 +- package.json | 2 +- src/BlueMarble.meta.js | 2 +- src/Overlay.js | 335 +++++++++++++++++++++- src/Template.js | 3 +- src/main.js | 99 ++++++- src/overlay.css | 147 +++++++++- src/templateManager.js | 1 + 14 files changed, 1031 insertions(+), 32 deletions(-) diff --git a/dist/BlueMarble-For-GreasyFork.user.css b/dist/BlueMarble-For-GreasyFork.user.css index ea39243..8db6d01 100644 --- a/dist/BlueMarble-For-GreasyFork.user.css +++ b/dist/BlueMarble-For-GreasyFork.user.css @@ -1,4 +1,15 @@ /* src/overlay.css */ +.bm-screenreader { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} .bm-window { position: fixed; background-color: rgba(21, 48, 99, 0.9); @@ -10,6 +21,7 @@ top: 75px; left: 60px; width: auto; + max-height: calc(100vh - 150px); max-width: calc(100% - 135px); font-family: "Roboto Mono", @@ -114,6 +126,23 @@ margin: 0 auto; fill: #111; } +.bm-window button.bm-button-trans { + background-color: unset; +} +.bm-button-trans.bm-button-hover-white:hover, +.bm-button-trans.bm-button-hover-white:focus { + background-color: rgba(255, 255, 255, 0.17); +} +.bm-button-trans.bm-button-hover-white:active { + background-color: rgba(255, 255, 255, 0.22); +} +.bm-button-trans.bm-button-hover-black:hover, +.bm-button-trans.bm-button-hover-black:focus { + background-color: rgba(0, 0, 0, 0.17); +} +.bm-button-trans.bm-button-hover-black:active { + background-color: rgba(0, 0, 0, 0.22); +} input[type=number].bm-input-coords { appearance: auto; -moz-appearance: textfield; @@ -176,3 +205,79 @@ input[type=file] { align-items: center; gap: 0.5ch; } +#bm-window-filter .bm-container:has(table) { + max-height: 60vh; + overflow: auto; +} +#bm-window-filter table { + table-layout: fixed; + width: 50ch; + border-collapse: separate; + border-spacing: 0 0.5em; +} +#bm-window-filter tr { + padding: 0.5em 0; +} +.bm-filter-tbl-clr { + display: block; + border: thick double lightgray; + width: fit-content; + height: fit-content; + padding: 1ch; +} +.bm-filter-tbl-clr button { + padding: 0.75em 0.5ch; +} +.bm-filter-tbl-clr svg { + width: 4ch; + isolation: isolate; +} +.bm-filter-tbl-id { + position: relative; + top: 0.75em; + left: 0.5ch; +} +.bm-filter-tbl-prmim { + position: relative; + top: 0.75em; + left: -3.5ch; +} +.bm-filter-tbl-name { + position: relative; + top: -0.75em; + left: -16ch; + text-wrap: nowrap; +} +.bm-filter-tbl-crct { + display: block; + width: 100%; + position: relative; + right: 18ch; + top: 0.75em; + text-align: right; +} +.bm-filter-tbl-totl { + display: block; + width: 100%; + position: relative; + left: -16ch; + top: 0.75em; + text-align: left; +} +.bm-filter-tbl-totl::after { + content: "/"; + position: absolute; + left: -1.5ch; + top: 50%; + transform: translateY(-50%); +} +#bm-window-filter tfoot { + display: table-header-group; +} +#bm-window-filter tfoot th { + text-align: left; +} +#bm-window-filter tfoot td { + text-align: right; + padding-left: 1ch; +} diff --git a/dist/BlueMarble-For-GreasyFork.user.js b/dist/BlueMarble-For-GreasyFork.user.js index 7c3e1c6..038db43 100644 --- a/dist/BlueMarble-For-GreasyFork.user.js +++ b/dist/BlueMarble-For-GreasyFork.user.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.179 +// @version 0.88.207 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine @@ -150,7 +150,7 @@ * This `small` element will have properties shared between all `small` elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the `small` that are NOT shared between all overlay `small` elements. These should be camelCase. - * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `small`. + * @param {function(Overlay, HTMLElement):void} [callback=()=>{}] - Additional JS modification to the `small`. * @returns {Overlay} Overlay class instance (this) * @since 0.55.8 * @example @@ -169,11 +169,34 @@ callback(this, small); return this; } + /** Adds a `span` to the overlay. + * This `span` element will have properties shared between all `span` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `span` that are NOT shared between all overlay `span` elements. These should be camelCase. + * @param {function(Overlay, HTMLSpanElement):void} [callback=()=>{}] - Additional JS modification to the `span`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.55.8 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addSpan({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addSpan(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const span = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "span", properties, additionalProperties); + callback(this, span); + return this; + } /** Adds a `details` to the overlay. * This `details` element will have properties shared between all `details` elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the `details` that are NOT shared between all overlay `details` elements. These should be camelCase. - * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `details`. + * @param {function(Overlay, HTMLDetailsElement):void} [callback=()=>{}] - Additional JS modification to the `details`. * @returns {Overlay} Overlay class instance (this) * @since 0.88.96 * @example @@ -196,7 +219,7 @@ * This `summary` element will have properties shared between all `summary` elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the `summary` that are NOT shared between all overlay `summary` elements. These should be camelCase. - * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `summary`. + * @param {function(Overlay, HTMLElement):void} [callback=()=>{}] - Additional JS modification to the `summary`. * @returns {Overlay} Overlay class instance (this) * @since 0.88.96 * @example @@ -338,6 +361,282 @@ callback(this, label, checkbox); return this; } + /** Adds an ordered list to the overlay. + * This `ol` element will have properties shared between all `ol` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `ol` that are NOT shared between all overlay `ol` elements. These should be camelCase. + * @param {function(Overlay, HTMLOListElement):void} [callback=()=>{}] - Additional JS modification to the `ol`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all
    elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addOl({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
      Foobar.
    + * + */ + addOl(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const ol = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "ol", properties, additionalProperties); + callback(this, ol); + return this; + } + /** Adds an unordered list to the overlay. + * This `ul` element will have properties shared between all `ul` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `ul` that are NOT shared between all overlay `ul` elements. These should be camelCase. + * @param {function(Overlay, HTMLUListElement):void} [callback=()=>{}] - Additional JS modification to the `ul`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all
      elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addUl({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
        Foobar.
      + * + */ + addUl(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const ul = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "ul", properties, additionalProperties); + callback(this, ul); + return this; + } + /** Adds a `menu` to the overlay. + * This `menu` element will have properties shared between all `menu` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `menu` that are NOT shared between all overlay `menu` elements. These should be camelCase. + * @param {function(Overlay, HTMLMenuElement):void} [callback=()=>{}] - Additional JS modification to the `menu`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addMenu({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addMenu(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const menu = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "menu", properties, additionalProperties); + callback(this, menu); + return this; + } + /** Adds a list item to the overlay. + * This `li` element will have properties shared between all `li` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `li` that are NOT shared between all overlay `li` elements. These should be camelCase. + * @param {function(Overlay, HTMLLIElement):void} [callback=()=>{}] - Additional JS modification to the `li`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all
    • elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addLi({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
    • Foobar.
    • + * + */ + addLi(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const li = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "li", properties, additionalProperties); + callback(this, li); + return this; + } + /** Adds a table to the overlay. + * This `table` element will have properties shared between all `table` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `table` that are NOT shared between all overlay `table` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableElement):void} [callback=()=>{}] - Additional JS modification to the `table`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTable({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
      Foobar.
      + * + */ + addTable(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const table = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "table", properties, additionalProperties); + callback(this, table); + return this; + } + /** Adds a table caption to the overlay. + * This `caption` element will have properties shared between all `caption` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `caption` that are NOT shared between all overlay `caption` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableCaptionElement):void} [callback=()=>{}] - Additional JS modification to the `caption`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addCaption({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addCaption(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const caption = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "caption", properties, additionalProperties); + callback(this, caption); + return this; + } + /** Adds a table header to the overlay. + * This `thead` element will have properties shared between all `thead` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `thead` that are NOT shared between all overlay `thead` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableSectionElement):void} [callback=()=>{}] - Additional JS modification to the `thead`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addThead({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addThead(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const thead = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "thead", properties, additionalProperties); + callback(this, thead); + return this; + } + /** Adds a table body to the overlay. + * This `tbody` element will have properties shared between all `tbody` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `tbody` that are NOT shared between all overlay `tbody` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableSectionElement):void} [callback=()=>{}] - Additional JS modification to the `tbody`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTbody({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTbody(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const tbody = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "tbody", properties, additionalProperties); + callback(this, tbody); + return this; + } + /** Adds a table footer to the overlay. + * This `tfoot` element will have properties shared between all `tfoot` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `tfoot` that are NOT shared between all overlay `tfoot` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableSectionElement):void} [callback=()=>{}] - Additional JS modification to the `tfoot`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTfoot({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTfoot(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const tfoot = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "tfoot", properties, additionalProperties); + callback(this, tfoot); + return this; + } + /** Adds a table row to the overlay. + * This `tr` element will have properties shared between all `tr` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `tr` that are NOT shared between all overlay `tr` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableRowElement):void} [callback=()=>{}] - Additional JS modification to the `tr`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTr({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTr(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const tr = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "tr", properties, additionalProperties); + callback(this, tr); + return this; + } + /** Adds a table header (label) cell to the overlay. + * This `th` element will have properties shared between all `th` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `th` that are NOT shared between all overlay `th` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableCellElement):void} [callback=()=>{}] - Additional JS modification to the `th`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTh({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTh(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const th = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "th", properties, additionalProperties); + callback(this, th); + return this; + } + /** Adds a table data cell to the overlay. + * This `td` element will have properties shared between all `td` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `td` that are NOT shared between all overlay `td` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableCellElement):void} [callback=()=>{}] - Additional JS modification to the `td`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTd({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTd(additionalProperties = {}, callback = () => { + }) { + const properties = {}; + const td = __privateMethod(this, _Overlay_instances, createElement_fn).call(this, "td", properties, additionalProperties); + callback(this, td); + return this; + } /** Adds a `button` to the overlay. * This `button` element will have properties shared between all `button` elements in the overlay. * You can override the shared properties by using a callback. @@ -502,7 +801,7 @@ * This dragbar element will have properties shared between all dragbar elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the dragbar that are NOT shared between all overlay dragbars. These should be camelCase. - * @param {function(Overlay, HTMLTextAreaElement):void} [callback=()=>{}] - Additional JS modification to the dragbar. + * @param {function(Overlay, HTMLDivElement):void} [callback=()=>{}] - Additional JS modification to the dragbar. * @returns {Overlay} Overlay class instance (this) * @since 0.88.145 * @example @@ -872,6 +1171,13 @@ } return array; } + function calculateRelativeLuminance(array) { + const srgb = array.map((channel) => { + channel /= 255; + return channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4); + }); + return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2]; + } function colorpaletteForBlueMarble(tolerance) { const colorpaletteBM = colorpalette; colorpaletteBM.unshift({ "id": -1, "premium": false, "name": "Erased", "rgb": [222, 250, 206] }); @@ -1805,7 +2111,7 @@ Time Since Blink: ${String(Math.floor(elapsed / 6e4)).padStart(2, "0")}:${String button.onclick = () => instance.handleMinimization(button); button.ontouchend = () => instance.handleMinimization(button); }).buildElement().addDiv().buildElement().buildElement().addDiv({ "class": "bm-window-content" }).addDiv({ "class": "bm-container" }).addImg({ "class": "bm-favicon", "src": "https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png" }).buildElement().addHeader(1, { "textContent": name }).buildElement().buildElement().addHr().buildElement().addDiv({ "class": "bm-container" }).addP({ "id": "bm-user-droplets", "textContent": "Droplets:" }).buildElement().addP({ "id": "bm-user-nextlevel", "textContent": "Next level in..." }).buildElement().buildElement().addHr().buildElement().addDiv({ "class": "bm-container" }).addDiv({ "class": "bm-container" }).addButton( - { "class": "bm-button-circle bm-button-pin", "style": "margin-top: 0;", "innerHTML": '' }, + { "class": "bm-button-circle bm-button-pin", "style": "margin-top: 0;", "innerHTML": '' }, (instance, button) => { button.onclick = () => { const coords2 = instance.apiManager?.coordsTilePixel; @@ -1944,15 +2250,44 @@ Version: ${version}`, "readOnly": true }).buildElement().buildElement().addDiv({ }).buildElement().addButton({ "textContent": "Unselect All" }, (instance, button) => { button.onclick = () => { }; - }).buildElement().buildElement().addDiv().buildElement().buildElement().buildElement().buildOverlay(document.body); + }).buildElement().buildElement().buildElement().buildElement().buildOverlay(document.body); overlayFilter.handleDrag("#bm-window-filter.bm-window", "#bm-window-filter .bm-dragbar"); const windowContent = document.querySelector("#bm-window-filter .bm-window-content"); const { palette, LUT: _ } = templateManager.paletteBM; + let allPixelsTotal = 0; + let allPixelsCorrectTotal = 0; + const allPixelsCorrect = /* @__PURE__ */ new Map(); + const allPixelsColor = /* @__PURE__ */ new Map(); + for (const template of templateManager.templatesArray) { + const total = template.pixelCount?.total ?? 0; + const colors = template.pixelCount?.colors ?? /* @__PURE__ */ new Map(); + const correct = template.pixelCount?.correct ?? /* @__PURE__ */ new Map(); + allPixelsTotal += total ?? 0; + for (const [colorID, correctPixels] of correct) { + const _correctPixels = Number(correctPixels) || 0; + allPixelsCorrectTotal += _correctPixels; + const allPixelsCorrectSoFar = allPixelsCorrect.get(colorID) ?? 0; + allPixelsCorrect.set(colorID, allPixelsCorrectSoFar + _correctPixels); + } + for (const [colorID, colorPixels] of colors) { + const _colorPixels = Number(colorPixels) || 0; + const allPixelsColorSoFar = allPixelsColor.get(colorID) ?? 0; + allPixelsColor.set(colorID, allPixelsColorSoFar + _colorPixels); + } + } const colorList = new Overlay(name, version); - colorList.addDiv({ "id": "bm-filter-container-colors", "class": "bm-container" }); + colorList.addDiv({ "class": "bm-container" }).addTable({ "class": "bm-container" }).addCaption().addHeader(2, { "textContent": "Pixels In Templates By Palette Color" }).buildElement().buildElement().addTfoot().addTr().addTh({ "textContent": "Total Correct", "scope": "row" }).buildElement().addTd({ "textContent": allPixelsCorrectTotal.toString() }).buildElement().buildElement().addTr().addTh({ "textContent": "Total Pixels", "scope": "row" }).buildElement().addTd({ "textContent": allPixelsTotal.toString() }).buildElement().buildElement().buildElement().addThead({ "class": "bm-screenreader" }).addTr().addTh({ "textContent": "Hide Color", "scope": "col" }).buildElement().addTh({ "textContent": "ID", "scope": "col" }).buildElement().addTh({ "textContent": "Is Premium", "scope": "col" }).buildElement().addTh({ "textContent": "Name", "scope": "col" }).buildElement().addTh({ "textContent": "Correct Pixels", "scope": "col" }).buildElement().addTh({ "textContent": "Total Pixels", "scope": "col" }).buildElement().buildElement().buildElement(); for (const color of palette) { - colorList.addDiv({ "class": "bm-container" }).addP({ "textContent": `Color ID: ${color.id?.toString()?.padStart(2, "0")}, Name: ${color.name}` }).buildElement().buildElement(); + const lumin = calculateRelativeLuminance(color.rgb); + const textColorForPaletteColorBackground = 1.05 / (lumin + 0.05) > (lumin + 0.05) / 0.05 ? "white" : "black"; + const bgEffectForButtons = textColorForPaletteColorBackground == "white" ? "bm-button-hover-white" : "bm-button-hover-black"; + colorList.addTr().addTd().addDiv({ "class": "bm-filter-tbl-clr", "style": `background-color: rgb(${color.rgb?.map((channel) => Number(channel) || 0).join(",")});` }).addButton({ "class": "bm-button-trans " + bgEffectForButtons, "aria-label": `Hide the color ${color.name || "color"} on templates`, "innerHTML": `` }).buildElement().buildElement().buildElement().addTd().addSpan({ "class": "bm-filter-tbl-id", "textContent": `#${color.id}` }).buildElement().buildElement().addTd().addSpan({ "class": "bm-filter-tbl-prmim", "textContent": color.premium ? "\u2605" : "" }).buildElement().buildElement().addTd().addSpan({ "class": "bm-filter-tbl-name", "textContent": color.name }).buildElement().buildElement().addTd().addSpan({ "class": "bm-filter-tbl-crct", "textContent": middleEllipsis(String(allPixelsCorrect.get(color.id) ?? "???"), 7) }).buildElement().buildElement().addTd().addSpan({ "class": "bm-filter-tbl-totl", "textContent": middleEllipsis(String(allPixelsColor.get(color.id) ?? "0"), 7) }).buildElement().buildElement().buildElement(); } colorList.buildOverlay(windowContent); + function middleEllipsis(text, maxChars) { + if (text.length <= maxChars) return text; + const half = Math.floor((maxChars - 3) / 2); + return text.slice(0, half) + "\u2026" + text.slice(text.length - half); + } } })(); diff --git a/dist/BlueMarble-Standalone.user.js b/dist/BlueMarble-Standalone.user.js index 22c9fee..22c33df 100644 --- a/dist/BlueMarble-Standalone.user.js +++ b/dist/BlueMarble-Standalone.user.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.179 +// @version 0.88.207 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine @@ -27,4 +27,4 @@ // License --> https://www.mozilla.org/en-US/MPL/2.0/ // Donate --> https://ko-fi.com/swingthevine -(()=>{var e,t,n,i=e=>{throw TypeError(e)},o=(e,t,n)=>t.has(e)?i("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),s=(e,t,n)=>(((e,t)=>{t.has(e)||i("Cannot access private method")})(e,t),n),a=class{constructor(t,n){o(this,e),this.name=t,this.version=n,this.t=null,this.i="bm-o",this.o=null,this.l=null,this.m=[]}u(e){this.t=e}h(){return this.m.length>0&&(this.l=this.m.pop()),this}p(e){e?.appendChild(this.o),this.o=null,this.l=null,this.m=[]}v(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"div",{},n)),this}$(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"p",{},n)),this}S(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"small",{},n)),this}M(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"details",{},n)),this}T(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"summary",{},n)),this}D(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"img",{},n)),this}O(n,i={},o=()=>{}){return o(this,s(this,e,t).call(this,"h"+n,{},i)),this}C(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"hr",{},n)),this}k(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"br",{},n)),this}N(n={},i=()=>{}){const o=s(this,e,t).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=s(this,e,t).call(this,"input",{type:"checkbox"},n);return o.insertBefore(a,o.firstChild),this.h(),i(this,o,a),this}B(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"button",{},n)),this}I(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-D",onclick:()=>{this.L(this.i,o)}};return i(this,s(this,e,t).call(this,"button",a,n)),this}P(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"input",{},n)),this}G(n={},i=()=>{}){const o=n.textContent??"";delete n.textContent;const a=s(this,e,t).call(this,"div"),r=s(this,e,t).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true",style:"display: none !important; visibility: hidden !important; position: absolute !important; left: -9999px !important; width: 0 !important; height: 0 !important; opacity: 0 !important;"},n);this.h();const l=s(this,e,t).call(this,"button",{textContent:o});return this.h(),this.h(),l.addEventListener("click",()=>{r.click()}),r.addEventListener("change",()=>{l.style.maxWidth=`${l.offsetWidth}px`,r.files.length>0?l.textContent=r.files[0].name:l.textContent=o}),i(this,a,r,l),this}W(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"textarea",{},n)),this}U(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"div",{class:"bm-16"},n)),this}L(e,t,n=!1){const i=document.getElementById(e.replace(/^#/,""));i&&(i instanceof HTMLInputElement?i.value=t:n?i.textContent=t:i.innerHTML=t)}_(e){if(e.disabled)return;e.disabled=!0,e.style.textDecoration="none";const t=e.closest(".bm-18"),n=e.closest(".bm-16"),i=t.querySelector("h1"),o=t.querySelector(".bm-P");if("expanded"==e.dataset.buttonStatus){o.style.height=o.scrollHeight+"px",t.style.width=t.scrollWidth+"px",o.style.height="0",o.addEventListener("transitionend",function t(){o.style.display="none",e.disabled=!1,e.style.textDecoration="",o.removeEventListener("transitionend",t)});const n=i.cloneNode(!0),s=n.textContent;e.nextElementSibling.appendChild(n),e.textContent="▶",e.dataset.buttonStatus="collapsed",e.ariaLabel=`Unminimize window "${s}"`}else{const i=n.querySelector("h1"),s=i.textContent;i.remove(),o.style.display="",o.style.height="0",t.style.width="",o.style.height=o.scrollHeight+"px",o.addEventListener("transitionend",function t(){o.style.height="",e.disabled=!1,e.style.textDecoration="",o.removeEventListener("transitionend",t)}),e.textContent="▼",e.dataset.buttonStatus="expanded",e.ariaLabel=`Minimize window "${s}"`}}A(e,t){if(e=document.querySelector(e),t=document.querySelector(t),!e||!t)return void this.F(`Can not drag! ${e?"":"moveMe"} ${e||t?"":"and "}${t?"":"iMoveThings "}was not found!`);let n,i=!1,o=0,s=null,a=0,r=0,l=0,c=0,m=null;const d=()=>{if(i){const t=Math.abs(a-l),n=Math.abs(r-c);(t>.5||n>.5)&&(a=l,r=c,e.style.transform=`translate(${a}px, ${r}px)`,e.style.left="0px",e.style.top="0px",e.style.right=""),s=requestAnimationFrame(d)}},u=(u,g)=>{i=!0,m=e.getBoundingClientRect(),n=u-m.left,o=g-m.top;const f=window.getComputedStyle(e).transform;if(f&&"none"!==f){const e=new DOMMatrix(f);a=e.m41,r=e.m42}else a=m.left,r=m.top;l=a,c=r,document.body.style.userSelect="none",t.classList.add("bm-11"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",h),document.addEventListener("touchend",h),document.addEventListener("touchcancel",h),s&&cancelAnimationFrame(s),d()},h=()=>{i=!1,s&&(cancelAnimationFrame(s),s=null),document.body.style.userSelect="",t.classList.remove("bm-11"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",h),document.removeEventListener("touchend",h),document.removeEventListener("touchcancel",h)},b=e=>{i&&m&&(l=e.clientX-n,c=e.clientY-o)},p=e=>{if(i&&m){const t=e.touches[0];if(!t)return;l=t.clientX-n,c=t.clientY-o,e.preventDefault()}};t.addEventListener("mousedown",function(e){e.preventDefault(),u(e.clientX,e.clientY)}),t.addEventListener("touchstart",function(e){const t=e?.touches?.[0];t&&(u(t.clientX,t.clientY),e.preventDefault())},{passive:!1})}X(e){(0,console.info)(`${this.name}: ${e}`),this.L(this.i,"Status: "+e,!0)}F(e){(0,console.error)(`${this.name}: ${e}`),this.L(this.i,"Error: "+e,!0)}};function r(...e){(0,console.error)(...e)}function l(e,t){if(0===e)return t[0];let n="";const i=t.length;for(;e>0;)n=t[e%i]+n,e=Math.floor(e/i);return n}function c(e){let t="";for(let n=0;n0==t?e:e[0].toUpperCase()+e.slice(1)).join("")]=n;else if(t.startsWith("aria")){const i=t.slice(5).split("-").map((e,t)=>0==t?e:e[0].toUpperCase()+e.slice(1)).join("");e["aria"+i[0].toUpperCase()+i.slice(1)]=n}else e[t]=n};var d,u,h,b,p,g,f,w,y,x=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],v=class{constructor({displayName:e="My template",J:t=0,j:n="",url:i="",file:s=null,coords:a=null,R:r=null,Y:l={},V:c=1e3}={}){o(this,d),this.displayName=e,this.J=t,this.j=n,this.url=i,this.file=s,this.coords=a,this.R=r,this.Y=l,this.V=c,this.H={total:0,colors:new Map}}async q(e,t){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),i=n.width,o=n.height;this.V=e;const a={},r={},l=new OffscreenCanvas(this.V,this.V),m=l.getContext("2d",{K:!0});l.width=i,l.height=o,m.imageSmoothingEnabled=!1,m.drawImage(n,0,0);let h=Date.now();const b=s(this,d,u).call(this,m.getImageData(0,0,i,o),t);console.log(`Calculating total pixels took ${(Date.now()-h)/1e3} seconds`);let p=0;for(const[e,t]of b)0!=e&&(p+=t);this.H={total:p,colors:b},h=Date.now();const g=new OffscreenCanvas(3,3),f=g.getContext("2d");f.clearRect(0,0,3,3),f.fillStyle="white",f.fillRect(1,1,1,1);for(let e=this.coords[3];e>>24==0?0:o.get(t)??-2;const a=s.get(i);s.set(i,a?a+1:1)}return console.log(s),s},h=new WeakSet,b=async function(){GM.setValue("bmTemplates",JSON.stringify(this.ne))},p=async function(e){console.log("Parsing BlueMarble...");const t=e.templates;if(console.log(`BlueMarble length: ${Object.keys(t).length}`),Object.keys(t).length>0)for(const e in t){const n=e,i=t[e];if(console.log(`Template Key: ${n}`),t.hasOwnProperty(e)){const e=n.split(" "),t=Number(e?.[0]),o=e?.[1]||"0",s=i.name||`Template ${t||""}`,a={total:i.pixels.total,colors:new Map(Object.entries(i.pixels.colors).map(([e,t])=>[Number(e),t]))},r=i.tiles,l={},c={},d=this.V*this.ie;for(const e in r)if(console.log(e),r.hasOwnProperty(e)){const t=m(r[e]),n=new Blob([t],{type:"image/png"}),i=await createImageBitmap(n);l[e]=i;const o=new OffscreenCanvas(d,d).getContext("2d");o.drawImage(i,0,0);const s=o.getImageData(0,0,i.width,i.height);c[e]=new Uint32Array(s.data.buffer)}const u=new v({displayName:s,J:t||this.oe?.length||0,j:o||""});u.H=a,u.R=l,u.Y=c,this.oe.push(u),console.log(this.oe),console.log("^^^ This ^^^")}}},g=function(e,t,n){const i=this.ie,o=this.V*i,s=n[0],a=n[1],r=n[2],l=n[3],c=this.se,{palette:m,te:d}=this.ae,u=new Map;for(let n=1;n>>24&255)<=c||(i>>>24&255)<=c)continue;const h=d.get(i)??-2,b=d.get(m)??-2;if(h!=b)continue;const p=u.get(b);u.set(b,p?p+1:1)}return console.log("List of template pixels that match the tile:"),console.log(u),u},f=new WeakSet,w=async function(e=navigator.userAgent){return(e=e||"").includes("OPR/")||e.includes("Opera")?"Opera":e.includes("Edg/")?"Edge":e.includes("Vivaldi")?"Vivaldi":e.includes("YaBrowser")?"Yandex":e.includes("Kiwi")?"Kiwi":e.includes("Brave")?"Brave":e.includes("Firefox/")?"Firefox":e.includes("Chrome/")?"Chrome":e.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"},y=function(e=navigator.userAgent){return/Windows NT 11/i.test(e=e||"")?"Windows 11":/Windows NT 10/i.test(e)?"Windows 10":/Windows NT 6\.3/i.test(e)?"Windows 8.1":/Windows NT 6\.2/i.test(e)?"Windows 8":/Windows NT 6\.1/i.test(e)?"Windows 7":/Windows NT 6\.0/i.test(e)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(e)?"Windows XP":/Mac OS X 10[_\.]15/i.test(e)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(e)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(e)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(e)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(e)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(e)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(e)?"macOS":/Android/i.test(e)?"Android":/iPhone|iPad|iPod/i.test(e)?"iOS":/Linux/i.test(e)?"Linux":"Unknown"};var $=GM_info.script.name.toString(),S=GM_info.script.version.toString();!function(e){const t=document.createElement("script");t.setAttribute("bm-E",$),t.setAttribute("bm-B","color: cornflowerblue;"),t.textContent=`(${e})();`,document.documentElement?.appendChild(t),t.remove()}(()=>{const e=document.currentScript,t=e?.getAttribute("bm-E")||"Blue Marble",n=e?.getAttribute("bm-B")||"",i=new Map;window.addEventListener("message",e=>{const{source:o,endpoint:s,blobID:a,blobData:r,blink:l}=e.data,c=Date.now()-l;if(console.groupCollapsed(`%c${t}%c: ${i.size} Recieved IMAGE message about blob "${a}"`,n,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,n,""),console.log(i),console.groupEnd(),"blue-marble"==o&&a&&r&&!s){const e=i.get(a);"function"==typeof e?e(r):function(...e){(0,console.warn)(...e)}(`%c${t}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",a),i.delete(a)}});const o=window.fetch;window.fetch=async function(...e){const s=await o.apply(this,e),a=s.clone(),r=(e[0]instanceof Request?e[0]?.url:e[0])||"ignore",l=a.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${t}%c: Sending JSON message about endpoint "${r}"`,n,""),a.json().then(e=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:e},"*")}).catch(e=>{console.error(`%c${t}%c: Failed to parse JSON: `,n,"",e)});else if(l.includes("image/")&&!r.includes("openfreemap")&&!r.includes("maps")){const e=Date.now(),o=await a.blob();return console.log(`%c${t}%c: ${i.size} Sending IMAGE message about endpoint "${r}"`,n,""),new Promise(s=>{const l=crypto.randomUUID();i.set(l,e=>{s(new Response(e,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${t}%c: ${i.size} Processed blob "${l}"`,n,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:l,blobData:o,blink:e})}).catch(o=>{const s=Date.now();console.error(`%c${t}%c: Failed to Promise blob!`,n,""),console.groupCollapsed(`%c${t}%c: Details of failed blob Promise:`,n,""),console.log(`Endpoint: ${r}\nThere are ${i.size} blobs processing...\nBlink: ${e.toLocaleString()}\nTime Since Blink: ${String(Math.floor(s/6e4)).padStart(2,"0")}:${String(Math.floor(s/1e3)%60).padStart(2,"0")}.${String(s%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",o),console.groupEnd()})}return s}});var M=`.bm-18{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-Y{max-width:300px}.bm-16{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-16.bm-11{cursor:grabbing}.bm-18:has(.bm-16.bm-11){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-16.bm-11{pointer-events:auto}.bm-17{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-18 h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-16 h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-16 div:has(h1){display:contents}.bm-10{margin:.5em 0}.bm-18 button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-18 button:hover,.bm-18 button:focus-visible{background-color:#1061e5}.bm-18 button:active,.bm-18 button:disabled{background-color:#2e97ff}.bm-18 button:disabled{text-decoration:line-through}.bm-U{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm--{vertical-align:middle}.bm-- svg{width:50%;margin:0 auto;fill:#111}input[type=number].bm-W{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-W::-webkit-outer-spin-button,input[type=number].bm-W::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-_)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-_,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-P{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-18 textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-18 small{font-size:x-small;color:#d3d3d3}.bm-X{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-flex-center{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch}`;GM_addStyle(M);var T,D="@font-face{font-family:'Roboto Mono';font-style:normal;font-weight:400;src:url(data:font/woff2;base64,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)format('woff2');}";D.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(D)):((T=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",T.rel="preload",T.as="style",T.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(T)),new class{constructor(){this.re=null,this.le=null,this.ce="#bm-h"}me(e){return this.le=e,this.re=new MutationObserver(e=>{for(const t of e)for(const e of t.addedNodes)e instanceof HTMLElement&&e.matches?.(this.ce)}),this}de(){return this.re}observe(e,t=!1,n=!1){e.observe(this.le,{childList:t,subtree:n})}};var O=new a($,S),C=(new a($,S),new class{constructor(e,t,n){o(this,h),this.name=e,this.version=t,this.o=n,this.ue="1.0.0",this.he=null,this.be="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.V=1e3,this.ie=3,this.se=3,this.ae=function(e){const t=x;t.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),t.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const n=new Map;for(const i of t){if(0==i.id||-2==i.id)continue;const t=i.rgb[0],o=i.rgb[1],s=i.rgb[2];for(let a=-e;a<=e;a++)for(let r=-e;r<=e;r++)for(let l=-e;l<=e;l++){const e=t+a,c=o+r,m=s+l;if(e<0||e>255||c<0||c>255||m<0||m>255)continue;const d=(255<<24|m<<16|c<<8|e)>>>0;n.has(d)||n.set(d,i.id)}}return{palette:t,te:n}}(this.se),this.pe=null,this.ge="",this.oe=[],this.ne=null,this.fe=!0,this.we=null}async ye(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.ue,templates:{}}}async xe(e,t,n){this.ne||(this.ne=await this.ye(),console.log("Creating JSON...")),this.o.X(`Creating template at ${n.join(", ")}...`);const i=new v({displayName:t,J:0,j:l(this.he||0,this.be),file:e,coords:n}),{Z:o,ee:a}=await i.q(this.V,this.ae);i.R=o;const r={total:i.H.total,colors:Object.fromEntries(i.H.colors)};this.ne.templates[`${i.J} ${i.j}`]={name:i.displayName,coords:n.join(", "),enabled:!0,pixels:r,tiles:a},this.oe=[],this.oe.push(i),this.o.X(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.ne.templates).length),console.log(this.ne),console.log(this.oe),console.log(JSON.stringify(this.ne)),await s(this,h,b).call(this)}ve(){}async $e(){this.ne||(this.ne=await this.ye(),console.log("Creating JSON..."))}async Se(e,t){if(!this.fe)return e;const n=this.V*this.ie;t=t[0].toString().padStart(4,"0")+","+t[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${t}"`);const i=this.oe;console.log(i),i.sort((e,t)=>e.J-t.J),console.log(i);const o=i.map(e=>{const n=Object.keys(e.R).filter(e=>e.startsWith(t));if(0===n.length)return null;const i=n.map(t=>{const n=t.split(",");return{Me:e,Te:e.R[t],Y:e.Y?.[t],De:[n[0],n[1]],Oe:[n[2],n[3]]}});return i?.[0]}).filter(Boolean);console.log(o);const a=o?.length||0;if(console.log(`templateCount = ${a}`),!(a>0))return this.o.X(`Sleeping\nVersion: ${this.version}`),e;{const e=i.filter(e=>Object.keys(e.R).filter(e=>e.startsWith(t)).length>0).reduce((e,t)=>e+(t.H.total||0),0),n=(new Intl.NumberFormat).format(e);this.o.X(`Displaying ${a} template${1==a?"":"s"}.\nTotal pixels: ${n}`)}const r=await createImageBitmap(e),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(r,0,0,n,n);const m=c.getImageData(0,0,n,n),d=new Uint32Array(m.data.buffer);for(const e of o){console.log("Template:"),console.log(e);let n=e.Y;const i=Number(e.Oe[0])*this.ie,o=Number(e.Oe[1])*this.ie;if(c.drawImage(e.Te,i,o),!n){const t=c.getImageData(i,o,e.Te.width,e.Te.height);n=new Uint32Array(t.data.buffer)}const a=Date.now(),r=s(this,h,g).call(this,d,n,[i,o,e.Te.width,e.Te.height]);let l=0;const m=0;for(const[e,t]of r)e!=m&&(l+=t);console.log(`Finished calculating correct pixels for the tile ${t} in ${(Date.now()-a)/1e3} seconds!\nThere are ${l} correct pixels.`),e.Me.H.correct=r}return await l.convertToBlob({type:"image/png"})}Ce(e){console.log("Importing JSON..."),console.log(e),"BlueMarble"==e?.whoami&&s(this,h,p).call(this,e)}ke(e){this.fe=e}}($,S,O)),k=new class{constructor(e){o(this,f),this.Ne=e,this.Be=!1,this.Ie=[],this.Le=[]}Pe(e){window.addEventListener("message",async t=>{const n=t.data,i=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const o=n.endpoint?.split("?")[0].split("/").filter(e=>e&&isNaN(Number(e))).filter(e=>e&&!e.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",o),o){case"me":if(i.status&&"2"!=i.status?.toString()[0])return void e.F("You are not logged in!\nCould not fetch userdata.");const t=Math.ceil(Math.pow(Math.floor(i.level)*Math.pow(30,.65),1/.65)-i.pixelsPainted);console.log(i.id),(i.id||0===i.id)&&console.log(l(i.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Ne.he=i.id,e.L("bm-p",`Droplets: ${(new Intl.NumberFormat).format(i.droplets)}`),e.L("bm-i",`Next level in ${(new Intl.NumberFormat).format(t)} pixel${1==t?"":"s"}`);break;case"pixel":const o=n.endpoint.split("?")[0].split("/").filter(e=>e&&!isNaN(Number(e))),r=new URLSearchParams(n.endpoint.split("?")[1]),c=[r.get("x"),r.get("y")];if(this.Ie.length&&(!o.length||!c.length))return void e.F("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Ie=[...o,...c];const m=(s=o,a=c,[parseInt(s[0])%4*1e3+parseInt(a[0]),parseInt(s[1])%4*1e3+parseInt(a[1])]),d=document.querySelectorAll("span");for(const e of d)if(e.textContent.trim().includes(`${m[0]}, ${m[1]}`)){let t=document.querySelector("#bm-h");const n=`(Tl X: ${o[0]}, Tl Y: ${o[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;t?t.textContent=n:(t=document.createElement("span"),t.id="bm-h",t.textContent=n,t.style="margin-left: calc(var(--spacing)*3); font-size: small;",e.parentNode.parentNode.insertAdjacentElement("afterend",t))}break;case"tiles":let u=n.endpoint.split("/");u=[parseInt(u[u.length-2]),parseInt(u[u.length-1].replace(".png",""))];const h=n.blobID,b=n.blobData,p=Date.now(),g=await this.Ne.Se(b,u);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:h,blobData:g,blink:n.blink});break;case"robots":this.Be="false"==i.userscript?.toString().toLowerCase();break}var s,a})}async Ge(e){console.log("Sending heartbeat to telemetry server...");let t=GM_getValue("bmUserSettings","{}");if(t=JSON.parse(t),!t||!t.telemetry||!t.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const n=navigator.userAgent;let i=await s(this,f,w).call(this,n),o=s(this,f,y).call(this,n);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:t.uuid,version:e,browser:i,os:o}),onload:e=>{200!==e.status&&r("Failed to send heartbeat:",e.statusText)},onerror:e=>{r("Error sending heartbeat:",e)}})}}(C);O.u(k);var N=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(N),C.Ce(N);var B=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(B),console.log(Object.keys(B).length),0==Object.keys(B).length){const e=crypto.randomUUID();console.log(e),GM.setValue("bmUserSettings",JSON.stringify({uuid:e}))}if(setInterval(()=>k.Ge(S),18e5),console.log(`Telemetry is ${!(null==B?.telemetry)}`),null==B?.telemetry||B?.telemetry>1){const e=new a($,S);e.u(k),e.v({id:"bm-d",style:"top: 0px; left: 0px; width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; z-index: 9999;"}).v({id:"bm-7",style:"display: flex; flex-direction: column; align-items: center;"}).v({id:"bm-1",style:"margin-top: 10%;"}).O(1,{textContent:`${$} Telemetry`}).h().h().v({id:"bm-e",style:"max-width: 50%; overflow-y: auto; max-height: 80vh;"}).C().h().k().h().v({style:"width: fit-content; margin: auto; text-align: center;"}).B({id:"bm-8",textContent:"More Information"},(e,t)=>{t.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).h().h().k().h().v({style:"width: fit-content; margin: auto; text-align: center;"}).B({id:"bm-5",textContent:"Enable Telemetry",style:"margin-right: 2ch;"},(e,t)=>{t.onclick=()=>{const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=1,GM.setValue("bmUserSettings",JSON.stringify(e));const t=document.getElementById("bm-d");t&&(t.style.display="none")}}).h().B({id:"bm-2",textContent:"Disable Telemetry"},(e,t)=>{t.onclick=()=>{const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=0,GM.setValue("bmUserSettings",JSON.stringify(e));const t=document.getElementById("bm-d");t&&(t.style.display="none")}}).h().h().k().h().$({textContent:"We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the 'Disable' button, but keeping it on helps us improve features and reliability faster. Thank you for supporting the Blue Marble!"}).h().$({textContent:'You can disable telemetry by pressing the "Disable" button below.'}).h().h().h().p(document.body)}O.v({id:"bm-Y",class:"bm-18",style:"top: 10px; left: unset; right: 75px;"}).U().B({class:"bm-U",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(e,t)=>{t.onclick=()=>e._(t),t.ontouchend=()=>e._(t)}).h().v().h().h().v({class:"bm-P"}).v({class:"bm-10"}).D({class:"bm-17",src:"data:image/png;base64,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"}).h().O(1,{textContent:$}).h().h().C().h().v({class:"bm-10"}).$({id:"bm-p",textContent:"Droplets:"}).h().$({id:"bm-i",textContent:"Next level in..."}).h().h().C().h().v({class:"bm-10"}).v({class:"bm-10"}).B({class:"bm-U bm--",style:"margin-top: 0;",innerHTML:''},(e,t)=>{t.onclick=()=>{const t=e.t?.Ie;t?.[0]?(e.L("bm-v",t?.[0]||""),e.L("bm-w",t?.[1]||""),e.L("bm-x",t?.[2]||""),e.L("bm-y",t?.[3]||"")):e.F("Coordinates are malformed! Did you try clicking on the canvas first?")}}).h().P({type:"number",id:"bm-v",class:"bm-W",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(e,t)=>{t.addEventListener("paste",e=>{let t=(e.clipboardData||window.clipboardData).getData("text").split(" ").filter(e=>e).map(Number).filter(e=>!isNaN(e));if(4!==t.length)return;let n=selectAllCoordinateInputs(document);for(let e=0;e{t.onclick=()=>{t.disabled=!0,"shown"==t.dataset.buttonStatus?(e.t?.Ne?.ke(!1),t.dataset.buttonStatus="hidden",t.textContent="Enable",e.X("Disabled templates!")):(e.t?.Ne?.ke(!0),t.dataset.buttonStatus="shown",t.textContent="Disable",e.X("Enabled templates!")),t.disabled=!1}}).h().B({textContent:"Create"},(e,t)=>{t.onclick=()=>{const t=document.querySelector("#bm-Y button.bm-_"),n=document.querySelector("#bm-v");if(!n.checkValidity())return n.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-w");if(!i.checkValidity())return i.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-x");if(!o.checkValidity())return o.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-y");if(!s.checkValidity())return s.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");t?.files[0]?(C.xe(t.files[0],t.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(i.value),Number(o.value),Number(s.value)]),e.X("Drew to canvas!")):e.F("No file selected!")}}).h().B({textContent:"Filter"},(e,t)=>{t.onclick=()=>function(){if(document.querySelector("#bm-V"))return void O.F("Color Filter window already exists!");const e=new a($,S);e.v({id:"bm-V",class:"bm-18"}).U().B({class:"bm-U",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(e,t)=>{t.onclick=()=>e._(t),t.ontouchend=()=>e._(t)}).h().v().h().B({class:"bm-U",textContent:"🞪","aria-label":'Close window "Color Filter"'},(e,t)=>{t.onclick=()=>{document.querySelector("#bm-V")?.remove()},t.ontouchend=()=>{document.querySelector("#bm-V")?.remove()}}).h().h().v({class:"bm-P"}).v({class:"bm-10"}).O(1,{textContent:"Color Filter"}).h().h().C().h().v({class:"bm-10 bm-X",style:"width: fit-content;"}).B({textContent:"Select All"},(e,t)=>{t.onclick=()=>{}}).h().B({textContent:"Unselect All"},(e,t)=>{t.onclick=()=>{}}).h().h().v().h().h().h().p(document.body),e.A("#bm-V.bm-18","#bm-V .bm-16");const t=document.querySelector("#bm-V .bm-P"),{palette:n,te:i}=C.ae,o=new a($,S);o.v({id:"bm-K",class:"bm-10"});for(const e of n)o.v({class:"bm-10"}).$({textContent:`Color ID: ${e.id?.toString()?.padStart(2,"0")}, Name: ${e.name}`}).h().h();o.p(t)}()}).h().h().v({class:"bm-10"}).W({id:O.i,placeholder:`Status: Sleeping...\nVersion: ${S}`,readOnly:!0}).h().h().v({class:"bm-10 bm-X",style:"margin-bottom: 0;"}).v({class:"bm-X"}).B({class:"bm-U",innerHTML:"🎨",title:"Template Color Converter"},(e,t)=>{t.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).h().B({class:"bm-U",innerHTML:"🌐",title:"Official Blue Marble Website"},(e,t)=>{t.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).h().h().S({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).h().h().h().h().h().p(document.body),O.A("#bm-Y.bm-18","#bm-Y .bm-16"),k.Pe(O),new MutationObserver((e,t)=>{const n=document.querySelector("#color-1");if(!n)return;let i=document.querySelector("#bm-t");if(!i){i=document.createElement("button"),i.id="bm-t",i.textContent="Move ↑",i.className="btn btn-soft",i.onclick=function(){const e=this.parentNode.parentNode.parentNode.parentNode,t="Move ↑"==this.textContent;e.parentNode.className=e.parentNode.className.replace(t?"bottom":"top",t?"top":"bottom"),e.style.borderTopLeftRadius=t?"0px":"var(--radius-box)",e.style.borderTopRightRadius=t?"0px":"var(--radius-box)",e.style.borderBottomLeftRadius=t?"var(--radius-box)":"0px",e.style.borderBottomRightRadius=t?"var(--radius-box)":"0px",this.textContent=t?"Move ↓":"Move ↑"};const e=n.parentNode.parentNode.parentNode.parentNode.querySelector("h2");e.parentNode?.appendChild(i)}}).observe(document.body,{childList:!0,subtree:!0}),function(...e){(0,console.log)(...e)}(`%c${$}%c (${S}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file +(()=>{var t,e,n,i=t=>{throw TypeError(t)},o=(t,e,n)=>e.has(t)?i("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n),s=(t,e,n)=>(((t,e)=>{e.has(t)||i("Cannot access private method")})(t,e),n),r=class{constructor(e,n){o(this,t),this.name=e,this.version=n,this.t=null,this.i="bm-o",this.o=null,this.l=null,this.m=[]}h(t){this.t=t}u(){return this.m.length>0&&(this.l=this.m.pop()),this}p(t){t?.appendChild(this.o),this.o=null,this.l=null,this.m=[]}v(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{},n)),this}S(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"p",{},n)),this}$(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"small",{},n)),this}M(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"span",{},n)),this}T(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"details",{},n)),this}C(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"summary",{},n)),this}D(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"img",{},n)),this}O(n,i={},o=()=>{}){return o(this,s(this,t,e).call(this,"h"+n,{},i)),this}k(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"hr",{},n)),this}N(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"br",{},n)),this}B(n={},i=()=>{}){const o=s(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const r=s(this,t,e).call(this,"input",{type:"checkbox"},n);return o.insertBefore(r,o.firstChild),this.u(),i(this,o,r),this}I(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"ol",{},n)),this}L(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"ul",{},n)),this}P(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"menu",{},n)),this}G(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"li",{},n)),this}U(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"table",{},n)),this}W(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"caption",{},n)),this}A(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"thead",{},n)),this}_(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"tbody",{},n)),this}F(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"tfoot",{},n)),this}X(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"tr",{},n)),this}H(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"th",{},n)),this}J(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"td",{},n)),this}j(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"button",{},n)),this}R(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const r={textContent:"?",className:"bm-D",onclick:()=>{this.Y(this.i,o)}};return i(this,s(this,t,e).call(this,"button",r,n)),this}V(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"input",{},n)),this}q(n={},i=()=>{}){const o=n.textContent??"";delete n.textContent;const r=s(this,t,e).call(this,"div"),a=s(this,t,e).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true",style:"display: none !important; visibility: hidden !important; position: absolute !important; left: -9999px !important; width: 0 !important; height: 0 !important; opacity: 0 !important;"},n);this.u();const l=s(this,t,e).call(this,"button",{textContent:o});return this.u(),this.u(),l.addEventListener("click",()=>{a.click()}),a.addEventListener("change",()=>{l.style.maxWidth=`${l.offsetWidth}px`,a.files.length>0?l.textContent=a.files[0].name:l.textContent=o}),i(this,r,a,l),this}K(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"textarea",{},n)),this}Z(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{class:"bm-1f"},n)),this}Y(t,e,n=!1){const i=document.getElementById(t.replace(/^#/,""));i&&(i instanceof HTMLInputElement?i.value=e:n?i.textContent=e:i.innerHTML=e)}tt(t){if(t.disabled)return;t.disabled=!0,t.style.textDecoration="none";const e=t.closest(".bm-1h"),n=t.closest(".bm-1f"),i=e.querySelector("h1"),o=e.querySelector(".bm-U");if("expanded"==t.dataset.buttonStatus){o.style.height=o.scrollHeight+"px",e.style.width=e.scrollWidth+"px",o.style.height="0",o.addEventListener("transitionend",function e(){o.style.display="none",t.disabled=!1,t.style.textDecoration="",o.removeEventListener("transitionend",e)});const n=i.cloneNode(!0),s=n.textContent;t.nextElementSibling.appendChild(n),t.textContent="▶",t.dataset.buttonStatus="collapsed",t.ariaLabel=`Unminimize window "${s}"`}else{const i=n.querySelector("h1"),s=i.textContent;i.remove(),o.style.display="",o.style.height="0",e.style.width="",o.style.height=o.scrollHeight+"px",o.addEventListener("transitionend",function e(){o.style.height="",t.disabled=!1,t.style.textDecoration="",o.removeEventListener("transitionend",e)}),t.textContent="▼",t.dataset.buttonStatus="expanded",t.ariaLabel=`Minimize window "${s}"`}}et(t,e){if(t=document.querySelector(t),e=document.querySelector(e),!t||!e)return void this.nt(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);let n,i=!1,o=0,s=null,r=0,a=0,l=0,c=0,m=null;const d=()=>{if(i){const e=Math.abs(r-l),n=Math.abs(a-c);(e>.5||n>.5)&&(r=l,a=c,t.style.transform=`translate(${r}px, ${a}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),s=requestAnimationFrame(d)}},h=(h,g)=>{i=!0,m=t.getBoundingClientRect(),n=h-m.left,o=g-m.top;const f=window.getComputedStyle(t).transform;if(f&&"none"!==f){const t=new DOMMatrix(f);r=t.m41,a=t.m42}else r=m.left,a=m.top;l=r,c=a,document.body.style.userSelect="none",e.classList.add("bm-1a"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",u),document.addEventListener("touchend",u),document.addEventListener("touchcancel",u),s&&cancelAnimationFrame(s),d()},u=()=>{i=!1,s&&(cancelAnimationFrame(s),s=null),document.body.style.userSelect="",e.classList.remove("bm-1a"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchend",u),document.removeEventListener("touchcancel",u)},b=t=>{i&&m&&(l=t.clientX-n,c=t.clientY-o)},p=t=>{if(i&&m){const e=t.touches[0];if(!e)return;l=e.clientX-n,c=e.clientY-o,t.preventDefault()}};e.addEventListener("mousedown",function(t){t.preventDefault(),h(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(h(e.clientX,e.clientY),t.preventDefault())},{passive:!1})}it(t){(0,console.info)(`${this.name}: ${t}`),this.Y(this.i,"Status: "+t,!0)}nt(t){(0,console.error)(`${this.name}: ${t}`),this.Y(this.i,"Error: "+t,!0)}};function a(...t){(0,console.error)(...t)}function l(t,e){if(0===t)return e[0];let n="";const i=e.length;for(;t>0;)n=e[t%i]+n,t=Math.floor(t/i);return n}function c(t){let e="";for(let n=0;n(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4));return.2126*e[0]+.7152*e[1]+.0722*e[2]}t=new WeakSet,e=function(e,i={},o={}){const r=document.createElement(e);this.o?(this.l?.appendChild(r),this.m.push(this.l),this.l=r):(this.o=r,this.l=r);for(const[e,o]of Object.entries(i))s(this,t,n).call(this,r,e,o);for(const[e,i]of Object.entries(o))s(this,t,n).call(this,r,e,i);return r},n=function(t,e,n){if("class"==e)t.classList.add(...n.split(/\s+/));else if("for"==e)t.htmlFor=n;else if("tabindex"==e)t.tabIndex=Number(n);else if("readonly"==e)t.readOnly="true"==n||"1"==n;else if("maxlength"==e)t.maxLength=Number(n);else if(e.startsWith("data"))t.dataset[e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("")]=n;else if(e.startsWith("aria")){const i=e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("");t["aria"+i[0].toUpperCase()+i.slice(1)]=n}else t[e]=n};var h,u,b,p,g,f,w,y,x,v=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],S=class{constructor({displayName:t="My template",ot:e=0,st:n="",url:i="",file:s=null,coords:r=null,rt:a=null,lt:l={},ct:c=1e3}={}){o(this,h),this.displayName=t,this.ot=e,this.st=n,this.url=i,this.file=s,this.coords=r,this.rt=a,this.lt=l,this.ct=c,this.dt={total:0,colors:new Map}}async ht(t,e){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),i=n.width,o=n.height;this.ct=t;const r={},a={},l=new OffscreenCanvas(this.ct,this.ct),m=l.getContext("2d",{ut:!0});l.width=i,l.height=o,m.imageSmoothingEnabled=!1,m.drawImage(n,0,0);let d=Date.now();const b=s(this,h,u).call(this,m.getImageData(0,0,i,o),e);console.log(`Calculating total pixels took ${(Date.now()-d)/1e3} seconds`);let p=0;for(const[t,e]of b)0!=t&&(p+=e);this.dt={total:p,colors:b},d=Date.now();const g=new OffscreenCanvas(3,3),f=g.getContext("2d");f.clearRect(0,0,3,3),f.fillStyle="white",f.fillRect(1,1,1,1);for(let t=this.coords[3];t>>24==0?0:o.get(e)??-2;const r=s.get(i);s.set(i,r?r+1:1)}return console.log(s),s},b=new WeakSet,p=async function(){GM.setValue("bmTemplates",JSON.stringify(this.wt))},g=async function(t){console.log("Parsing BlueMarble...");const e=t.templates;if(console.log(`BlueMarble length: ${Object.keys(e).length}`),Object.keys(e).length>0)for(const t in e){const n=t,i=e[t];if(console.log(`Template Key: ${n}`),e.hasOwnProperty(t)){const t=n.split(" "),e=Number(t?.[0]),o=t?.[1]||"0",s=i.name||`Template ${e||""}`,r={total:i.pixels.total,colors:new Map(Object.entries(i.pixels.colors).map(([t,e])=>[Number(t),e]))},a=i.tiles,l={},c={},d=this.ct*this.yt;for(const t in a)if(console.log(t),a.hasOwnProperty(t)){const e=m(a[t]),n=new Blob([e],{type:"image/png"}),i=await createImageBitmap(n);l[t]=i;const o=new OffscreenCanvas(d,d).getContext("2d");o.drawImage(i,0,0);const s=o.getImageData(0,0,i.width,i.height);c[t]=new Uint32Array(s.data.buffer)}const h=new S({displayName:s,ot:e||this.xt?.length||0,st:o||""});h.dt=r,h.rt=l,h.lt=c,this.xt.push(h),console.log(this.xt),console.log("^^^ This ^^^")}}},f=function(t,e,n){const i=this.yt,o=this.ct*i,s=n[0],r=n[1],a=n[2],l=n[3],c=this.vt,{palette:m,ft:d}=this.St,h=new Map;for(let n=1;n>>24&255)<=c||(i>>>24&255)<=c)continue;const u=d.get(i)??-2,b=d.get(m)??-2;if(u!=b)continue;const p=h.get(b);h.set(b,p?p+1:1)}return console.log("List of template pixels that match the tile:"),console.log(h),h},w=new WeakSet,y=async function(t=navigator.userAgent){return(t=t||"").includes("OPR/")||t.includes("Opera")?"Opera":t.includes("Edg/")?"Edge":t.includes("Vivaldi")?"Vivaldi":t.includes("YaBrowser")?"Yandex":t.includes("Kiwi")?"Kiwi":t.includes("Brave")?"Brave":t.includes("Firefox/")?"Firefox":t.includes("Chrome/")?"Chrome":t.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"},x=function(t=navigator.userAgent){return/Windows NT 11/i.test(t=t||"")?"Windows 11":/Windows NT 10/i.test(t)?"Windows 10":/Windows NT 6\.3/i.test(t)?"Windows 8.1":/Windows NT 6\.2/i.test(t)?"Windows 8":/Windows NT 6\.1/i.test(t)?"Windows 7":/Windows NT 6\.0/i.test(t)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(t)?"Windows XP":/Mac OS X 10[_\.]15/i.test(t)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(t)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(t)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(t)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(t)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(t)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"};var $=GM_info.script.name.toString(),M=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-E",$),e.setAttribute("bm-B","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-E")||"Blue Marble",n=t?.getAttribute("bm-B")||"",i=new Map;window.addEventListener("message",t=>{const{source:o,endpoint:s,blobID:r,blobData:a,blink:l}=t.data,c=Date.now()-l;if(console.groupCollapsed(`%c${e}%c: ${i.size} Recieved IMAGE message about blob "${r}"`,n,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,n,""),console.log(i),console.groupEnd(),"blue-marble"==o&&r&&a&&!s){const t=i.get(r);"function"==typeof t?t(a):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",r),i.delete(r)}});const o=window.fetch;window.fetch=async function(...t){const s=await o.apply(this,t),r=s.clone(),a=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",l=r.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${a}"`,n,""),r.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:a,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,n,"",t)});else if(l.includes("image/")&&!a.includes("openfreemap")&&!a.includes("maps")){const t=Date.now(),o=await r.blob();return console.log(`%c${e}%c: ${i.size} Sending IMAGE message about endpoint "${a}"`,n,""),new Promise(s=>{const l=crypto.randomUUID();i.set(l,t=>{s(new Response(t,{headers:r.headers,status:r.status,statusText:r.statusText})),console.log(`%c${e}%c: ${i.size} Processed blob "${l}"`,n,"")}),window.postMessage({source:"blue-marble",endpoint:a,blobID:l,blobData:o,blink:t})}).catch(o=>{const s=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,n,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,n,""),console.log(`Endpoint: ${a}\nThere are ${i.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(s/6e4)).padStart(2,"0")}:${String(Math.floor(s/1e3)%60).padStart(2,"0")}.${String(s%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",o),console.groupEnd()})}return s}});var T=`.bm-13{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.bm-1h{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-height:calc(100vh - 150px);max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-15{max-width:300px}.bm-1f{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-1f.bm-1a{cursor:grabbing}.bm-1h:has(.bm-1f.bm-1a){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-1f.bm-1a{pointer-events:auto}.bm-1g{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-1h h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-1f h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-1f div:has(h1){display:contents}.bm-19{margin:.5em 0}.bm-1h button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-1h button:hover,.bm-1h button:focus-visible{background-color:#1061e5}.bm-1h button:active,.bm-1h button:disabled{background-color:#2e97ff}.bm-1h button:disabled{text-decoration:line-through}.bm--{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm-17{vertical-align:middle}.bm-17 svg{width:50%;margin:0 auto;fill:#111}.bm-1h button.bm-14{background-color:unset}.bm-14.bm-M:hover,.bm-14.bm-M:focus{background-color:#ffffff2b}.bm-14.bm-M:active{background-color:#ffffff38}.bm-14.bm-N:hover,.bm-14.bm-N:focus{background-color:#0000002b}.bm-14.bm-N:active{background-color:#00000038}input[type=number].bm-11{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-11::-webkit-outer-spin-button,input[type=number].bm-11::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-18)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-18,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-U{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-1h textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-1h small{font-size:x-small;color:#d3d3d3}.bm-12{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-flex-center{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch}#bm-_ .bm-19:has(table){max-height:60vh;overflow:auto}#bm-_ table{table-layout:fixed;width:50ch;border-collapse:separate;border-spacing:0 .5em}#bm-_ tr{padding:.5em 0}.bm-X{display:block;border:thick double lightgray;width:fit-content;height:fit-content;padding:1ch}.bm-X button{padding:.75em .5ch}.bm-X svg{width:4ch;isolation:isolate}.bm-10{position:relative;top:.75em;left:.5ch}.bm-Q{position:relative;top:.75em;left:-3.5ch}.bm-R{position:relative;top:-.75em;left:-16ch;text-wrap:nowrap}.bm-S{display:block;width:100%;position:relative;right:18ch;top:.75em;text-align:right}.bm-T{display:block;width:100%;position:relative;left:-16ch;top:.75em;text-align:left}.bm-T:after{content:"/";position:absolute;left:-1.5ch;top:50%;transform:translateY(-50%)}#bm-_ tfoot{display:table-header-group}#bm-_ tfoot th{text-align:left}#bm-_ tfoot td{text-align:right;padding-left:1ch}`;GM_addStyle(T);var C,D="@font-face{font-family:'Roboto Mono';font-style:normal;font-weight:400;src:url(data:font/woff2;base64,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)format('woff2');}";D.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(D)):((C=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",C.rel="preload",C.as="style",C.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(C)),new class{constructor(){this.$t=null,this.Mt=null,this.Tt="#bm-h"}Ct(t){return this.Mt=t,this.$t=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.Tt)}),this}Dt(){return this.$t}observe(t,e=!1,n=!1){t.observe(this.Mt,{childList:e,subtree:n})}};var O=new r($,M),k=(new r($,M),new class{constructor(t,e,n){o(this,b),this.name=t,this.version=e,this.o=n,this.Ot="1.0.0",this.kt=null,this.Nt="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.ct=1e3,this.yt=3,this.vt=3,this.St=function(t){const e=v;e.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),e.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const n=new Map;for(const i of e){if(0==i.id||-2==i.id)continue;const e=i.rgb[0],o=i.rgb[1],s=i.rgb[2];for(let r=-t;r<=t;r++)for(let a=-t;a<=t;a++)for(let l=-t;l<=t;l++){const t=e+r,c=o+a,m=s+l;if(t<0||t>255||c<0||c>255||m<0||m>255)continue;const d=(255<<24|m<<16|c<<8|t)>>>0;n.has(d)||n.set(d,i.id)}}return{palette:e,ft:n}}(this.vt),this.Bt=null,this.It="",this.xt=[],this.wt=null,this.Lt=!0,this.Pt=null}async Gt(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.Ot,templates:{}}}async Ut(t,e,n){this.wt||(this.wt=await this.Gt(),console.log("Creating JSON...")),this.o.it(`Creating template at ${n.join(", ")}...`);const i=new S({displayName:e,ot:0,st:l(this.kt||0,this.Nt),file:t,coords:n}),{bt:o,gt:r}=await i.ht(this.ct,this.St);i.rt=o;const a={total:i.dt.total,colors:Object.fromEntries(i.dt.colors)};this.wt.templates[`${i.ot} ${i.st}`]={name:i.displayName,coords:n.join(", "),enabled:!0,pixels:a,tiles:r},this.xt=[],this.xt.push(i),this.o.it(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.wt.templates).length),console.log(this.wt),console.log(this.xt),console.log(JSON.stringify(this.wt)),await s(this,b,p).call(this)}Wt(){}async At(){this.wt||(this.wt=await this.Gt(),console.log("Creating JSON..."))}async _t(t,e){if(!this.Lt)return t;const n=this.ct*this.yt;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${e}"`);const i=this.xt;console.log(i),i.sort((t,e)=>t.ot-e.ot),console.log(i);const o=i.map(t=>{const n=Object.keys(t.rt).filter(t=>t.startsWith(e));if(0===n.length)return null;const i=n.map(e=>{const n=e.split(",");return{Ft:t,Xt:t.rt[e],lt:t.lt?.[e],Et:[n[0],n[1]],Ht:[n[2],n[3]]}});return i?.[0]}).filter(Boolean);console.log(o);const r=o?.length||0;if(console.log(`templateCount = ${r}`),!(r>0))return this.o.it(`Sleeping\nVersion: ${this.version}`),t;{const t=i.filter(t=>Object.keys(t.rt).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.dt.total||0),0),n=(new Intl.NumberFormat).format(t);this.o.it(`Displaying ${r} template${1==r?"":"s"}.\nTotal pixels: ${n}`)}const a=await createImageBitmap(t),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(a,0,0,n,n);const m=c.getImageData(0,0,n,n),d=new Uint32Array(m.data.buffer);for(const t of o){console.log("Template:"),console.log(t);let n=t.lt;const i=Number(t.Ht[0])*this.yt,o=Number(t.Ht[1])*this.yt;if(c.drawImage(t.Xt,i,o),!n){const e=c.getImageData(i,o,t.Xt.width,t.Xt.height);n=new Uint32Array(e.data.buffer)}const r=Date.now(),a=s(this,b,f).call(this,d,n,[i,o,t.Xt.width,t.Xt.height]);let l=0;const m=0;for(const[t,e]of a)t!=m&&(l+=e);console.log(`Finished calculating correct pixels for the tile ${e} in ${(Date.now()-r)/1e3} seconds!\nThere are ${l} correct pixels.`),t.Ft.dt.correct=a}return await l.convertToBlob({type:"image/png"})}Jt(t){console.log("Importing JSON..."),console.log(t),"BlueMarble"==t?.whoami&&s(this,b,g).call(this,t)}jt(t){this.Lt=t}}($,M,O)),N=new class{constructor(t){o(this,w),this.Rt=t,this.Yt=!1,this.Vt=[],this.zt=[]}qt(t){window.addEventListener("message",async e=>{const n=e.data,i=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const o=n.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",o),o){case"me":if(i.status&&"2"!=i.status?.toString()[0])return void t.nt("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(i.level)*Math.pow(30,.65),1/.65)-i.pixelsPainted);console.log(i.id),(i.id||0===i.id)&&console.log(l(i.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Rt.kt=i.id,t.Y("bm-p",`Droplets: ${(new Intl.NumberFormat).format(i.droplets)}`),t.Y("bm-i",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const o=n.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),a=new URLSearchParams(n.endpoint.split("?")[1]),c=[a.get("x"),a.get("y")];if(this.Vt.length&&(!o.length||!c.length))return void t.nt("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Vt=[...o,...c];const m=(s=o,r=c,[parseInt(s[0])%4*1e3+parseInt(r[0]),parseInt(s[1])%4*1e3+parseInt(r[1])]),d=document.querySelectorAll("span");for(const t of d)if(t.textContent.trim().includes(`${m[0]}, ${m[1]}`)){let e=document.querySelector("#bm-h");const n=`(Tl X: ${o[0]}, Tl Y: ${o[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-h",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let h=n.endpoint.split("/");h=[parseInt(h[h.length-2]),parseInt(h[h.length-1].replace(".png",""))];const u=n.blobID,b=n.blobData,p=Date.now(),g=await this.Rt._t(b,h);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:u,blobData:g,blink:n.blink});break;case"robots":this.Yt="false"==i.userscript?.toString().toLowerCase();break}var s,r})}async Kt(t){console.log("Sending heartbeat to telemetry server...");let e=GM_getValue("bmUserSettings","{}");if(e=JSON.parse(e),!e||!e.telemetry||!e.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const n=navigator.userAgent;let i=await s(this,w,y).call(this,n),o=s(this,w,x).call(this,n);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:e.uuid,version:t,browser:i,os:o}),onload:t=>{200!==t.status&&a("Failed to send heartbeat:",t.statusText)},onerror:t=>{a("Error sending heartbeat:",t)}})}}(k);O.h(N);var B=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(B),k.Jt(B);var I=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(I),console.log(Object.keys(I).length),0==Object.keys(I).length){const t=crypto.randomUUID();console.log(t),GM.setValue("bmUserSettings",JSON.stringify({uuid:t}))}if(setInterval(()=>N.Kt(M),18e5),console.log(`Telemetry is ${!(null==I?.telemetry)}`),null==I?.telemetry||I?.telemetry>1){const t=new r($,M);t.h(N),t.v({id:"bm-d",style:"top: 0px; left: 0px; width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; z-index: 9999;"}).v({id:"bm-7",style:"display: flex; flex-direction: column; align-items: center;"}).v({id:"bm-1",style:"margin-top: 10%;"}).O(1,{textContent:`${$} Telemetry`}).u().u().v({id:"bm-e",style:"max-width: 50%; overflow-y: auto; max-height: 80vh;"}).k().u().N().u().v({style:"width: fit-content; margin: auto; text-align: center;"}).j({id:"bm-8",textContent:"More Information"},(t,e)=>{e.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).u().u().N().u().v({style:"width: fit-content; margin: auto; text-align: center;"}).j({id:"bm-5",textContent:"Enable Telemetry",style:"margin-right: 2ch;"},(t,e)=>{e.onclick=()=>{const t=JSON.parse(GM_getValue("bmUserSettings","{}"));t.telemetry=1,GM.setValue("bmUserSettings",JSON.stringify(t));const e=document.getElementById("bm-d");e&&(e.style.display="none")}}).u().j({id:"bm-2",textContent:"Disable Telemetry"},(t,e)=>{e.onclick=()=>{const t=JSON.parse(GM_getValue("bmUserSettings","{}"));t.telemetry=0,GM.setValue("bmUserSettings",JSON.stringify(t));const e=document.getElementById("bm-d");e&&(e.style.display="none")}}).u().u().N().u().S({textContent:"We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the 'Disable' button, but keeping it on helps us improve features and reliability faster. Thank you for supporting the Blue Marble!"}).u().S({textContent:'You can disable telemetry by pressing the "Disable" button below.'}).u().u().u().p(document.body)}O.v({id:"bm-15",class:"bm-1h",style:"top: 10px; left: unset; right: 75px;"}).Z().j({class:"bm--",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.tt(e),e.ontouchend=()=>t.tt(e)}).u().v().u().u().v({class:"bm-U"}).v({class:"bm-19"}).D({class:"bm-1g",src:"data:image/png;base64,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"}).u().O(1,{textContent:$}).u().u().k().u().v({class:"bm-19"}).S({id:"bm-p",textContent:"Droplets:"}).u().S({id:"bm-i",textContent:"Next level in..."}).u().u().k().u().v({class:"bm-19"}).v({class:"bm-19"}).j({class:"bm-- bm-17",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.t?.Vt;e?.[0]?(t.Y("bm-v",e?.[0]||""),t.Y("bm-w",e?.[1]||""),t.Y("bm-x",e?.[2]||""),t.Y("bm-y",e?.[3]||"")):t.nt("Coordinates are malformed! Did you try clicking on the canvas first?")}}).u().V({type:"number",id:"bm-v",class:"bm-11",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",t=>{let e=(t.clipboardData||window.clipboardData).getData("text").split(" ").filter(t=>t).map(Number).filter(t=>!isNaN(t));if(4!==e.length)return;let n=selectAllCoordinateInputs(document);for(let t=0;t{e.onclick=()=>{e.disabled=!0,"shown"==e.dataset.buttonStatus?(t.t?.Rt?.jt(!1),e.dataset.buttonStatus="hidden",e.textContent="Enable",t.it("Disabled templates!")):(t.t?.Rt?.jt(!0),e.dataset.buttonStatus="shown",e.textContent="Disable",t.it("Enabled templates!")),e.disabled=!1}}).u().j({textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-15 button.bm-18"),n=document.querySelector("#bm-v");if(!n.checkValidity())return n.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-w");if(!i.checkValidity())return i.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-x");if(!o.checkValidity())return o.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-y");if(!s.checkValidity())return s.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(k.Ut(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(i.value),Number(o.value),Number(s.value)]),t.it("Drew to canvas!")):t.nt("No file selected!")}}).u().j({textContent:"Filter"},(t,e)=>{e.onclick=()=>function(){if(document.querySelector("#bm-_"))return void O.nt("Color Filter window already exists!");const t=new r($,M);t.v({id:"bm-_",class:"bm-1h"}).Z().j({class:"bm--",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.tt(e),e.ontouchend=()=>t.tt(e)}).u().v().u().j({class:"bm--",textContent:"🞪","aria-label":'Close window "Color Filter"'},(t,e)=>{e.onclick=()=>{document.querySelector("#bm-_")?.remove()},e.ontouchend=()=>{document.querySelector("#bm-_")?.remove()}}).u().u().v({class:"bm-U"}).v({class:"bm-19"}).O(1,{textContent:"Color Filter"}).u().u().k().u().v({class:"bm-19 bm-12",style:"width: fit-content;"}).j({textContent:"Select All"},(t,e)=>{e.onclick=()=>{}}).u().j({textContent:"Unselect All"},(t,e)=>{e.onclick=()=>{}}).u().u().u().u().p(document.body),t.et("#bm-_.bm-1h","#bm-_ .bm-1f");const e=document.querySelector("#bm-_ .bm-U"),{palette:n,ft:i}=k.St;let o=0,s=0;const a=new Map,l=new Map;for(const t of k.xt){const e=t.dt?.total??0,n=t.dt?.colors??new Map,i=t.dt?.correct??new Map;o+=e??0;for(const[t,e]of i){const n=Number(e)||0;s+=n;const i=a.get(t)??0;a.set(t,i+n)}for(const[t,e]of n){const n=Number(e)||0,i=l.get(t)??0;l.set(t,i+n)}}const c=new r($,M);c.v({class:"bm-19"}).U({class:"bm-19"}).W().O(2,{textContent:"Pixels In Templates By Palette Color"}).u().u().F().X().H({textContent:"Total Correct",scope:"row"}).u().J({textContent:s.toString()}).u().u().X().H({textContent:"Total Pixels",scope:"row"}).u().J({textContent:o.toString()}).u().u().u().A({class:"bm-13"}).X().H({textContent:"Hide Color",scope:"col"}).u().H({textContent:"ID",scope:"col"}).u().H({textContent:"Is Premium",scope:"col"}).u().H({textContent:"Name",scope:"col"}).u().H({textContent:"Correct Pixels",scope:"col"}).u().H({textContent:"Total Pixels",scope:"col"}).u().u().u();for(const t of n){const e=d(t.rgb),n=1.05/(e+.05)>(e+.05)/.05?"white":"black",i="white"==n?"bm-M":"bm-N";c.X().J().v({class:"bm-X",style:`background-color: rgb(${t.rgb?.map(t=>Number(t)||0).join(",")});`}).j({class:"bm-14 "+i,"aria-label":`Hide the color ${t.name||"color"} on templates`,innerHTML:``}).u().u().u().J().M({class:"bm-10",textContent:`#${t.id}`}).u().u().J().M({class:"bm-Q",textContent:t.premium?"★":""}).u().u().J().M({class:"bm-R",textContent:t.name}).u().u().J().M({class:"bm-S",textContent:m(String(a.get(t.id)??"???"),7)}).u().u().J().M({class:"bm-T",textContent:m(String(l.get(t.id)??"0"),7)}).u().u().u()}function m(t,e){if(t.length<=e)return t;const n=Math.floor((e-3)/2);return t.slice(0,n)+"…"+t.slice(t.length-n)}c.p(e)}()}).u().u().v({class:"bm-19"}).K({id:O.i,placeholder:`Status: Sleeping...\nVersion: ${M}`,readOnly:!0}).u().u().v({class:"bm-19 bm-12",style:"margin-bottom: 0;"}).v({class:"bm-12"}).j({class:"bm--",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).u().j({class:"bm--",innerHTML:"🌐",title:"Official Blue Marble Website"},(t,e)=>{e.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).u().u().$({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).u().u().u().u().u().p(document.body),O.et("#bm-15.bm-1h","#bm-15 .bm-1f"),N.qt(O),new MutationObserver((t,e)=>{const n=document.querySelector("#color-1");if(!n)return;let i=document.querySelector("#bm-t");if(!i){i=document.createElement("button"),i.id="bm-t",i.textContent="Move ↑",i.className="btn btn-soft",i.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=n.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(i)}}).observe(document.body,{childList:!0,subtree:!0}),function(...t){(0,console.log)(...t)}(`%c${$}%c (${M}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file diff --git a/dist/BlueMarble.user.css b/dist/BlueMarble.user.css index 15e0be5..dcd301b 100644 --- a/dist/BlueMarble.user.css +++ b/dist/BlueMarble.user.css @@ -1 +1 @@ -.bm-18{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-Y{max-width:300px}.bm-16{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-16.bm-11{cursor:grabbing}.bm-18:has(.bm-16.bm-11){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-16.bm-11{pointer-events:auto}.bm-17{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-18 h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-16 h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-16 div:has(h1){display:contents}.bm-10{margin:.5em 0}.bm-18 button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-18 button:hover,.bm-18 button:focus-visible{background-color:#1061e5}.bm-18 button:active,.bm-18 button:disabled{background-color:#2e97ff}.bm-18 button:disabled{text-decoration:line-through}.bm-U{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm--{vertical-align:middle}.bm-- svg{width:50%;margin:0 auto;fill:#111}input[type=number].bm-W{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-W::-webkit-outer-spin-button,input[type=number].bm-W::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-_)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-_,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-P{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-18 textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-18 small{font-size:x-small;color:#d3d3d3}.bm-X{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-flex-center{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch} +.bm-13{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.bm-1h{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-height:calc(100vh - 150px);max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-15{max-width:300px}.bm-1f{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-1f.bm-1a{cursor:grabbing}.bm-1h:has(.bm-1f.bm-1a){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-1f.bm-1a{pointer-events:auto}.bm-1g{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-1h h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-1f h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-1f div:has(h1){display:contents}.bm-19{margin:.5em 0}.bm-1h button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-1h button:hover,.bm-1h button:focus-visible{background-color:#1061e5}.bm-1h button:active,.bm-1h button:disabled{background-color:#2e97ff}.bm-1h button:disabled{text-decoration:line-through}.bm--{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm-17{vertical-align:middle}.bm-17 svg{width:50%;margin:0 auto;fill:#111}.bm-1h button.bm-14{background-color:unset}.bm-14.bm-M:hover,.bm-14.bm-M:focus{background-color:#ffffff2b}.bm-14.bm-M:active{background-color:#ffffff38}.bm-14.bm-N:hover,.bm-14.bm-N:focus{background-color:#0000002b}.bm-14.bm-N:active{background-color:#00000038}input[type=number].bm-11{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-11::-webkit-outer-spin-button,input[type=number].bm-11::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-18)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-18,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-U{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-1h textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-1h small{font-size:x-small;color:#d3d3d3}.bm-12{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-flex-center{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch}#bm-_ .bm-19:has(table){max-height:60vh;overflow:auto}#bm-_ table{table-layout:fixed;width:50ch;border-collapse:separate;border-spacing:0 .5em}#bm-_ tr{padding:.5em 0}.bm-X{display:block;border:thick double lightgray;width:fit-content;height:fit-content;padding:1ch}.bm-X button{padding:.75em .5ch}.bm-X svg{width:4ch;isolation:isolate}.bm-10{position:relative;top:.75em;left:.5ch}.bm-Q{position:relative;top:.75em;left:-3.5ch}.bm-R{position:relative;top:-.75em;left:-16ch;text-wrap:nowrap}.bm-S{display:block;width:100%;position:relative;right:18ch;top:.75em;text-align:right}.bm-T{display:block;width:100%;position:relative;left:-16ch;top:.75em;text-align:left}.bm-T:after{content:"/";position:absolute;left:-1.5ch;top:50%;transform:translateY(-50%)}#bm-_ tfoot{display:table-header-group}#bm-_ tfoot th{text-align:left}#bm-_ tfoot td{text-align:right;padding-left:1ch} diff --git a/dist/BlueMarble.user.js b/dist/BlueMarble.user.js index 9b8f780..cd2151c 100644 --- a/dist/BlueMarble.user.js +++ b/dist/BlueMarble.user.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.179 +// @version 0.88.207 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine @@ -28,4 +28,4 @@ // License --> https://www.mozilla.org/en-US/MPL/2.0/ // Donate --> https://ko-fi.com/swingthevine -(()=>{var e,t,n,i=e=>{throw TypeError(e)},o=(e,t,n)=>t.has(e)?i("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),s=(e,t,n)=>(((e,t)=>{t.has(e)||i("Cannot access private method")})(e,t),n),a=class{constructor(t,n){o(this,e),this.name=t,this.version=n,this.t=null,this.i="bm-o",this.o=null,this.l=null,this.m=[]}u(e){this.t=e}h(){return this.m.length>0&&(this.l=this.m.pop()),this}p(e){e?.appendChild(this.o),this.o=null,this.l=null,this.m=[]}v(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"div",{},n)),this}$(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"p",{},n)),this}S(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"small",{},n)),this}M(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"details",{},n)),this}T(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"summary",{},n)),this}D(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"img",{},n)),this}O(n,i={},o=()=>{}){return o(this,s(this,e,t).call(this,"h"+n,{},i)),this}C(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"hr",{},n)),this}k(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"br",{},n)),this}N(n={},i=()=>{}){const o=s(this,e,t).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const a=s(this,e,t).call(this,"input",{type:"checkbox"},n);return o.insertBefore(a,o.firstChild),this.h(),i(this,o,a),this}B(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"button",{},n)),this}I(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const a={textContent:"?",className:"bm-D",onclick:()=>{this.L(this.i,o)}};return i(this,s(this,e,t).call(this,"button",a,n)),this}P(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"input",{},n)),this}G(n={},i=()=>{}){const o=n.textContent??"";delete n.textContent;const a=s(this,e,t).call(this,"div"),r=s(this,e,t).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true",style:"display: none !important; visibility: hidden !important; position: absolute !important; left: -9999px !important; width: 0 !important; height: 0 !important; opacity: 0 !important;"},n);this.h();const l=s(this,e,t).call(this,"button",{textContent:o});return this.h(),this.h(),l.addEventListener("click",()=>{r.click()}),r.addEventListener("change",()=>{l.style.maxWidth=`${l.offsetWidth}px`,r.files.length>0?l.textContent=r.files[0].name:l.textContent=o}),i(this,a,r,l),this}W(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"textarea",{},n)),this}U(n={},i=()=>{}){return i(this,s(this,e,t).call(this,"div",{class:"bm-16"},n)),this}L(e,t,n=!1){const i=document.getElementById(e.replace(/^#/,""));i&&(i instanceof HTMLInputElement?i.value=t:n?i.textContent=t:i.innerHTML=t)}_(e){if(e.disabled)return;e.disabled=!0,e.style.textDecoration="none";const t=e.closest(".bm-18"),n=e.closest(".bm-16"),i=t.querySelector("h1"),o=t.querySelector(".bm-P");if("expanded"==e.dataset.buttonStatus){o.style.height=o.scrollHeight+"px",t.style.width=t.scrollWidth+"px",o.style.height="0",o.addEventListener("transitionend",function t(){o.style.display="none",e.disabled=!1,e.style.textDecoration="",o.removeEventListener("transitionend",t)});const n=i.cloneNode(!0),s=n.textContent;e.nextElementSibling.appendChild(n),e.textContent="▶",e.dataset.buttonStatus="collapsed",e.ariaLabel=`Unminimize window "${s}"`}else{const i=n.querySelector("h1"),s=i.textContent;i.remove(),o.style.display="",o.style.height="0",t.style.width="",o.style.height=o.scrollHeight+"px",o.addEventListener("transitionend",function t(){o.style.height="",e.disabled=!1,e.style.textDecoration="",o.removeEventListener("transitionend",t)}),e.textContent="▼",e.dataset.buttonStatus="expanded",e.ariaLabel=`Minimize window "${s}"`}}A(e,t){if(e=document.querySelector(e),t=document.querySelector(t),!e||!t)return void this.F(`Can not drag! ${e?"":"moveMe"} ${e||t?"":"and "}${t?"":"iMoveThings "}was not found!`);let n,i=!1,o=0,s=null,a=0,r=0,l=0,c=0,m=null;const d=()=>{if(i){const t=Math.abs(a-l),n=Math.abs(r-c);(t>.5||n>.5)&&(a=l,r=c,e.style.transform=`translate(${a}px, ${r}px)`,e.style.left="0px",e.style.top="0px",e.style.right=""),s=requestAnimationFrame(d)}},u=(u,g)=>{i=!0,m=e.getBoundingClientRect(),n=u-m.left,o=g-m.top;const f=window.getComputedStyle(e).transform;if(f&&"none"!==f){const e=new DOMMatrix(f);a=e.m41,r=e.m42}else a=m.left,r=m.top;l=a,c=r,document.body.style.userSelect="none",t.classList.add("bm-11"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",h),document.addEventListener("touchend",h),document.addEventListener("touchcancel",h),s&&cancelAnimationFrame(s),d()},h=()=>{i=!1,s&&(cancelAnimationFrame(s),s=null),document.body.style.userSelect="",t.classList.remove("bm-11"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",h),document.removeEventListener("touchend",h),document.removeEventListener("touchcancel",h)},b=e=>{i&&m&&(l=e.clientX-n,c=e.clientY-o)},p=e=>{if(i&&m){const t=e.touches[0];if(!t)return;l=t.clientX-n,c=t.clientY-o,e.preventDefault()}};t.addEventListener("mousedown",function(e){e.preventDefault(),u(e.clientX,e.clientY)}),t.addEventListener("touchstart",function(e){const t=e?.touches?.[0];t&&(u(t.clientX,t.clientY),e.preventDefault())},{passive:!1})}X(e){(0,console.info)(`${this.name}: ${e}`),this.L(this.i,"Status: "+e,!0)}F(e){(0,console.error)(`${this.name}: ${e}`),this.L(this.i,"Error: "+e,!0)}};function r(...e){(0,console.error)(...e)}function l(e,t){if(0===e)return t[0];let n="";const i=t.length;for(;e>0;)n=t[e%i]+n,e=Math.floor(e/i);return n}function c(e){let t="";for(let n=0;n0==t?e:e[0].toUpperCase()+e.slice(1)).join("")]=n;else if(t.startsWith("aria")){const i=t.slice(5).split("-").map((e,t)=>0==t?e:e[0].toUpperCase()+e.slice(1)).join("");e["aria"+i[0].toUpperCase()+i.slice(1)]=n}else e[t]=n};var d,u,h,b,p,g,f,w,y,x=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],v=class{constructor({displayName:e="My template",J:t=0,j:n="",url:i="",file:s=null,coords:a=null,R:r=null,Y:l={},V:c=1e3}={}){o(this,d),this.displayName=e,this.J=t,this.j=n,this.url=i,this.file=s,this.coords=a,this.R=r,this.Y=l,this.V=c,this.H={total:0,colors:new Map}}async q(e,t){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),i=n.width,o=n.height;this.V=e;const a={},r={},l=new OffscreenCanvas(this.V,this.V),m=l.getContext("2d",{K:!0});l.width=i,l.height=o,m.imageSmoothingEnabled=!1,m.drawImage(n,0,0);let h=Date.now();const b=s(this,d,u).call(this,m.getImageData(0,0,i,o),t);console.log(`Calculating total pixels took ${(Date.now()-h)/1e3} seconds`);let p=0;for(const[e,t]of b)0!=e&&(p+=t);this.H={total:p,colors:b},h=Date.now();const g=new OffscreenCanvas(3,3),f=g.getContext("2d");f.clearRect(0,0,3,3),f.fillStyle="white",f.fillRect(1,1,1,1);for(let e=this.coords[3];e>>24==0?0:o.get(t)??-2;const a=s.get(i);s.set(i,a?a+1:1)}return console.log(s),s},h=new WeakSet,b=async function(){GM.setValue("bmTemplates",JSON.stringify(this.ne))},p=async function(e){console.log("Parsing BlueMarble...");const t=e.templates;if(console.log(`BlueMarble length: ${Object.keys(t).length}`),Object.keys(t).length>0)for(const e in t){const n=e,i=t[e];if(console.log(`Template Key: ${n}`),t.hasOwnProperty(e)){const e=n.split(" "),t=Number(e?.[0]),o=e?.[1]||"0",s=i.name||`Template ${t||""}`,a={total:i.pixels.total,colors:new Map(Object.entries(i.pixels.colors).map(([e,t])=>[Number(e),t]))},r=i.tiles,l={},c={},d=this.V*this.ie;for(const e in r)if(console.log(e),r.hasOwnProperty(e)){const t=m(r[e]),n=new Blob([t],{type:"image/png"}),i=await createImageBitmap(n);l[e]=i;const o=new OffscreenCanvas(d,d).getContext("2d");o.drawImage(i,0,0);const s=o.getImageData(0,0,i.width,i.height);c[e]=new Uint32Array(s.data.buffer)}const u=new v({displayName:s,J:t||this.oe?.length||0,j:o||""});u.H=a,u.R=l,u.Y=c,this.oe.push(u),console.log(this.oe),console.log("^^^ This ^^^")}}},g=function(e,t,n){const i=this.ie,o=this.V*i,s=n[0],a=n[1],r=n[2],l=n[3],c=this.se,{palette:m,te:d}=this.ae,u=new Map;for(let n=1;n>>24&255)<=c||(i>>>24&255)<=c)continue;const h=d.get(i)??-2,b=d.get(m)??-2;if(h!=b)continue;const p=u.get(b);u.set(b,p?p+1:1)}return console.log("List of template pixels that match the tile:"),console.log(u),u},f=new WeakSet,w=async function(e=navigator.userAgent){return(e=e||"").includes("OPR/")||e.includes("Opera")?"Opera":e.includes("Edg/")?"Edge":e.includes("Vivaldi")?"Vivaldi":e.includes("YaBrowser")?"Yandex":e.includes("Kiwi")?"Kiwi":e.includes("Brave")?"Brave":e.includes("Firefox/")?"Firefox":e.includes("Chrome/")?"Chrome":e.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"},y=function(e=navigator.userAgent){return/Windows NT 11/i.test(e=e||"")?"Windows 11":/Windows NT 10/i.test(e)?"Windows 10":/Windows NT 6\.3/i.test(e)?"Windows 8.1":/Windows NT 6\.2/i.test(e)?"Windows 8":/Windows NT 6\.1/i.test(e)?"Windows 7":/Windows NT 6\.0/i.test(e)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(e)?"Windows XP":/Mac OS X 10[_\.]15/i.test(e)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(e)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(e)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(e)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(e)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(e)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(e)?"macOS":/Android/i.test(e)?"Android":/iPhone|iPad|iPod/i.test(e)?"iOS":/Linux/i.test(e)?"Linux":"Unknown"};var $=GM_info.script.name.toString(),S=GM_info.script.version.toString();!function(e){const t=document.createElement("script");t.setAttribute("bm-E",$),t.setAttribute("bm-B","color: cornflowerblue;"),t.textContent=`(${e})();`,document.documentElement?.appendChild(t),t.remove()}(()=>{const e=document.currentScript,t=e?.getAttribute("bm-E")||"Blue Marble",n=e?.getAttribute("bm-B")||"",i=new Map;window.addEventListener("message",e=>{const{source:o,endpoint:s,blobID:a,blobData:r,blink:l}=e.data,c=Date.now()-l;if(console.groupCollapsed(`%c${t}%c: ${i.size} Recieved IMAGE message about blob "${a}"`,n,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,n,""),console.log(i),console.groupEnd(),"blue-marble"==o&&a&&r&&!s){const e=i.get(a);"function"==typeof e?e(r):function(...e){(0,console.warn)(...e)}(`%c${t}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",a),i.delete(a)}});const o=window.fetch;window.fetch=async function(...e){const s=await o.apply(this,e),a=s.clone(),r=(e[0]instanceof Request?e[0]?.url:e[0])||"ignore",l=a.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${t}%c: Sending JSON message about endpoint "${r}"`,n,""),a.json().then(e=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:e},"*")}).catch(e=>{console.error(`%c${t}%c: Failed to parse JSON: `,n,"",e)});else if(l.includes("image/")&&!r.includes("openfreemap")&&!r.includes("maps")){const e=Date.now(),o=await a.blob();return console.log(`%c${t}%c: ${i.size} Sending IMAGE message about endpoint "${r}"`,n,""),new Promise(s=>{const l=crypto.randomUUID();i.set(l,e=>{s(new Response(e,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${t}%c: ${i.size} Processed blob "${l}"`,n,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:l,blobData:o,blink:e})}).catch(o=>{const s=Date.now();console.error(`%c${t}%c: Failed to Promise blob!`,n,""),console.groupCollapsed(`%c${t}%c: Details of failed blob Promise:`,n,""),console.log(`Endpoint: ${r}\nThere are ${i.size} blobs processing...\nBlink: ${e.toLocaleString()}\nTime Since Blink: ${String(Math.floor(s/6e4)).padStart(2,"0")}:${String(Math.floor(s/1e3)%60).padStart(2,"0")}.${String(s%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",o),console.groupEnd()})}return s}});var M=GM_getResourceText("CSS-BM-File");GM_addStyle(M);var T,D="robotoMonoInjectionPoint";D.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(D)):((T=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",T.rel="preload",T.as="style",T.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(T)),new class{constructor(){this.re=null,this.le=null,this.ce="#bm-h"}me(e){return this.le=e,this.re=new MutationObserver(e=>{for(const t of e)for(const e of t.addedNodes)e instanceof HTMLElement&&e.matches?.(this.ce)}),this}de(){return this.re}observe(e,t=!1,n=!1){e.observe(this.le,{childList:t,subtree:n})}};var O=new a($,S),C=(new a($,S),new class{constructor(e,t,n){o(this,h),this.name=e,this.version=t,this.o=n,this.ue="1.0.0",this.he=null,this.be="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.V=1e3,this.ie=3,this.se=3,this.ae=function(e){const t=x;t.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),t.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const n=new Map;for(const i of t){if(0==i.id||-2==i.id)continue;const t=i.rgb[0],o=i.rgb[1],s=i.rgb[2];for(let a=-e;a<=e;a++)for(let r=-e;r<=e;r++)for(let l=-e;l<=e;l++){const e=t+a,c=o+r,m=s+l;if(e<0||e>255||c<0||c>255||m<0||m>255)continue;const d=(255<<24|m<<16|c<<8|e)>>>0;n.has(d)||n.set(d,i.id)}}return{palette:t,te:n}}(this.se),this.pe=null,this.ge="",this.oe=[],this.ne=null,this.fe=!0,this.we=null}async ye(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.ue,templates:{}}}async xe(e,t,n){this.ne||(this.ne=await this.ye(),console.log("Creating JSON...")),this.o.X(`Creating template at ${n.join(", ")}...`);const i=new v({displayName:t,J:0,j:l(this.he||0,this.be),file:e,coords:n}),{Z:o,ee:a}=await i.q(this.V,this.ae);i.R=o;const r={total:i.H.total,colors:Object.fromEntries(i.H.colors)};this.ne.templates[`${i.J} ${i.j}`]={name:i.displayName,coords:n.join(", "),enabled:!0,pixels:r,tiles:a},this.oe=[],this.oe.push(i),this.o.X(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.ne.templates).length),console.log(this.ne),console.log(this.oe),console.log(JSON.stringify(this.ne)),await s(this,h,b).call(this)}ve(){}async $e(){this.ne||(this.ne=await this.ye(),console.log("Creating JSON..."))}async Se(e,t){if(!this.fe)return e;const n=this.V*this.ie;t=t[0].toString().padStart(4,"0")+","+t[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${t}"`);const i=this.oe;console.log(i),i.sort((e,t)=>e.J-t.J),console.log(i);const o=i.map(e=>{const n=Object.keys(e.R).filter(e=>e.startsWith(t));if(0===n.length)return null;const i=n.map(t=>{const n=t.split(",");return{Me:e,Te:e.R[t],Y:e.Y?.[t],De:[n[0],n[1]],Oe:[n[2],n[3]]}});return i?.[0]}).filter(Boolean);console.log(o);const a=o?.length||0;if(console.log(`templateCount = ${a}`),!(a>0))return this.o.X(`Sleeping\nVersion: ${this.version}`),e;{const e=i.filter(e=>Object.keys(e.R).filter(e=>e.startsWith(t)).length>0).reduce((e,t)=>e+(t.H.total||0),0),n=(new Intl.NumberFormat).format(e);this.o.X(`Displaying ${a} template${1==a?"":"s"}.\nTotal pixels: ${n}`)}const r=await createImageBitmap(e),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(r,0,0,n,n);const m=c.getImageData(0,0,n,n),d=new Uint32Array(m.data.buffer);for(const e of o){console.log("Template:"),console.log(e);let n=e.Y;const i=Number(e.Oe[0])*this.ie,o=Number(e.Oe[1])*this.ie;if(c.drawImage(e.Te,i,o),!n){const t=c.getImageData(i,o,e.Te.width,e.Te.height);n=new Uint32Array(t.data.buffer)}const a=Date.now(),r=s(this,h,g).call(this,d,n,[i,o,e.Te.width,e.Te.height]);let l=0;const m=0;for(const[e,t]of r)e!=m&&(l+=t);console.log(`Finished calculating correct pixels for the tile ${t} in ${(Date.now()-a)/1e3} seconds!\nThere are ${l} correct pixels.`),e.Me.H.correct=r}return await l.convertToBlob({type:"image/png"})}Ce(e){console.log("Importing JSON..."),console.log(e),"BlueMarble"==e?.whoami&&s(this,h,p).call(this,e)}ke(e){this.fe=e}}($,S,O)),k=new class{constructor(e){o(this,f),this.Ne=e,this.Be=!1,this.Ie=[],this.Le=[]}Pe(e){window.addEventListener("message",async t=>{const n=t.data,i=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const o=n.endpoint?.split("?")[0].split("/").filter(e=>e&&isNaN(Number(e))).filter(e=>e&&!e.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",o),o){case"me":if(i.status&&"2"!=i.status?.toString()[0])return void e.F("You are not logged in!\nCould not fetch userdata.");const t=Math.ceil(Math.pow(Math.floor(i.level)*Math.pow(30,.65),1/.65)-i.pixelsPainted);console.log(i.id),(i.id||0===i.id)&&console.log(l(i.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Ne.he=i.id,e.L("bm-p",`Droplets: ${(new Intl.NumberFormat).format(i.droplets)}`),e.L("bm-i",`Next level in ${(new Intl.NumberFormat).format(t)} pixel${1==t?"":"s"}`);break;case"pixel":const o=n.endpoint.split("?")[0].split("/").filter(e=>e&&!isNaN(Number(e))),r=new URLSearchParams(n.endpoint.split("?")[1]),c=[r.get("x"),r.get("y")];if(this.Ie.length&&(!o.length||!c.length))return void e.F("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Ie=[...o,...c];const m=(s=o,a=c,[parseInt(s[0])%4*1e3+parseInt(a[0]),parseInt(s[1])%4*1e3+parseInt(a[1])]),d=document.querySelectorAll("span");for(const e of d)if(e.textContent.trim().includes(`${m[0]}, ${m[1]}`)){let t=document.querySelector("#bm-h");const n=`(Tl X: ${o[0]}, Tl Y: ${o[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;t?t.textContent=n:(t=document.createElement("span"),t.id="bm-h",t.textContent=n,t.style="margin-left: calc(var(--spacing)*3); font-size: small;",e.parentNode.parentNode.insertAdjacentElement("afterend",t))}break;case"tiles":let u=n.endpoint.split("/");u=[parseInt(u[u.length-2]),parseInt(u[u.length-1].replace(".png",""))];const h=n.blobID,b=n.blobData,p=Date.now(),g=await this.Ne.Se(b,u);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:h,blobData:g,blink:n.blink});break;case"robots":this.Be="false"==i.userscript?.toString().toLowerCase();break}var s,a})}async Ge(e){console.log("Sending heartbeat to telemetry server...");let t=GM_getValue("bmUserSettings","{}");if(t=JSON.parse(t),!t||!t.telemetry||!t.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const n=navigator.userAgent;let i=await s(this,f,w).call(this,n),o=s(this,f,y).call(this,n);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:t.uuid,version:e,browser:i,os:o}),onload:e=>{200!==e.status&&r("Failed to send heartbeat:",e.statusText)},onerror:e=>{r("Error sending heartbeat:",e)}})}}(C);O.u(k);var N=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(N),C.Ce(N);var B=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(B),console.log(Object.keys(B).length),0==Object.keys(B).length){const e=crypto.randomUUID();console.log(e),GM.setValue("bmUserSettings",JSON.stringify({uuid:e}))}if(setInterval(()=>k.Ge(S),18e5),console.log(`Telemetry is ${!(null==B?.telemetry)}`),null==B?.telemetry||B?.telemetry>1){const e=new a($,S);e.u(k),e.v({id:"bm-d",style:"top: 0px; left: 0px; width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; z-index: 9999;"}).v({id:"bm-7",style:"display: flex; flex-direction: column; align-items: center;"}).v({id:"bm-1",style:"margin-top: 10%;"}).O(1,{textContent:`${$} Telemetry`}).h().h().v({id:"bm-e",style:"max-width: 50%; overflow-y: auto; max-height: 80vh;"}).C().h().k().h().v({style:"width: fit-content; margin: auto; text-align: center;"}).B({id:"bm-8",textContent:"More Information"},(e,t)=>{t.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).h().h().k().h().v({style:"width: fit-content; margin: auto; text-align: center;"}).B({id:"bm-5",textContent:"Enable Telemetry",style:"margin-right: 2ch;"},(e,t)=>{t.onclick=()=>{const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=1,GM.setValue("bmUserSettings",JSON.stringify(e));const t=document.getElementById("bm-d");t&&(t.style.display="none")}}).h().B({id:"bm-2",textContent:"Disable Telemetry"},(e,t)=>{t.onclick=()=>{const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=0,GM.setValue("bmUserSettings",JSON.stringify(e));const t=document.getElementById("bm-d");t&&(t.style.display="none")}}).h().h().k().h().$({textContent:"We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the 'Disable' button, but keeping it on helps us improve features and reliability faster. Thank you for supporting the Blue Marble!"}).h().$({textContent:'You can disable telemetry by pressing the "Disable" button below.'}).h().h().h().p(document.body)}O.v({id:"bm-Y",class:"bm-18",style:"top: 10px; left: unset; right: 75px;"}).U().B({class:"bm-U",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(e,t)=>{t.onclick=()=>e._(t),t.ontouchend=()=>e._(t)}).h().v().h().h().v({class:"bm-P"}).v({class:"bm-10"}).D({class:"bm-17",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"}).h().O(1,{textContent:$}).h().h().C().h().v({class:"bm-10"}).$({id:"bm-p",textContent:"Droplets:"}).h().$({id:"bm-i",textContent:"Next level in..."}).h().h().C().h().v({class:"bm-10"}).v({class:"bm-10"}).B({class:"bm-U bm--",style:"margin-top: 0;",innerHTML:''},(e,t)=>{t.onclick=()=>{const t=e.t?.Ie;t?.[0]?(e.L("bm-v",t?.[0]||""),e.L("bm-w",t?.[1]||""),e.L("bm-x",t?.[2]||""),e.L("bm-y",t?.[3]||"")):e.F("Coordinates are malformed! Did you try clicking on the canvas first?")}}).h().P({type:"number",id:"bm-v",class:"bm-W",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(e,t)=>{t.addEventListener("paste",e=>{let t=(e.clipboardData||window.clipboardData).getData("text").split(" ").filter(e=>e).map(Number).filter(e=>!isNaN(e));if(4!==t.length)return;let n=selectAllCoordinateInputs(document);for(let e=0;e{t.onclick=()=>{t.disabled=!0,"shown"==t.dataset.buttonStatus?(e.t?.Ne?.ke(!1),t.dataset.buttonStatus="hidden",t.textContent="Enable",e.X("Disabled templates!")):(e.t?.Ne?.ke(!0),t.dataset.buttonStatus="shown",t.textContent="Disable",e.X("Enabled templates!")),t.disabled=!1}}).h().B({textContent:"Create"},(e,t)=>{t.onclick=()=>{const t=document.querySelector("#bm-Y button.bm-_"),n=document.querySelector("#bm-v");if(!n.checkValidity())return n.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-w");if(!i.checkValidity())return i.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-x");if(!o.checkValidity())return o.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-y");if(!s.checkValidity())return s.reportValidity(),void e.F("Coordinates are malformed! Did you try clicking on the canvas first?");t?.files[0]?(C.xe(t.files[0],t.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(i.value),Number(o.value),Number(s.value)]),e.X("Drew to canvas!")):e.F("No file selected!")}}).h().B({textContent:"Filter"},(e,t)=>{t.onclick=()=>function(){if(document.querySelector("#bm-V"))return void O.F("Color Filter window already exists!");const e=new a($,S);e.v({id:"bm-V",class:"bm-18"}).U().B({class:"bm-U",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(e,t)=>{t.onclick=()=>e._(t),t.ontouchend=()=>e._(t)}).h().v().h().B({class:"bm-U",textContent:"🞪","aria-label":'Close window "Color Filter"'},(e,t)=>{t.onclick=()=>{document.querySelector("#bm-V")?.remove()},t.ontouchend=()=>{document.querySelector("#bm-V")?.remove()}}).h().h().v({class:"bm-P"}).v({class:"bm-10"}).O(1,{textContent:"Color Filter"}).h().h().C().h().v({class:"bm-10 bm-X",style:"width: fit-content;"}).B({textContent:"Select All"},(e,t)=>{t.onclick=()=>{}}).h().B({textContent:"Unselect All"},(e,t)=>{t.onclick=()=>{}}).h().h().v().h().h().h().p(document.body),e.A("#bm-V.bm-18","#bm-V .bm-16");const t=document.querySelector("#bm-V .bm-P"),{palette:n,te:i}=C.ae,o=new a($,S);o.v({id:"bm-K",class:"bm-10"});for(const e of n)o.v({class:"bm-10"}).$({textContent:`Color ID: ${e.id?.toString()?.padStart(2,"0")}, Name: ${e.name}`}).h().h();o.p(t)}()}).h().h().v({class:"bm-10"}).W({id:O.i,placeholder:`Status: Sleeping...\nVersion: ${S}`,readOnly:!0}).h().h().v({class:"bm-10 bm-X",style:"margin-bottom: 0;"}).v({class:"bm-X"}).B({class:"bm-U",innerHTML:"🎨",title:"Template Color Converter"},(e,t)=>{t.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).h().B({class:"bm-U",innerHTML:"🌐",title:"Official Blue Marble Website"},(e,t)=>{t.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).h().h().S({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).h().h().h().h().h().p(document.body),O.A("#bm-Y.bm-18","#bm-Y .bm-16"),k.Pe(O),new MutationObserver((e,t)=>{const n=document.querySelector("#color-1");if(!n)return;let i=document.querySelector("#bm-t");if(!i){i=document.createElement("button"),i.id="bm-t",i.textContent="Move ↑",i.className="btn btn-soft",i.onclick=function(){const e=this.parentNode.parentNode.parentNode.parentNode,t="Move ↑"==this.textContent;e.parentNode.className=e.parentNode.className.replace(t?"bottom":"top",t?"top":"bottom"),e.style.borderTopLeftRadius=t?"0px":"var(--radius-box)",e.style.borderTopRightRadius=t?"0px":"var(--radius-box)",e.style.borderBottomLeftRadius=t?"var(--radius-box)":"0px",e.style.borderBottomRightRadius=t?"var(--radius-box)":"0px",this.textContent=t?"Move ↓":"Move ↑"};const e=n.parentNode.parentNode.parentNode.parentNode.querySelector("h2");e.parentNode?.appendChild(i)}}).observe(document.body,{childList:!0,subtree:!0}),function(...e){(0,console.log)(...e)}(`%c${$}%c (${S}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file +(()=>{var t,e,n,i=t=>{throw TypeError(t)},o=(t,e,n)=>e.has(t)?i("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n),s=(t,e,n)=>(((t,e)=>{e.has(t)||i("Cannot access private method")})(t,e),n),r=class{constructor(e,n){o(this,t),this.name=e,this.version=n,this.t=null,this.i="bm-o",this.o=null,this.l=null,this.m=[]}h(t){this.t=t}u(){return this.m.length>0&&(this.l=this.m.pop()),this}p(t){t?.appendChild(this.o),this.o=null,this.l=null,this.m=[]}v(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{},n)),this}S(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"p",{},n)),this}$(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"small",{},n)),this}M(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"span",{},n)),this}T(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"details",{},n)),this}C(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"summary",{},n)),this}D(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"img",{},n)),this}O(n,i={},o=()=>{}){return o(this,s(this,t,e).call(this,"h"+n,{},i)),this}k(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"hr",{},n)),this}N(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"br",{},n)),this}B(n={},i=()=>{}){const o=s(this,t,e).call(this,"label",{textContent:n.textContent??""});delete n.textContent;const r=s(this,t,e).call(this,"input",{type:"checkbox"},n);return o.insertBefore(r,o.firstChild),this.u(),i(this,o,r),this}I(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"ol",{},n)),this}L(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"ul",{},n)),this}P(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"menu",{},n)),this}G(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"li",{},n)),this}U(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"table",{},n)),this}W(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"caption",{},n)),this}A(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"thead",{},n)),this}_(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"tbody",{},n)),this}F(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"tfoot",{},n)),this}X(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"tr",{},n)),this}H(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"th",{},n)),this}J(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"td",{},n)),this}j(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"button",{},n)),this}R(n={},i=()=>{}){const o=n.title??n.textContent??"Help: No info";delete n.textContent,n.title=`Help: ${o}`;const r={textContent:"?",className:"bm-D",onclick:()=>{this.Y(this.i,o)}};return i(this,s(this,t,e).call(this,"button",r,n)),this}V(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"input",{},n)),this}q(n={},i=()=>{}){const o=n.textContent??"";delete n.textContent;const r=s(this,t,e).call(this,"div"),a=s(this,t,e).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true",style:"display: none !important; visibility: hidden !important; position: absolute !important; left: -9999px !important; width: 0 !important; height: 0 !important; opacity: 0 !important;"},n);this.u();const l=s(this,t,e).call(this,"button",{textContent:o});return this.u(),this.u(),l.addEventListener("click",()=>{a.click()}),a.addEventListener("change",()=>{l.style.maxWidth=`${l.offsetWidth}px`,a.files.length>0?l.textContent=a.files[0].name:l.textContent=o}),i(this,r,a,l),this}K(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"textarea",{},n)),this}Z(n={},i=()=>{}){return i(this,s(this,t,e).call(this,"div",{class:"bm-1f"},n)),this}Y(t,e,n=!1){const i=document.getElementById(t.replace(/^#/,""));i&&(i instanceof HTMLInputElement?i.value=e:n?i.textContent=e:i.innerHTML=e)}tt(t){if(t.disabled)return;t.disabled=!0,t.style.textDecoration="none";const e=t.closest(".bm-1h"),n=t.closest(".bm-1f"),i=e.querySelector("h1"),o=e.querySelector(".bm-U");if("expanded"==t.dataset.buttonStatus){o.style.height=o.scrollHeight+"px",e.style.width=e.scrollWidth+"px",o.style.height="0",o.addEventListener("transitionend",function e(){o.style.display="none",t.disabled=!1,t.style.textDecoration="",o.removeEventListener("transitionend",e)});const n=i.cloneNode(!0),s=n.textContent;t.nextElementSibling.appendChild(n),t.textContent="▶",t.dataset.buttonStatus="collapsed",t.ariaLabel=`Unminimize window "${s}"`}else{const i=n.querySelector("h1"),s=i.textContent;i.remove(),o.style.display="",o.style.height="0",e.style.width="",o.style.height=o.scrollHeight+"px",o.addEventListener("transitionend",function e(){o.style.height="",t.disabled=!1,t.style.textDecoration="",o.removeEventListener("transitionend",e)}),t.textContent="▼",t.dataset.buttonStatus="expanded",t.ariaLabel=`Minimize window "${s}"`}}et(t,e){if(t=document.querySelector(t),e=document.querySelector(e),!t||!e)return void this.nt(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);let n,i=!1,o=0,s=null,r=0,a=0,l=0,c=0,m=null;const d=()=>{if(i){const e=Math.abs(r-l),n=Math.abs(a-c);(e>.5||n>.5)&&(r=l,a=c,t.style.transform=`translate(${r}px, ${a}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),s=requestAnimationFrame(d)}},h=(h,g)=>{i=!0,m=t.getBoundingClientRect(),n=h-m.left,o=g-m.top;const f=window.getComputedStyle(t).transform;if(f&&"none"!==f){const t=new DOMMatrix(f);r=t.m41,a=t.m42}else r=m.left,a=m.top;l=r,c=a,document.body.style.userSelect="none",e.classList.add("bm-1a"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",u),document.addEventListener("touchend",u),document.addEventListener("touchcancel",u),s&&cancelAnimationFrame(s),d()},u=()=>{i=!1,s&&(cancelAnimationFrame(s),s=null),document.body.style.userSelect="",e.classList.remove("bm-1a"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchend",u),document.removeEventListener("touchcancel",u)},b=t=>{i&&m&&(l=t.clientX-n,c=t.clientY-o)},p=t=>{if(i&&m){const e=t.touches[0];if(!e)return;l=e.clientX-n,c=e.clientY-o,t.preventDefault()}};e.addEventListener("mousedown",function(t){t.preventDefault(),h(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(h(e.clientX,e.clientY),t.preventDefault())},{passive:!1})}it(t){(0,console.info)(`${this.name}: ${t}`),this.Y(this.i,"Status: "+t,!0)}nt(t){(0,console.error)(`${this.name}: ${t}`),this.Y(this.i,"Error: "+t,!0)}};function a(...t){(0,console.error)(...t)}function l(t,e){if(0===t)return e[0];let n="";const i=e.length;for(;t>0;)n=e[t%i]+n,t=Math.floor(t/i);return n}function c(t){let e="";for(let n=0;n(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4));return.2126*e[0]+.7152*e[1]+.0722*e[2]}t=new WeakSet,e=function(e,i={},o={}){const r=document.createElement(e);this.o?(this.l?.appendChild(r),this.m.push(this.l),this.l=r):(this.o=r,this.l=r);for(const[e,o]of Object.entries(i))s(this,t,n).call(this,r,e,o);for(const[e,i]of Object.entries(o))s(this,t,n).call(this,r,e,i);return r},n=function(t,e,n){if("class"==e)t.classList.add(...n.split(/\s+/));else if("for"==e)t.htmlFor=n;else if("tabindex"==e)t.tabIndex=Number(n);else if("readonly"==e)t.readOnly="true"==n||"1"==n;else if("maxlength"==e)t.maxLength=Number(n);else if(e.startsWith("data"))t.dataset[e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("")]=n;else if(e.startsWith("aria")){const i=e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("");t["aria"+i[0].toUpperCase()+i.slice(1)]=n}else t[e]=n};var h,u,b,p,g,f,w,y,x,v=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],S=class{constructor({displayName:t="My template",ot:e=0,st:n="",url:i="",file:s=null,coords:r=null,rt:a=null,lt:l={},ct:c=1e3}={}){o(this,h),this.displayName=t,this.ot=e,this.st=n,this.url=i,this.file=s,this.coords=r,this.rt=a,this.lt=l,this.ct=c,this.dt={total:0,colors:new Map}}async ht(t,e){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),i=n.width,o=n.height;this.ct=t;const r={},a={},l=new OffscreenCanvas(this.ct,this.ct),m=l.getContext("2d",{ut:!0});l.width=i,l.height=o,m.imageSmoothingEnabled=!1,m.drawImage(n,0,0);let d=Date.now();const b=s(this,h,u).call(this,m.getImageData(0,0,i,o),e);console.log(`Calculating total pixels took ${(Date.now()-d)/1e3} seconds`);let p=0;for(const[t,e]of b)0!=t&&(p+=e);this.dt={total:p,colors:b},d=Date.now();const g=new OffscreenCanvas(3,3),f=g.getContext("2d");f.clearRect(0,0,3,3),f.fillStyle="white",f.fillRect(1,1,1,1);for(let t=this.coords[3];t>>24==0?0:o.get(e)??-2;const r=s.get(i);s.set(i,r?r+1:1)}return console.log(s),s},b=new WeakSet,p=async function(){GM.setValue("bmTemplates",JSON.stringify(this.wt))},g=async function(t){console.log("Parsing BlueMarble...");const e=t.templates;if(console.log(`BlueMarble length: ${Object.keys(e).length}`),Object.keys(e).length>0)for(const t in e){const n=t,i=e[t];if(console.log(`Template Key: ${n}`),e.hasOwnProperty(t)){const t=n.split(" "),e=Number(t?.[0]),o=t?.[1]||"0",s=i.name||`Template ${e||""}`,r={total:i.pixels.total,colors:new Map(Object.entries(i.pixels.colors).map(([t,e])=>[Number(t),e]))},a=i.tiles,l={},c={},d=this.ct*this.yt;for(const t in a)if(console.log(t),a.hasOwnProperty(t)){const e=m(a[t]),n=new Blob([e],{type:"image/png"}),i=await createImageBitmap(n);l[t]=i;const o=new OffscreenCanvas(d,d).getContext("2d");o.drawImage(i,0,0);const s=o.getImageData(0,0,i.width,i.height);c[t]=new Uint32Array(s.data.buffer)}const h=new S({displayName:s,ot:e||this.xt?.length||0,st:o||""});h.dt=r,h.rt=l,h.lt=c,this.xt.push(h),console.log(this.xt),console.log("^^^ This ^^^")}}},f=function(t,e,n){const i=this.yt,o=this.ct*i,s=n[0],r=n[1],a=n[2],l=n[3],c=this.vt,{palette:m,ft:d}=this.St,h=new Map;for(let n=1;n>>24&255)<=c||(i>>>24&255)<=c)continue;const u=d.get(i)??-2,b=d.get(m)??-2;if(u!=b)continue;const p=h.get(b);h.set(b,p?p+1:1)}return console.log("List of template pixels that match the tile:"),console.log(h),h},w=new WeakSet,y=async function(t=navigator.userAgent){return(t=t||"").includes("OPR/")||t.includes("Opera")?"Opera":t.includes("Edg/")?"Edge":t.includes("Vivaldi")?"Vivaldi":t.includes("YaBrowser")?"Yandex":t.includes("Kiwi")?"Kiwi":t.includes("Brave")?"Brave":t.includes("Firefox/")?"Firefox":t.includes("Chrome/")?"Chrome":t.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"},x=function(t=navigator.userAgent){return/Windows NT 11/i.test(t=t||"")?"Windows 11":/Windows NT 10/i.test(t)?"Windows 10":/Windows NT 6\.3/i.test(t)?"Windows 8.1":/Windows NT 6\.2/i.test(t)?"Windows 8":/Windows NT 6\.1/i.test(t)?"Windows 7":/Windows NT 6\.0/i.test(t)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(t)?"Windows XP":/Mac OS X 10[_\.]15/i.test(t)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(t)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(t)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(t)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(t)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(t)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"};var $=GM_info.script.name.toString(),M=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-E",$),e.setAttribute("bm-B","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-E")||"Blue Marble",n=t?.getAttribute("bm-B")||"",i=new Map;window.addEventListener("message",t=>{const{source:o,endpoint:s,blobID:r,blobData:a,blink:l}=t.data,c=Date.now()-l;if(console.groupCollapsed(`%c${e}%c: ${i.size} Recieved IMAGE message about blob "${r}"`,n,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,n,""),console.log(i),console.groupEnd(),"blue-marble"==o&&r&&a&&!s){const t=i.get(r);"function"==typeof t?t(a):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,n,"",r),i.delete(r)}});const o=window.fetch;window.fetch=async function(...t){const s=await o.apply(this,t),r=s.clone(),a=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",l=r.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${a}"`,n,""),r.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:a,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,n,"",t)});else if(l.includes("image/")&&!a.includes("openfreemap")&&!a.includes("maps")){const t=Date.now(),o=await r.blob();return console.log(`%c${e}%c: ${i.size} Sending IMAGE message about endpoint "${a}"`,n,""),new Promise(s=>{const l=crypto.randomUUID();i.set(l,t=>{s(new Response(t,{headers:r.headers,status:r.status,statusText:r.statusText})),console.log(`%c${e}%c: ${i.size} Processed blob "${l}"`,n,"")}),window.postMessage({source:"blue-marble",endpoint:a,blobID:l,blobData:o,blink:t})}).catch(o=>{const s=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,n,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,n,""),console.log(`Endpoint: ${a}\nThere are ${i.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(s/6e4)).padStart(2,"0")}:${String(Math.floor(s/1e3)%60).padStart(2,"0")}.${String(s%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",o),console.groupEnd()})}return s}});var T=GM_getResourceText("CSS-BM-File");GM_addStyle(T);var C,D="robotoMonoInjectionPoint";D.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(D)):((C=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",C.rel="preload",C.as="style",C.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(C)),new class{constructor(){this.$t=null,this.Mt=null,this.Tt="#bm-h"}Ct(t){return this.Mt=t,this.$t=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.Tt)}),this}Dt(){return this.$t}observe(t,e=!1,n=!1){t.observe(this.Mt,{childList:e,subtree:n})}};var O=new r($,M),k=(new r($,M),new class{constructor(t,e,n){o(this,b),this.name=t,this.version=e,this.o=n,this.Ot="1.0.0",this.kt=null,this.Nt="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.ct=1e3,this.yt=3,this.vt=3,this.St=function(t){const e=v;e.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),e.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const n=new Map;for(const i of e){if(0==i.id||-2==i.id)continue;const e=i.rgb[0],o=i.rgb[1],s=i.rgb[2];for(let r=-t;r<=t;r++)for(let a=-t;a<=t;a++)for(let l=-t;l<=t;l++){const t=e+r,c=o+a,m=s+l;if(t<0||t>255||c<0||c>255||m<0||m>255)continue;const d=(255<<24|m<<16|c<<8|t)>>>0;n.has(d)||n.set(d,i.id)}}return{palette:e,ft:n}}(this.vt),this.Bt=null,this.It="",this.xt=[],this.wt=null,this.Lt=!0,this.Pt=null}async Gt(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.Ot,templates:{}}}async Ut(t,e,n){this.wt||(this.wt=await this.Gt(),console.log("Creating JSON...")),this.o.it(`Creating template at ${n.join(", ")}...`);const i=new S({displayName:e,ot:0,st:l(this.kt||0,this.Nt),file:t,coords:n}),{bt:o,gt:r}=await i.ht(this.ct,this.St);i.rt=o;const a={total:i.dt.total,colors:Object.fromEntries(i.dt.colors)};this.wt.templates[`${i.ot} ${i.st}`]={name:i.displayName,coords:n.join(", "),enabled:!0,pixels:a,tiles:r},this.xt=[],this.xt.push(i),this.o.it(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.wt.templates).length),console.log(this.wt),console.log(this.xt),console.log(JSON.stringify(this.wt)),await s(this,b,p).call(this)}Wt(){}async At(){this.wt||(this.wt=await this.Gt(),console.log("Creating JSON..."))}async _t(t,e){if(!this.Lt)return t;const n=this.ct*this.yt;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${e}"`);const i=this.xt;console.log(i),i.sort((t,e)=>t.ot-e.ot),console.log(i);const o=i.map(t=>{const n=Object.keys(t.rt).filter(t=>t.startsWith(e));if(0===n.length)return null;const i=n.map(e=>{const n=e.split(",");return{Ft:t,Xt:t.rt[e],lt:t.lt?.[e],Et:[n[0],n[1]],Ht:[n[2],n[3]]}});return i?.[0]}).filter(Boolean);console.log(o);const r=o?.length||0;if(console.log(`templateCount = ${r}`),!(r>0))return this.o.it(`Sleeping\nVersion: ${this.version}`),t;{const t=i.filter(t=>Object.keys(t.rt).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.dt.total||0),0),n=(new Intl.NumberFormat).format(t);this.o.it(`Displaying ${r} template${1==r?"":"s"}.\nTotal pixels: ${n}`)}const a=await createImageBitmap(t),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(a,0,0,n,n);const m=c.getImageData(0,0,n,n),d=new Uint32Array(m.data.buffer);for(const t of o){console.log("Template:"),console.log(t);let n=t.lt;const i=Number(t.Ht[0])*this.yt,o=Number(t.Ht[1])*this.yt;if(c.drawImage(t.Xt,i,o),!n){const e=c.getImageData(i,o,t.Xt.width,t.Xt.height);n=new Uint32Array(e.data.buffer)}const r=Date.now(),a=s(this,b,f).call(this,d,n,[i,o,t.Xt.width,t.Xt.height]);let l=0;const m=0;for(const[t,e]of a)t!=m&&(l+=e);console.log(`Finished calculating correct pixels for the tile ${e} in ${(Date.now()-r)/1e3} seconds!\nThere are ${l} correct pixels.`),t.Ft.dt.correct=a}return await l.convertToBlob({type:"image/png"})}Jt(t){console.log("Importing JSON..."),console.log(t),"BlueMarble"==t?.whoami&&s(this,b,g).call(this,t)}jt(t){this.Lt=t}}($,M,O)),N=new class{constructor(t){o(this,w),this.Rt=t,this.Yt=!1,this.Vt=[],this.zt=[]}qt(t){window.addEventListener("message",async e=>{const n=e.data,i=n.jsonData;if(!n||"blue-marble"!==n.source)return;if(!n.endpoint)return;const o=n.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",o),o){case"me":if(i.status&&"2"!=i.status?.toString()[0])return void t.nt("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(i.level)*Math.pow(30,.65),1/.65)-i.pixelsPainted);console.log(i.id),(i.id||0===i.id)&&console.log(l(i.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Rt.kt=i.id,t.Y("bm-p",`Droplets: ${(new Intl.NumberFormat).format(i.droplets)}`),t.Y("bm-i",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const o=n.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),a=new URLSearchParams(n.endpoint.split("?")[1]),c=[a.get("x"),a.get("y")];if(this.Vt.length&&(!o.length||!c.length))return void t.nt("Coordinates are malformed!\nDid you try clicking the canvas first?");this.Vt=[...o,...c];const m=(s=o,r=c,[parseInt(s[0])%4*1e3+parseInt(r[0]),parseInt(s[1])%4*1e3+parseInt(r[1])]),d=document.querySelectorAll("span");for(const t of d)if(t.textContent.trim().includes(`${m[0]}, ${m[1]}`)){let e=document.querySelector("#bm-h");const n=`(Tl X: ${o[0]}, Tl Y: ${o[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=n:(e=document.createElement("span"),e.id="bm-h",e.textContent=n,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let h=n.endpoint.split("/");h=[parseInt(h[h.length-2]),parseInt(h[h.length-1].replace(".png",""))];const u=n.blobID,b=n.blobData,p=Date.now(),g=await this.Rt._t(b,h);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:u,blobData:g,blink:n.blink});break;case"robots":this.Yt="false"==i.userscript?.toString().toLowerCase();break}var s,r})}async Kt(t){console.log("Sending heartbeat to telemetry server...");let e=GM_getValue("bmUserSettings","{}");if(e=JSON.parse(e),!e||!e.telemetry||!e.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const n=navigator.userAgent;let i=await s(this,w,y).call(this,n),o=s(this,w,x).call(this,n);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:e.uuid,version:t,browser:i,os:o}),onload:t=>{200!==t.status&&a("Failed to send heartbeat:",t.statusText)},onerror:t=>{a("Error sending heartbeat:",t)}})}}(k);O.h(N);var B=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(B),k.Jt(B);var I=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(I),console.log(Object.keys(I).length),0==Object.keys(I).length){const t=crypto.randomUUID();console.log(t),GM.setValue("bmUserSettings",JSON.stringify({uuid:t}))}if(setInterval(()=>N.Kt(M),18e5),console.log(`Telemetry is ${!(null==I?.telemetry)}`),null==I?.telemetry||I?.telemetry>1){const t=new r($,M);t.h(N),t.v({id:"bm-d",style:"top: 0px; left: 0px; width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; z-index: 9999;"}).v({id:"bm-7",style:"display: flex; flex-direction: column; align-items: center;"}).v({id:"bm-1",style:"margin-top: 10%;"}).O(1,{textContent:`${$} Telemetry`}).u().u().v({id:"bm-e",style:"max-width: 50%; overflow-y: auto; max-height: 80vh;"}).k().u().N().u().v({style:"width: fit-content; margin: auto; text-align: center;"}).j({id:"bm-8",textContent:"More Information"},(t,e)=>{e.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).u().u().N().u().v({style:"width: fit-content; margin: auto; text-align: center;"}).j({id:"bm-5",textContent:"Enable Telemetry",style:"margin-right: 2ch;"},(t,e)=>{e.onclick=()=>{const t=JSON.parse(GM_getValue("bmUserSettings","{}"));t.telemetry=1,GM.setValue("bmUserSettings",JSON.stringify(t));const e=document.getElementById("bm-d");e&&(e.style.display="none")}}).u().j({id:"bm-2",textContent:"Disable Telemetry"},(t,e)=>{e.onclick=()=>{const t=JSON.parse(GM_getValue("bmUserSettings","{}"));t.telemetry=0,GM.setValue("bmUserSettings",JSON.stringify(t));const e=document.getElementById("bm-d");e&&(e.style.display="none")}}).u().u().N().u().S({textContent:"We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the 'Disable' button, but keeping it on helps us improve features and reliability faster. Thank you for supporting the Blue Marble!"}).u().S({textContent:'You can disable telemetry by pressing the "Disable" button below.'}).u().u().u().p(document.body)}O.v({id:"bm-15",class:"bm-1h",style:"top: 10px; left: unset; right: 75px;"}).Z().j({class:"bm--",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.tt(e),e.ontouchend=()=>t.tt(e)}).u().v().u().u().v({class:"bm-U"}).v({class:"bm-19"}).D({class:"bm-1g",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"}).u().O(1,{textContent:$}).u().u().k().u().v({class:"bm-19"}).S({id:"bm-p",textContent:"Droplets:"}).u().S({id:"bm-i",textContent:"Next level in..."}).u().u().k().u().v({class:"bm-19"}).v({class:"bm-19"}).j({class:"bm-- bm-17",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.t?.Vt;e?.[0]?(t.Y("bm-v",e?.[0]||""),t.Y("bm-w",e?.[1]||""),t.Y("bm-x",e?.[2]||""),t.Y("bm-y",e?.[3]||"")):t.nt("Coordinates are malformed! Did you try clicking on the canvas first?")}}).u().V({type:"number",id:"bm-v",class:"bm-11",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",t=>{let e=(t.clipboardData||window.clipboardData).getData("text").split(" ").filter(t=>t).map(Number).filter(t=>!isNaN(t));if(4!==e.length)return;let n=selectAllCoordinateInputs(document);for(let t=0;t{e.onclick=()=>{e.disabled=!0,"shown"==e.dataset.buttonStatus?(t.t?.Rt?.jt(!1),e.dataset.buttonStatus="hidden",e.textContent="Enable",t.it("Disabled templates!")):(t.t?.Rt?.jt(!0),e.dataset.buttonStatus="shown",e.textContent="Disable",t.it("Enabled templates!")),e.disabled=!1}}).u().j({textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector("#bm-15 button.bm-18"),n=document.querySelector("#bm-v");if(!n.checkValidity())return n.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");const i=document.querySelector("#bm-w");if(!i.checkValidity())return i.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-x");if(!o.checkValidity())return o.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-y");if(!s.checkValidity())return s.reportValidity(),void t.nt("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(k.Ut(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(n.value),Number(i.value),Number(o.value),Number(s.value)]),t.it("Drew to canvas!")):t.nt("No file selected!")}}).u().j({textContent:"Filter"},(t,e)=>{e.onclick=()=>function(){if(document.querySelector("#bm-_"))return void O.nt("Color Filter window already exists!");const t=new r($,M);t.v({id:"bm-_",class:"bm-1h"}).Z().j({class:"bm--",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.tt(e),e.ontouchend=()=>t.tt(e)}).u().v().u().j({class:"bm--",textContent:"🞪","aria-label":'Close window "Color Filter"'},(t,e)=>{e.onclick=()=>{document.querySelector("#bm-_")?.remove()},e.ontouchend=()=>{document.querySelector("#bm-_")?.remove()}}).u().u().v({class:"bm-U"}).v({class:"bm-19"}).O(1,{textContent:"Color Filter"}).u().u().k().u().v({class:"bm-19 bm-12",style:"width: fit-content;"}).j({textContent:"Select All"},(t,e)=>{e.onclick=()=>{}}).u().j({textContent:"Unselect All"},(t,e)=>{e.onclick=()=>{}}).u().u().u().u().p(document.body),t.et("#bm-_.bm-1h","#bm-_ .bm-1f");const e=document.querySelector("#bm-_ .bm-U"),{palette:n,ft:i}=k.St;let o=0,s=0;const a=new Map,l=new Map;for(const t of k.xt){const e=t.dt?.total??0,n=t.dt?.colors??new Map,i=t.dt?.correct??new Map;o+=e??0;for(const[t,e]of i){const n=Number(e)||0;s+=n;const i=a.get(t)??0;a.set(t,i+n)}for(const[t,e]of n){const n=Number(e)||0,i=l.get(t)??0;l.set(t,i+n)}}const c=new r($,M);c.v({class:"bm-19"}).U({class:"bm-19"}).W().O(2,{textContent:"Pixels In Templates By Palette Color"}).u().u().F().X().H({textContent:"Total Correct",scope:"row"}).u().J({textContent:s.toString()}).u().u().X().H({textContent:"Total Pixels",scope:"row"}).u().J({textContent:o.toString()}).u().u().u().A({class:"bm-13"}).X().H({textContent:"Hide Color",scope:"col"}).u().H({textContent:"ID",scope:"col"}).u().H({textContent:"Is Premium",scope:"col"}).u().H({textContent:"Name",scope:"col"}).u().H({textContent:"Correct Pixels",scope:"col"}).u().H({textContent:"Total Pixels",scope:"col"}).u().u().u();for(const t of n){const e=d(t.rgb),n=1.05/(e+.05)>(e+.05)/.05?"white":"black",i="white"==n?"bm-M":"bm-N";c.X().J().v({class:"bm-X",style:`background-color: rgb(${t.rgb?.map(t=>Number(t)||0).join(",")});`}).j({class:"bm-14 "+i,"aria-label":`Hide the color ${t.name||"color"} on templates`,innerHTML:``}).u().u().u().J().M({class:"bm-10",textContent:`#${t.id}`}).u().u().J().M({class:"bm-Q",textContent:t.premium?"★":""}).u().u().J().M({class:"bm-R",textContent:t.name}).u().u().J().M({class:"bm-S",textContent:m(String(a.get(t.id)??"???"),7)}).u().u().J().M({class:"bm-T",textContent:m(String(l.get(t.id)??"0"),7)}).u().u().u()}function m(t,e){if(t.length<=e)return t;const n=Math.floor((e-3)/2);return t.slice(0,n)+"…"+t.slice(t.length-n)}c.p(e)}()}).u().u().v({class:"bm-19"}).K({id:O.i,placeholder:`Status: Sleeping...\nVersion: ${M}`,readOnly:!0}).u().u().v({class:"bm-19 bm-12",style:"margin-bottom: 0;"}).v({class:"bm-12"}).j({class:"bm--",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).u().j({class:"bm--",innerHTML:"🌐",title:"Official Blue Marble Website"},(t,e)=>{e.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).u().u().$({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).u().u().u().u().u().p(document.body),O.et("#bm-15.bm-1h","#bm-15 .bm-1f"),N.qt(O),new MutationObserver((t,e)=>{const n=document.querySelector("#color-1");if(!n)return;let i=document.querySelector("#bm-t");if(!i){i=document.createElement("button"),i.id="bm-t",i.textContent="Move ↑",i.className="btn btn-soft",i.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=n.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(i)}}).observe(document.body,{childList:!0,subtree:!0}),function(...t){(0,console.log)(...t)}(`%c${$}%c (${M}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 1413855..0e0960f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -51,7 +51,7 @@ Contact Me Blue Marble Website WakaTime -Total Patches +Total Patches Total Lines of Code Total Comments Compression diff --git a/package-lock.json b/package-lock.json index 309927f..f65a805 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wplace-bluemarble", - "version": "0.88.179", + "version": "0.88.207", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wplace-bluemarble", - "version": "0.88.179", + "version": "0.88.207", "devDependencies": { "esbuild": "^0.25.0", "jsdoc": "^4.0.5", diff --git a/package.json b/package.json index 67d3a5c..be0e7c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wplace-bluemarble", - "version": "0.88.179", + "version": "0.88.207", "type": "module", "homepage": "https://bluemarble.lol/", "repository": { diff --git a/src/BlueMarble.meta.js b/src/BlueMarble.meta.js index a49aef1..7cb07c7 100644 --- a/src/BlueMarble.meta.js +++ b/src/BlueMarble.meta.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.179 +// @version 0.88.207 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine diff --git a/src/Overlay.js b/src/Overlay.js index db5d901..8eb2b84 100644 --- a/src/Overlay.js +++ b/src/Overlay.js @@ -208,12 +208,12 @@ export default class Overlay { callback(this, p); // Runs any script passed in through the callback return this; } - + /** Adds a `small` to the overlay. * This `small` element will have properties shared between all `small` elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the `small` that are NOT shared between all overlay `small` elements. These should be camelCase. - * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `small`. + * @param {function(Overlay, HTMLElement):void} [callback=()=>{}] - Additional JS modification to the `small`. * @returns {Overlay} Overlay class instance (this) * @since 0.55.8 * @example @@ -234,11 +234,36 @@ export default class Overlay { return this; } + /** Adds a `span` to the overlay. + * This `span` element will have properties shared between all `span` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `span` that are NOT shared between all overlay `span` elements. These should be camelCase. + * @param {function(Overlay, HTMLSpanElement):void} [callback=()=>{}] - Additional JS modification to the `span`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.55.8 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addSpan({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addSpan(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared DOM properties + + const span = this.#createElement('span', properties, additionalProperties); // Creates the element + callback(this, span); // Runs any script passed in through the callback + return this; + } + /** Adds a `details` to the overlay. * This `details` element will have properties shared between all `details` elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the `details` that are NOT shared between all overlay `details` elements. These should be camelCase. - * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `details`. + * @param {function(Overlay, HTMLDetailsElement):void} [callback=()=>{}] - Additional JS modification to the `details`. * @returns {Overlay} Overlay class instance (this) * @since 0.88.96 * @example @@ -263,7 +288,7 @@ export default class Overlay { * This `summary` element will have properties shared between all `summary` elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the `summary` that are NOT shared between all overlay `summary` elements. These should be camelCase. - * @param {function(Overlay, HTMLParagraphElement):void} [callback=()=>{}] - Additional JS modification to the `summary`. + * @param {function(Overlay, HTMLElement):void} [callback=()=>{}] - Additional JS modification to the `summary`. * @returns {Overlay} Overlay class instance (this) * @since 0.88.96 * @example @@ -416,6 +441,306 @@ export default class Overlay { callback(this, label, checkbox); // Runs any script passed in through the callback return this; } + + /** Adds an ordered list to the overlay. + * This `ol` element will have properties shared between all `ol` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `ol` that are NOT shared between all overlay `ol` elements. These should be camelCase. + * @param {function(Overlay, HTMLOListElement):void} [callback=()=>{}] - Additional JS modification to the `ol`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all
        elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addOl({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
          Foobar.
        + * + */ + addOl(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared
          DOM properties + + const ol = this.#createElement('ol', properties, additionalProperties); // Creates the
            element + callback(this, ol); // Runs any script passed in through the callback + return this; + } + + /** Adds an unordered list to the overlay. + * This `ul` element will have properties shared between all `ul` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `ul` that are NOT shared between all overlay `ul` elements. These should be camelCase. + * @param {function(Overlay, HTMLUListElement):void} [callback=()=>{}] - Additional JS modification to the `ul`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all
              elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addUl({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
                Foobar.
              + * + */ + addUl(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared
                DOM properties + + const ul = this.#createElement('ul', properties, additionalProperties); // Creates the
                  element + callback(this, ul); // Runs any script passed in through the callback + return this; + } + + /** Adds a `menu` to the overlay. + * This `menu` element will have properties shared between all `menu` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `menu` that are NOT shared between all overlay `menu` elements. These should be camelCase. + * @param {function(Overlay, HTMLMenuElement):void} [callback=()=>{}] - Additional JS modification to the `menu`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addMenu({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addMenu(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared DOM properties + + const menu = this.#createElement('menu', properties, additionalProperties); // Creates the element + callback(this, menu); // Runs any script passed in through the callback + return this; + } + + /** Adds a list item to the overlay. + * This `li` element will have properties shared between all `li` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `li` that are NOT shared between all overlay `li` elements. These should be camelCase. + * @param {function(Overlay, HTMLLIElement):void} [callback=()=>{}] - Additional JS modification to the `li`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all
                • elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addLi({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
                • Foobar.
                • + * + */ + addLi(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared
                • DOM properties + + const li = this.#createElement('li', properties, additionalProperties); // Creates the
                • element + callback(this, li); // Runs any script passed in through the callback + return this; + } + + /** Adds a table to the overlay. + * This `table` element will have properties shared between all `table` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `table` that are NOT shared between all overlay `table` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableElement):void} [callback=()=>{}] - Additional JS modification to the `table`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTable({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + *
                  Foobar.
                  + * + */ + addTable(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared DOM properties + + const table = this.#createElement('table', properties, additionalProperties); // Creates the
                  element + callback(this, table); // Runs any script passed in through the callback + return this; + } + + /** Adds a table caption to the overlay. + * This `caption` element will have properties shared between all `caption` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `caption` that are NOT shared between all overlay `caption` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableCaptionElement):void} [callback=()=>{}] - Additional JS modification to the `caption`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all + * + */ + addCaption(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addThead({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addThead(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared DOM properties + + const thead = this.#createElement('thead', properties, additionalProperties); // Creates the element + callback(this, thead); // Runs any script passed in through the callback + return this; + } + + /** Adds a table body to the overlay. + * This `tbody` element will have properties shared between all `tbody` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `tbody` that are NOT shared between all overlay `tbody` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableSectionElement):void} [callback=()=>{}] - Additional JS modification to the `tbody`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTbody({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTbody(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared DOM properties + + const tbody = this.#createElement('tbody', properties, additionalProperties); // Creates the element + callback(this, tbody); // Runs any script passed in through the callback + return this; + } + + /** Adds a table footer to the overlay. + * This `tfoot` element will have properties shared between all `tfoot` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `tfoot` that are NOT shared between all overlay `tfoot` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableSectionElement):void} [callback=()=>{}] - Additional JS modification to the `tfoot`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTfoot({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTfoot(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared DOM properties + + const tfoot = this.#createElement('tfoot', properties, additionalProperties); // Creates the element + callback(this, tfoot); // Runs any script passed in through the callback + return this; + } + + /** Adds a table row to the overlay. + * This `tr` element will have properties shared between all `tr` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `tr` that are NOT shared between all overlay `tr` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableRowElement):void} [callback=()=>{}] - Additional JS modification to the `tr`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTr({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. + * + */ + addTr(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared DOM properties + + const tr = this.#createElement('tr', properties, additionalProperties); // Creates the element + callback(this, tr); // Runs any script passed in through the callback + return this; + } + + /** Adds a table header (label) cell to the overlay. + * This `th` element will have properties shared between all `th` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `th` that are NOT shared between all overlay `th` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableCellElement):void} [callback=()=>{}] - Additional JS modification to the `th`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all + * + */ + addTh(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared + * + */ + addTd(additionalProperties = {}, callback = () => {}) { + + const properties = {}; // Shared
                  elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addCaption({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. DOM properties + + const caption = this.#createElement('caption', properties, additionalProperties); // Creates the element + callback(this, caption); // Runs any script passed in through the callback + return this; + } + + /** Adds a table header to the overlay. + * This `thead` element will have properties shared between all `thead` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `thead` that are NOT shared between all overlay `thead` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableSectionElement):void} [callback=()=>{}] - Additional JS modification to the `thead`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all
                  elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTh({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. DOM properties + + const th = this.#createElement('th', properties, additionalProperties); // Creates the element + callback(this, th); // Runs any script passed in through the callback + return this; + } + + /** Adds a table data cell to the overlay. + * This `td` element will have properties shared between all `td` elements in the overlay. + * You can override the shared properties by using a callback. + * @param {Object.} [additionalProperties={}] - The DOM properties of the `td` that are NOT shared between all overlay `td` elements. These should be camelCase. + * @param {function(Overlay, HTMLTableCellElement):void} [callback=()=>{}] - Additional JS modification to the `td`. + * @returns {Overlay} Overlay class instance (this) + * @since 0.88.180 + * @example + * // Assume all elements have a shared class (e.g. {'className': 'bar'}) + * overlay.addTd({'id': 'foo', 'textContent': 'Foobar.'}).buildOverlay(document.body); + * // Output: + * // (Assume already exists in the webpage) + * + * Foobar. DOM properties + + const td = this.#createElement('td', properties, additionalProperties); // Creates the element + callback(this, td); // Runs any script passed in through the callback + return this; + } /** Adds a `button` to the overlay. * This `button` element will have properties shared between all `button` elements in the overlay. @@ -604,7 +929,7 @@ export default class Overlay { * This dragbar element will have properties shared between all dragbar elements in the overlay. * You can override the shared properties by using a callback. * @param {Object.} [additionalProperties={}] - The DOM properties of the dragbar that are NOT shared between all overlay dragbars. These should be camelCase. - * @param {function(Overlay, HTMLTextAreaElement):void} [callback=()=>{}] - Additional JS modification to the dragbar. + * @param {function(Overlay, HTMLDivElement):void} [callback=()=>{}] - Additional JS modification to the dragbar. * @returns {Overlay} Overlay class instance (this) * @since 0.88.145 * @example diff --git a/src/Template.js b/src/Template.js index 71dee90..7a936b7 100644 --- a/src/Template.js +++ b/src/Template.js @@ -41,7 +41,8 @@ export default class Template { this.chunked = chunked; this.chunked32 = chunked32; this.tileSize = tileSize; - this.pixelCount = { total: 0, colors: new Map() }; // Total pixel count in template + /** Total pixel count in template @type {{total: number, colors: Map, correct?: Map}} */ + this.pixelCount = { total: 0, colors: new Map() }; } /** Creates chunks of the template for each tile. diff --git a/src/main.js b/src/main.js index dba4528..5b1bbbf 100644 --- a/src/main.js +++ b/src/main.js @@ -492,7 +492,6 @@ function buildWindowFilter() { } }).buildElement() .buildElement() - .addDiv().buildElement() .buildElement() .buildElement().buildOverlay(document.body); @@ -505,9 +504,67 @@ function buildWindowFilter() { // Obtains the palette Blue Marble currently uses const { palette: palette, LUT: _ } = templateManager.paletteBM; + // Pixel totals + let allPixelsTotal = 0; + let allPixelsCorrectTotal = 0; + const allPixelsCorrect = new Map(); + const allPixelsColor = new Map(); + + // Sum the pixel totals across all templates. + // If there is no total for a template, it defaults to zero + for (const template of templateManager.templatesArray) { + + const total = template.pixelCount?.total ?? 0; + const colors = template.pixelCount?.colors ?? new Map(); + const correct = template.pixelCount?.correct ?? new Map(); + + allPixelsTotal += total ?? 0; // Sums the pixels placed as "total" per everything + + // Sums the pixels placed as "correct" per color ID + for (const [colorID, correctPixels] of correct) { + const _correctPixels = Number(correctPixels) || 0; // Boilerplate + allPixelsCorrectTotal += _correctPixels; // Sums the pixels placed as "correct" per everything + const allPixelsCorrectSoFar = allPixelsCorrect.get(colorID) ?? 0; // The total correct pixels for this color ID so far, or zero if none counted so far + allPixelsCorrect.set(colorID, allPixelsCorrectSoFar + _correctPixels); + } + + // Sums the color pixels placed as "total" per color ID + for (const [colorID, colorPixels] of colors) { + const _colorPixels = Number(colorPixels) || 0; // Boilerplate + const allPixelsColorSoFar = allPixelsColor.get(colorID) ?? 0; // The total color pixels for this color ID so far, or zero if none counted so far + allPixelsColor.set(colorID, allPixelsColorSoFar + _colorPixels); + } + } + // Creates the color list container const colorList = new Overlay(name, version); - colorList.addDiv({'id': 'bm-filter-container-colors', 'class': 'bm-container'}) + colorList.addDiv({'class': 'bm-container'}) + .addTable({'class': 'bm-container'}) + .addCaption() + .addHeader(2, {'textContent': 'Pixels In Templates By Palette Color'}).buildElement() + .buildElement() + .addTfoot() + .addTr() + .addTh({'textContent': 'Total Correct', 'scope': 'row'}).buildElement() + .addTd({'textContent': allPixelsCorrectTotal.toString()}).buildElement() + .buildElement() + .addTr() + .addTh({'textContent': 'Total Pixels', 'scope': 'row'}).buildElement() + .addTd({'textContent': allPixelsTotal.toString()}).buildElement() + .buildElement() + .buildElement() + .addThead({'class': 'bm-screenreader'}) + .addTr() + .addTh({'textContent': 'Hide Color', 'scope': 'col'}).buildElement() + .addTh({'textContent': 'ID', 'scope': 'col'}).buildElement() + .addTh({'textContent': 'Is Premium', 'scope': 'col'}).buildElement() + .addTh({'textContent': 'Name', 'scope': 'col'}).buildElement() + .addTh({'textContent': 'Correct Pixels', 'scope': 'col'}).buildElement() + .addTh({'textContent': 'Total Pixels', 'scope': 'col'}).buildElement() + .buildElement() + .buildElement() + // Notice that there is no buildElement() for the table here? + // We leave the table open so we can continue to add children. // For each color in the palette... for (const color of palette) { @@ -520,19 +577,49 @@ function buildWindowFilter() { (((1.05) / (lumin + 0.05)) > ((lumin + 0.05) / 0.05)) ? 'white' : 'black'; + const bgEffectForButtons = (textColorForPaletteColorBackground == 'white') ? 'bm-button-hover-white' : 'bm-button-hover-black'; + // + // Construct the DOM tree - colorList.addDiv({'class': 'bm-container flex-space-between'}) - .addDiv({'class': '' + textColorForPaletteColorBackground, 'style': `border: thick double white`}) - .addButton({'class': 'bm-button-trans', 'innerHTML': ``}).buildElement() + colorList.addTr() + .addTd() + .addDiv({'class': 'bm-filter-tbl-clr', 'style': `background-color: rgb(${color.rgb?.map(channel => Number(channel) || 0).join(',')});`}) + .addButton({'class': 'bm-button-trans ' + bgEffectForButtons, 'aria-label': `Hide the color ${color.name || 'color'} on templates`, 'innerHTML': ``}).buildElement() + .buildElement() + .buildElement() + .addTd() + .addSpan({'class': 'bm-filter-tbl-id', 'textContent': `#${color.id}`}).buildElement() + .buildElement() + .addTd() + .addSpan({'class': 'bm-filter-tbl-prmim', 'textContent': color.premium ? '★' : ''}).buildElement() + .buildElement() + .addTd() + .addSpan({'class': 'bm-filter-tbl-name', 'textContent': color.name}).buildElement() + .buildElement() + .addTd() + .addSpan({'class': 'bm-filter-tbl-crct', 'textContent': middleEllipsis(String(allPixelsCorrect.get(color.id) ?? '0'), 7)}).buildElement() + .buildElement() + .addTd() + .addSpan({'class': 'bm-filter-tbl-totl', 'textContent': middleEllipsis(String(allPixelsColor.get(color.id) ?? '0'), 7)}).buildElement() .buildElement() - .addP({'textContent': `Color ID: ${color.id?.toString()?.padStart(2, '0')}, Name: ${color.name}`}).buildElement() .buildElement() } // Adds the colors to the color container in the filter window colorList.buildOverlay(windowContent); + + // Overflow ellipse but the ellipse is in the middle, not end of the string + function middleEllipsis(text, maxChars) { + if (text.length <= maxChars) return text; + const half = Math.floor((maxChars - 3) / 2); + return ( + text.slice(0, half) + + "…" + + text.slice(text.length - half) + ); + } } function buildOverlayTabTemplate() { diff --git a/src/overlay.css b/src/overlay.css index 0f4bc81..7243546 100644 --- a/src/overlay.css +++ b/src/overlay.css @@ -1,5 +1,17 @@ /* @since 0.5.1 */ +/* Content with this class is only available to screen readers */ +.bm-screenreader { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} /* The Blue Marble window(s) */ .bm-window { @@ -13,6 +25,7 @@ top: 75px; left: 60px; width: auto; + max-height: calc(100vh - 150px); max-width: calc(100% - 135px); /* Font stack is as follows: * Highest Priority (Roboto Mono) @@ -152,6 +165,33 @@ fill: #111; } +/* Transparent buttons */ +.bm-window button.bm-button-trans { + background-color: unset; +} + +/* Transparent buttons on dark backgrounds when hovered */ +.bm-button-trans.bm-button-hover-white:hover, +.bm-button-trans.bm-button-hover-white:focus { + background-color: rgba(255, 255, 255, 0.17); +} + +/* Transparent buttons on dark backgrounds when pressed */ +.bm-button-trans.bm-button-hover-white:active { + background-color: rgba(255, 255, 255, 0.22); +} + +/* Transparent buttons on light backgrounds when hovered */ +.bm-button-trans.bm-button-hover-black:hover, +.bm-button-trans.bm-button-hover-black:focus { + background-color: rgba(0, 0, 0, 0.17); +} + +/* Transparent buttons on light backgrounds when pressed */ +.bm-button-trans.bm-button-hover-black:active { + background-color: rgba(0, 0, 0, 0.22); +} + /* Tile (x, y) & Pixel (x, y) input fields */ input[type="number"].bm-input-coords { appearance: auto; @@ -230,4 +270,109 @@ input[type="file"] { justify-content: center; align-items: center; gap: 0.5ch; -} \ No newline at end of file +} + +/* Filter window table container */ +#bm-window-filter .bm-container:has(table) { + max-height: 60vh; + overflow: auto; +} + +/* Filter window table */ +#bm-window-filter table { + table-layout: fixed; + width: 50ch; + border-collapse: separate; + border-spacing: 0 0.5em; +} + +/* Filter window table row */ +#bm-window-filter tr { + padding: 0.5em 0; +} + +/* Filter window table cell for RGB color display */ +.bm-filter-tbl-clr { + display: block; + border: thick double lightgray; + width: fit-content; + height: fit-content; + padding: 1ch; +} + +/* Filter window hide color button */ +.bm-filter-tbl-clr button { + padding: 0.75em 0.5ch; +} + +/* Filter window hide color button SVG */ +.bm-filter-tbl-clr svg { + width: 4ch; + isolation: isolate; +} + +/* Filter window color ID */ +.bm-filter-tbl-id { + position: relative; + top: 0.75em; + left: 0.5ch; +} + +/* Filter window color premium */ +.bm-filter-tbl-prmim { + position: relative; + top: 0.75em; + left: -3.5ch; +} + +/* Filter window color name */ +.bm-filter-tbl-name { + position: relative; + top: -0.75em; + left: -16ch; + text-wrap: nowrap; +} + +/* Filter window color correct pixels */ +.bm-filter-tbl-crct { + display: block; + width: 100%; + position: relative; + right: 18ch; + top: 0.75em; + text-align: right; +} + +/* Filter window color total pixels */ +.bm-filter-tbl-totl { + display: block; + width: 100%; + position: relative; + left: -16ch; + top: 0.75em; + text-align: left; +} + +.bm-filter-tbl-totl::after { + content: "/"; + position: absolute; + left: -1.5ch; + top: 50%; + transform: translateY(-50%); +} + +/* Filter window table footer */ +#bm-window-filter tfoot { + display: table-header-group; +} + +/* Filter window table footer header */ +#bm-window-filter tfoot th { + text-align: left; +} + +/* Filter window table footer data */ +#bm-window-filter tfoot td { + text-align: right; + padding-left: 1ch; +} diff --git a/src/templateManager.js b/src/templateManager.js index 41ba17d..a3f9360 100644 --- a/src/templateManager.js +++ b/src/templateManager.js @@ -71,6 +71,7 @@ export default class TemplateManager { // Template this.template = null; // The template image. this.templateState = ''; // The state of the template ('blob', 'proccessing', 'template', etc.) + /** @type {Array