Polish Codewars with cleaner training pages, better editor typography, responsive fixes, subtle typing effects, and promotion cleanup.
// ==UserScript==
// @name Prettier Codewars
// @namespace https://codewars.com/
// @version 1.2.0
// @description Polish Codewars with cleaner training pages, better editor typography, responsive fixes, subtle typing effects, and promotion cleanup.
// @author NihilDigit
// @match https://www.codewars.com/*
// @match https://codewars.com/*
// @icon https://www.codewars.com/favicon.ico
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @run-at document-start
// @license MIT
// ==/UserScript==
(function () {
"use strict";
const STYLE_ID = "cw-polish-style";
const HIDDEN_MARK = "data-cw-polish-hidden";
const SPARKS_ID = "cw-polish-sparks";
const STORAGE_PREFIX = "prettier-codewars:";
const defaultConfig = {
hidePromotions: true,
useMapleMono: true,
tuneCodeMirror: true,
lineWrapping: true,
autoFormat: true,
lightweightAutocomplete: true,
typingSparks: true,
deleteAnnihilation: true,
editorFontSize: "15px",
editorLineHeight: 1.55
};
const menuOptions = [
["hidePromotions", "Hide promotions"],
["useMapleMono", "Maple Mono font"],
["tuneCodeMirror", "CodeMirror polish"],
["lineWrapping", "Line wrapping"],
["autoFormat", "AutoFormat"],
["lightweightAutocomplete", "Lightweight autocomplete"],
["typingSparks", "Typing sparks"],
["deleteAnnihilation", "Delete annihilation"]
];
const C_KEYWORDS = [
"auto",
"break",
"case",
"char",
"const",
"continue",
"default",
"do",
"double",
"else",
"enum",
"extern",
"float",
"for",
"goto",
"if",
"inline",
"int",
"long",
"register",
"restrict",
"return",
"short",
"signed",
"sizeof",
"static",
"struct",
"switch",
"typedef",
"union",
"unsigned",
"void",
"volatile",
"while"
];
const C_STANDARD_WORDS = [
"EOF",
"FILE",
"NULL",
"SEEK_CUR",
"SEEK_END",
"SEEK_SET",
"bool",
"calloc",
"char",
"double",
"errno",
"exit",
"fclose",
"feof",
"ferror",
"fflush",
"fgets",
"fopen",
"fprintf",
"fputc",
"fputs",
"fread",
"free",
"fscanf",
"fseek",
"ftell",
"fwrite",
"getchar",
"int16_t",
"int32_t",
"int64_t",
"int8_t",
"intptr_t",
"malloc",
"max_align_t",
"memcmp",
"memcpy",
"memmove",
"memset",
"offsetof",
"printf",
"ptrdiff_t",
"putchar",
"puts",
"qsort",
"realloc",
"scanf",
"size_t",
"snprintf",
"sprintf",
"sscanf",
"stderr",
"stdin",
"stdout",
"strcat",
"strchr",
"strcmp",
"strcpy",
"strlen",
"strncmp",
"strncpy",
"strrchr",
"strstr",
"strtol",
"strtoul",
"uint16_t",
"uint32_t",
"uint64_t",
"uint8_t",
"uintptr_t",
"va_arg",
"va_end",
"va_list",
"va_start",
"void"
];
function readSetting(key) {
const fallback = defaultConfig[key];
const storageKey = STORAGE_PREFIX + key;
try {
if (typeof GM_getValue === "function") {
return GM_getValue(storageKey, fallback);
}
const value = window.localStorage.getItem(storageKey);
return value === null ? fallback : JSON.parse(value);
} catch (_error) {
return fallback;
}
}
function writeSetting(key, value, reload = true) {
const storageKey = STORAGE_PREFIX + key;
try {
if (typeof GM_setValue === "function") {
GM_setValue(storageKey, value);
} else {
window.localStorage.setItem(storageKey, JSON.stringify(value));
}
} catch (_error) {
return;
}
if (reload) {
window.location.reload();
}
}
function readConfig() {
return Object.fromEntries(Object.keys(defaultConfig).map((key) => [key, readSetting(key)]));
}
const config = readConfig();
const effectColors = {
sparks: ["#ffd166", "#ff9f1c", "#ff6b35", "#e5383b", "#fff3b0"]
};
function buildCss() {
return `
${
config.hidePromotions
? `
[data-cw-polish-hidden="true"] {
display: none !important;
}
.partner-display,
.promoted {
display: none !important;
}
`
: ""
}
${
config.useMapleMono
? `
@font-face {
font-family: "Maple Mono Web";
font-style: normal;
font-weight: 400;
font-display: swap;
src:
local("Maple Mono NF"),
local("MapleMono NF"),
local("Maple Mono Normal NF"),
url("https://cdn.jsdelivr.net/fontsource/fonts/maple-mono@latest/latin-400-normal.woff2") format("woff2");
}
@font-face {
font-family: "Maple Mono Web";
font-style: italic;
font-weight: 400;
font-display: swap;
src:
local("Maple Mono NF Italic"),
local("MapleMono NF Italic"),
local("Maple Mono Normal NF Italic"),
url("https://cdn.jsdelivr.net/fontsource/fonts/maple-mono@latest/latin-400-italic.woff2") format("woff2");
}
.CodeMirror,
.CodeMirror pre,
.CodeMirror code,
.CodeMirror-line,
.CodeMirror-line *,
pre,
code,
kbd,
samp {
font-family: "Maple Mono Web", "Maple Mono NF", "Maple Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace !important;
font-variant-ligatures: contextual common-ligatures !important;
}
`
: ""
}
${
config.tuneCodeMirror
? `
.CodeMirror {
font-size: ${config.editorFontSize} !important;
line-height: ${config.editorLineHeight} !important;
}
.CodeMirror-lines,
.CodeMirror pre.CodeMirror-line,
.CodeMirror pre.CodeMirror-line-like {
line-height: ${config.editorLineHeight} !important;
}
.CodeMirror-cursor {
transition:
left 80ms ease-out,
top 80ms ease-out,
height 80ms ease-out !important;
}
.CodeMirror-activeline-background {
background: rgb(255 255 255 / 5.5%) !important;
}
.CodeMirror-hscrollbar {
display: none !important;
}
.CodeMirror-scroll {
overflow-x: hidden !important;
}
`
: ""
}
#description_area .description-content[data-cw-polish-short-overflow="true"] {
overflow: visible !important;
}
#description_area .description.h-full > :not(.description-content) {
display: none !important;
}
#description_area .description.h-full {
overflow: hidden !important;
}
#description_area .description-content.p-4 {
height: 100% !important;
overflow: auto !important;
}
.CodeMirror-hints {
z-index: 2147483646 !important;
border: 1px solid rgb(255 255 255 / 14%) !important;
border-radius: 6px !important;
background: rgb(18 20 26 / 96%) !important;
box-shadow: 0 12px 30px rgb(0 0 0 / 35%) !important;
color: rgb(238 241 246 / 94%) !important;
font-family: "Maple Mono Web", "Maple Mono NF", "Maple Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace !important;
font-size: 13px !important;
}
.CodeMirror-hint {
border-radius: 4px !important;
color: inherit !important;
}
li.CodeMirror-hint-active {
background: rgb(232 98 36 / 92%) !important;
color: white !important;
}
#cw-polish-sparks {
position: fixed;
inset: 0;
z-index: 2147483647;
pointer-events: none;
overflow: hidden;
}
@media (max-width: 1100px) {
body.play_view #cc_play_view .game-title .panel > .flex.flex-col.md\\:flex-row {
flex-direction: column !important;
}
body.play_view #cc_play_view .game-title .w-full.md\\:w-5\\/12,
body.play_view #cc_play_view .game-title .w-full.md\\:w-7\\/12 {
width: 100% !important;
}
body.play_view #cc_play_view .game-title .w-full.md\\:w-7\\/12.pt-4.md\\:pl-4 {
display: flex !important;
flex-wrap: wrap !important;
align-items: stretch !important;
gap: 8px !important;
padding-left: 0 !important;
padding-top: 12px !important;
}
body.play_view #cc_play_view .game-title .language-selector,
body.play_view #cc_play_view .game-title #language_dd,
body.play_view #cc_play_view .game-title #language_version {
flex: 1 1 180px !important;
min-width: 160px !important;
max-width: none !important;
}
body.play_view #cc_play_view .game-title .w-full.md\\:w-7\\/12.pt-4.md\\:pl-4 > a {
display: flex !important;
flex: 0 0 auto !important;
}
}
@media (max-width: 1000px) {
body#users.show_view main .bg-ui-section .flex.flex-col.md\\:flex-row {
flex-direction: column !important;
align-items: stretch !important;
}
body#users.show_view main .bg-ui-section .flex.flex-col.md\\:flex-row > .w-full.md\\:w-6\\/12 {
width: 100% !important;
padding-left: 0 !important;
}
body#users.show_view #report .honor-chart-container {
display: grid !important;
grid-template-columns: 220px minmax(220px, 1fr) !important;
align-items: center !important;
column-gap: 32px !important;
width: max-content !important;
max-width: 100% !important;
margin: 16px auto 0 !important;
}
body#users.show_view #report #honor_chart {
grid-column: 1 !important;
}
body#users.show_view #report .honor-chart-center {
left: 55px !important;
top: 55px !important;
}
body#users.show_view #report .honor-chart-container > .md\\:w-64 {
position: static !important;
grid-column: 2 !important;
width: auto !important;
height: auto !important;
overflow: visible !important;
padding-left: 0 !important;
margin-top: 0 !important;
}
}
@media (max-width: 720px) {
body#users.show_view main .bg-ui-section .flex.flex-col.md\\:flex-row {
flex-direction: column !important;
}
body#users.show_view main .bg-ui-section .flex.flex-col.md\\:flex-row > .w-full.md\\:w-6\\/12 {
width: 100% !important;
}
body#users.show_view #report .honor-chart-container {
grid-template-columns: 1fr !important;
justify-items: center !important;
row-gap: 18px !important;
width: 100% !important;
}
body#users.show_view #report .honor-chart-container > .md\\:w-64 {
grid-column: 1 !important;
}
}
`;
}
const adSelectors = [
"#house_ad_display",
".cw-ad",
".ads-container",
"[id*='ad_display' i]",
"[id*='ad-container' i]",
"[class*='ad-container' i]",
"a[href*='/ads/']",
"a[href*='house_srv']",
"iframe[src*='ad' i]",
"ins.adsbygoogle",
".partner-display",
".promoted",
".my-4.flex.flex-col.md\\:flex-row.space-y-4.md\\:space-y-0.md\\:space-x-4",
".mt-4.flex.flex-col.md\\:flex-row.space-y-4.md\\:space-y-0.md\\:space-x-4"
];
const classSetBlocklist = [
["my-4", "flex", "flex-col", "md:flex-row", "space-y-4", "md:space-y-0", "md:space-x-4"],
["mt-4", "flex", "flex-col", "md:flex-row", "space-y-4", "md:space-y-0", "md:space-x-4"],
["description-footer", "flex", "flex-row"],
["w-256", "max-w-full", "mx-auto", "my-4"],
["partner-display"],
["promoted"]
];
function injectStyle() {
let style = document.getElementById(STYLE_ID);
if (!style) {
style = document.createElement("style");
style.id = STYLE_ID;
(document.head || document.documentElement).append(style);
}
style.id = STYLE_ID;
style.textContent = buildCss();
}
function registerSettingsMenu() {
if (typeof GM_registerMenuCommand !== "function") return;
menuOptions.forEach(([key, label]) => {
const state = config[key] ? "On" : "Off";
GM_registerMenuCommand(`${state} - ${label}`, () => writeSetting(key, !config[key]));
});
GM_registerMenuCommand(`Set editor font size (${config.editorFontSize})`, () => {
const value = window.prompt("Editor font size, for example 15px:", config.editorFontSize);
if (value && /^\d+(?:\.\d+)?(?:px|rem|em)$/.test(value.trim())) {
writeSetting("editorFontSize", value.trim());
}
});
GM_registerMenuCommand(`Set editor line height (${config.editorLineHeight})`, () => {
const value = window.prompt("Editor line height, for example 1.55:", String(config.editorLineHeight));
const numberValue = Number(value);
if (Number.isFinite(numberValue) && numberValue >= 1 && numberValue <= 3) {
writeSetting("editorLineHeight", numberValue);
}
});
GM_registerMenuCommand("Reset Prettier Codewars settings", () => {
Object.entries(defaultConfig).forEach(([key, value]) => writeSetting(key, value, false));
window.location.reload();
});
}
function hide(node) {
if (node && node.nodeType === Node.ELEMENT_NODE) {
node.setAttribute(HIDDEN_MARK, "true");
}
}
function isProtected(element) {
return Boolean(
element.closest("html, body") === element ||
element.matches("main, #main_header, #trainer, #trainer *") ||
element.querySelector?.("#trainer")
);
}
function hideSafely(element) {
if (!element || isProtected(element)) return;
hide(element);
}
function nearestAdContainer(element) {
return (
element.closest(
"#house_ad_display, .ads-container, .cw-ad, aside, article, section:not(#trainer), .panel, div[class*='md:w-'], div[class*='w-full']"
) ||
element
);
}
function removeAds(root = document) {
if (!config.hidePromotions) return;
for (const selector of adSelectors) {
root.querySelectorAll(selector).forEach((element) => hideSafely(nearestAdContainer(element)));
}
root.querySelectorAll("div").forEach((element) => {
if (classSetBlocklist.some((classSet) => classSet.every((name) => element.classList.contains(name)))) {
hideSafely(element);
}
});
}
function tuneEditors(root = document) {
if (!config.tuneCodeMirror) return;
const mirrors = [];
if (root.matches?.(".CodeMirror")) {
mirrors.push(root);
}
if (root.querySelectorAll) {
mirrors.push(...root.querySelectorAll(".CodeMirror"));
}
mirrors.forEach((element) => {
if (element.CodeMirror) {
tuneEditor(element.CodeMirror);
scheduleInitialAutoFormat(element.CodeMirror, element);
if (config.typingSparks || config.deleteAnnihilation) {
attachEffects(element.CodeMirror);
}
}
});
}
function tuneEditor(cm) {
const optionsKey = [config.lineWrapping, 4, 4, false].join(":");
if (cm.__cwPolishOptionsKey !== optionsKey) {
cm.__cwPolishOptionsKey = optionsKey;
cm.setOption("lineWrapping", config.lineWrapping);
cm.setOption("indentUnit", 4);
cm.setOption("tabSize", 4);
cm.setOption("indentWithTabs", false);
cm.refresh();
}
attachEditorFeatures(cm);
}
function scheduleInitialAutoFormat(cm, element) {
if (!config.autoFormat || cm.__cwPolishInitialFormatted || !isCMode(cm) || !isSolutionEditor(element)) return;
cm.__cwPolishInitialFormatted = true;
window.setTimeout(() => {
if (!cm.getWrapperElement?.().isConnected) return;
autoFormat(cm);
}, 200);
}
function isSolutionEditor(element) {
return document.querySelector(".CodeMirror") === element;
}
function attachEditorFeatures(cm) {
if (cm.__cwPolishFeatures) return;
cm.__cwPolishFeatures = true;
const keyMap = {
Tab: (instance) => {
insertSpaces(instance, 4);
return true;
}
};
if (config.autoFormat) {
keyMap["Alt-Shift-F"] = (instance) => {
autoFormat(instance);
return true;
};
}
if (config.lightweightAutocomplete && isCMode(cm)) {
keyMap["Ctrl-Space"] = (instance) => {
showIdentifierHints(instance, true);
return true;
};
cm.on("inputRead", (instance, change) => {
if (instance.state.completionActive || !change.text || change.text.length !== 1) return;
if (!/^[A-Za-z_$]$/.test(change.text[0])) return;
const prefix = currentPrefix(instance);
if (prefix.length >= 2) {
showIdentifierHints(instance, false);
}
});
}
cm.addKeyMap(keyMap);
}
function insertSpaces(cm, count) {
const spaces = " ".repeat(count);
if (typeof cm.replaceSelections === "function" && typeof cm.listSelections === "function") {
cm.replaceSelections(cm.listSelections().map(() => spaces), "end", "+input");
return;
}
cm.replaceSelection(spaces, "end", "+input");
}
function autoFormat(cm) {
if (!cm || typeof cm.indentLine !== "function") return;
const cursor = cm.getCursor();
const scroll = cm.getScrollInfo();
if (isCMode(cm)) {
const formatted = formatKAndRC(cm.getValue());
if (formatted !== cm.getValue()) {
cm.setValue(formatted);
}
}
cm.operation(() => {
for (let line = cm.firstLine(); line <= cm.lastLine(); line += 1) {
cm.indentLine(line, "smart");
}
});
cm.setCursor(cursor);
cm.scrollTo(scroll.left, scroll.top);
}
function formatKAndRC(text) {
const normalized = text.replace(/\t/g, " ");
const lines = normalized.split("\n");
const output = [];
lines.forEach((line) => {
const leading = line.match(/^\s*/)[0];
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("//") || trimmed.startsWith("*")) {
output.push(line);
return;
}
if (trimmed === "{" && output.length > 0) {
const previous = output[output.length - 1];
const previousTrimmed = previous.trim();
if (isKAndRBraceLine(previousTrimmed)) {
output[output.length - 1] = `${previous.replace(/\s*$/, "")} {`;
return;
}
}
if (/^else\b/.test(trimmed) && output.length > 0 && output[output.length - 1].trim() === "}") {
output[output.length - 1] = `${output[output.length - 1].replace(/\s*$/, "")} ${trimmed}`;
return;
}
output.push(line.replace(/^(\s*)}\s*else\b/, "$1} else"));
});
return output.join("\n");
}
function isKAndRBraceLine(beforeBrace) {
return (
/^(?:if|for|while|switch)\s*\(.*\)$/.test(beforeBrace) ||
/^}?\s*else(?:\s+if\s*\(.*\))?$/.test(beforeBrace) ||
/^do$/.test(beforeBrace) ||
/^(?:[A-Za-z_]\w*[\w\s*]*\s+)?[A-Za-z_]\w*\s*\([^;]*\)$/.test(beforeBrace) ||
/^(?:struct|union|enum)\b.*$/.test(beforeBrace)
);
}
function showIdentifierHints(cm, explicit) {
if (!cm || !isCMode(cm) || typeof cm.showHint !== "function") return;
const hints = buildIdentifierHints(cm);
if (!explicit && hints.list.length < 2) return;
cm.showHint({
hint: () => hints,
completeSingle: false,
closeCharacters: /[\s()[\]{};:>,]/,
customKeys: {
Tab: (_editor, handle) => handle.pick(),
Enter: (_editor, handle) => handle.pick(),
Esc: (_editor, handle) => handle.close(),
Up: (_editor, handle) => handle.moveFocus(-1),
Down: (_editor, handle) => handle.moveFocus(1)
}
});
}
function buildIdentifierHints(cm) {
const cursor = cm.getCursor();
const prefix = currentPrefix(cm);
const from = { line: cursor.line, ch: cursor.ch - prefix.length };
const to = { line: cursor.line, ch: cursor.ch };
const candidates = buildCompletionCandidates(cm, cursor);
const seen = new Set();
const list = candidates
.filter((word) => {
const normalized = word.toLowerCase();
if (seen.has(normalized)) return false;
seen.add(normalized);
return word.length > 1 && word !== prefix && (!prefix || normalized.startsWith(prefix.toLowerCase()));
})
.slice(0, 80);
return { list, from, to };
}
function buildCompletionCandidates(cm, cursor) {
const text = cm.getValue();
const cache = cm.__cwPolishCompletionCache;
if (cache && cache.text === text && cache.line === cursor.line) {
return cache.candidates;
}
const candidates = [
...collectLocalIdentifiers(cm, cursor),
...collectPreprocessorIdentifiers(text),
...C_STANDARD_WORDS,
...C_KEYWORDS
];
cm.__cwPolishCompletionCache = {
candidates,
text,
line: cursor.line
};
return candidates;
}
function collectLocalIdentifiers(cm, cursor) {
const startLine = findLocalBlockStart(cm, cursor.line);
const endLine = findLocalBlockEnd(cm, cursor.line);
const text = cm.getRange({ line: startLine, ch: 0 }, { line: endLine, ch: cm.getLine(endLine).length });
return collectIdentifiers(text);
}
function collectPreprocessorIdentifiers(text) {
const identifiers = [];
const definePattern = /^\s*#\s*define\s+([A-Za-z_]\w*)/gm;
let match;
while ((match = definePattern.exec(text))) {
identifiers.push(match[1]);
}
return identifiers;
}
function findLocalBlockStart(cm, line) {
let depth = 0;
for (let index = line; index >= cm.firstLine(); index -= 1) {
const text = stripCCommentsAndStrings(cm.getLine(index));
for (let ch = text.length - 1; ch >= 0; ch -= 1) {
if (text[ch] === "}") depth += 1;
if (text[ch] === "{") {
if (depth === 0) return Math.max(cm.firstLine(), index - 1);
depth -= 1;
}
}
}
return cm.firstLine();
}
function findLocalBlockEnd(cm, line) {
let depth = 0;
for (let index = line; index <= cm.lastLine(); index += 1) {
const text = stripCCommentsAndStrings(cm.getLine(index));
for (let ch = 0; ch < text.length; ch += 1) {
if (text[ch] === "{") depth += 1;
if (text[ch] === "}") {
if (depth === 0) return index;
depth -= 1;
if (depth === 0) return index;
}
}
}
return cm.lastLine();
}
function collectIdentifiers(text) {
const identifiers = [];
const wordPattern = /\b[A-Za-z_]\w*\b/g;
const cleaned = stripCCommentsAndStrings(text);
let match;
while ((match = wordPattern.exec(cleaned))) {
identifiers.push(match[0]);
}
return identifiers;
}
function stripCCommentsAndStrings(text) {
return text
.replace(/\/\*[\s\S]*?\*\//g, " ")
.replace(/\/\/.*/g, " ")
.replace(/"(?:\\.|[^"\\])*"/g, " ")
.replace(/'(?:\\.|[^'\\])*'/g, " ");
}
function currentPrefix(cm) {
const cursor = cm.getCursor();
const line = cm.getLine(cursor.line).slice(0, cursor.ch);
const match = line.match(/[A-Za-z_$][\w$]*$/);
return match ? match[0] : "";
}
function isCMode(cm) {
return languageKey(cm.getOption("mode")) === "c";
}
function languageKey(mode) {
const value = String(mode || "").toLowerCase();
if (value === "text/x-c" || value === "text/x-csrc" || value === "text/x-chdr") return "c";
return "";
}
function attachRunAutoFormat() {
if (!config.autoFormat || document.__cwPolishRunAutoFormat) return;
document.__cwPolishRunAutoFormat = true;
document.addEventListener(
"click",
(event) => {
if (!event.target.closest?.("#validate_btn, #attempt_btn, #submit_btn")) return;
const solutionEditor = document.querySelector(".CodeMirror")?.CodeMirror;
autoFormat(solutionEditor);
},
true
);
}
function ensureSparkLayer() {
let layer = document.getElementById(SPARKS_ID);
if (!layer) {
layer = document.createElement("div");
layer.id = SPARKS_ID;
document.documentElement.append(layer);
}
return layer;
}
function sparkAt(x, y, intensity = 1) {
const layer = ensureSparkLayer();
const count = Math.min(7, Math.max(3, Math.round(4 * intensity)));
for (let index = 0; index < count; index += 1) {
const spark = document.createElement("i");
const angle = -Math.PI + Math.random() * Math.PI;
const distance = 18 + Math.random() * 34 * intensity;
const dx = Math.cos(angle) * distance;
const dy = Math.sin(angle) * distance - Math.random() * 8;
const size = 4 + Math.random() * 4;
const color = effectColors.sparks[Math.floor(Math.random() * effectColors.sparks.length)];
const rotation = (Math.random() - 0.5) * 160;
spark.style.cssText = [
"position:absolute",
`left:${x}px`,
`top:${y}px`,
`width:${size}px`,
`height:${size}px`,
`background:${color}`,
"border-radius:1px",
`box-shadow:0 0 ${7 + size * 2}px ${color}`,
`transform:translate(-50%,-50%) rotate(${rotation}deg) scale(1)`,
"opacity:.9",
"will-change:transform,opacity"
].join(";");
layer.append(spark);
spark
.animate(
[
{ transform: `translate(-50%, -50%) rotate(${rotation}deg) scale(1)`, opacity: 0.95 },
{
transform: `translate(calc(-50% + ${dx}px), calc(-50% + ${dy}px)) rotate(${rotation + 120}deg) scale(.25)`,
opacity: 0
}
],
{
duration: 520 + Math.random() * 260,
easing: "cubic-bezier(.16, 1, .3, 1)"
}
)
.finished.finally(() => spark.remove());
}
}
function annihilateAt(x, y, intensity = 1) {
const layer = ensureSparkLayer();
const driftX = -5 - Math.random() * 8;
const driftY = -2 + (Math.random() - 0.5) * 6;
const count = Math.min(5, Math.max(3, Math.round(4 * intensity)));
for (let index = 0; index < count; index += 1) {
const voidBit = document.createElement("i");
const angle = Math.random() * Math.PI * 2;
const distance = 18 + Math.random() * 32 * intensity;
const sx = Math.cos(angle) * distance;
const sy = Math.sin(angle) * distance;
const endX = driftX * 0.35 + (Math.random() - 0.5) * 1.5;
const endY = driftY * 0.35 + (Math.random() - 0.5) * 1.5;
const size = 4 + Math.random() * 5;
const rotation = (Math.random() - 0.5) * 180;
voidBit.style.cssText = [
"position:absolute",
`left:${x}px`,
`top:${y}px`,
`width:${size}px`,
`height:${size}px`,
"background:oklch(5% 0.01 265 / .92)",
"border-radius:2px",
"box-shadow:0 0 8px oklch(0% 0 0 / .9)",
`transform:translate(calc(-50% + ${sx}px), calc(-50% + ${sy}px)) rotate(${rotation}deg) scale(1)`,
"opacity:.86",
"will-change:transform,opacity,filter"
].join(";");
layer.append(voidBit);
voidBit
.animate(
[
{
transform: `translate(calc(-50% + ${sx}px), calc(-50% + ${sy}px)) rotate(${rotation}deg) scale(1)`,
opacity: 0.86
},
{
transform: `translate(calc(-50% + ${endX}px), calc(-50% + ${endY}px)) rotate(${rotation + 210}deg) scale(.05)`,
opacity: 0
}
],
{
duration: 500 + Math.random() * 140,
easing: "cubic-bezier(.55, 0, .1, 1)"
}
)
.finished.finally(() => voidBit.remove());
}
}
function attachEffects(cm) {
if (cm.__cwPolishEffects) return;
cm.__cwPolishEffects = true;
let lastSpark = 0;
cm.on("change", (_instance, change) => {
if (!change.origin || change.origin === "setValue") return;
const now = performance.now();
if (now - lastSpark < 30) return;
lastSpark = now;
const cursor = cm.getCursor();
const pos = cm.cursorCoords(cursor, "window");
const typed = change.text.join("").length;
const removed = change.removed ? change.removed.join("").length : 0;
const x = pos.left + 2;
const y = pos.top + (pos.bottom - pos.top) / 2;
if (typed > 0 && config.typingSparks) {
sparkAt(x, y, Math.min(1.8, 1 + typed / 8));
} else if (removed > 0 && config.deleteAnnihilation) {
annihilateAt(x, y, Math.min(1.6, 1 + removed / 8));
}
});
}
function tuneDescriptionScroll(root = document) {
const contents = [];
if (root.matches?.("#description_area .description-content")) {
contents.push(root);
}
if (root.querySelectorAll) {
contents.push(...root.querySelectorAll("#description_area .description-content"));
}
contents.forEach((element) => {
if (element.scrollHeight - element.clientHeight <= 20) {
element.setAttribute("data-cw-polish-short-overflow", "true");
} else {
element.removeAttribute("data-cw-polish-short-overflow");
}
});
}
function boot() {
registerSettingsMenu();
injectStyle();
removeAds();
tuneEditors();
tuneDescriptionScroll();
attachRunAutoFormat();
[100, 300, 800, 1500, 3000].forEach((delay) => {
window.setTimeout(() => {
injectStyle();
removeAds();
tuneEditors();
tuneDescriptionScroll();
}, delay);
});
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
removeAds(node);
tuneEditors(node);
tuneDescriptionScroll(node);
}
}
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", boot, { once: true });
injectStyle();
} else {
boot();
}
})();