[1.11k+] Sticker System | Animated emotes, overhead popups, live reaction GUI and more!

26/07/2026

  • Sticker bubbles created by Anchor & Glue mode will no longer cause z-fighting/overlapping when there are many in the same spot

  • Stickers with randomized animations/sounds/sprites/effects will pick the same results across clients in order to sync on all clients (Server will decide a global seed and send along with the sticker visual info)

  • Fixed “summon Sticker” effect placing stickers in the wrong location

  • Fixed Viewport type not showing for Anchor placement mode

  • Fixed workspace’s name showing on the live sticker GUI for parts in workspace that are using stickers

  • Added sounds to a ton of stickers

  • Added 14 new stickers: Spider Land, UFO, Morning Sunshine, Nightfall Moonlight, Retrowave Synthwave, Jester Stare, Ninja Think, Adventurer Dance, Goddess Dance, Crusader Dance, Wizard Dance, Yakuza Dance, Pepe Lag, Chicken Pog

pomni-tadc-ezgif.com-crop
Sticker of the day: Jester Stare

1 Like

08/08/2026

  • Fixed “Sticker” effect live sticker GUI not using the color of the main sticker (Few stickers can spawn even more stickers, those did not share the same color, that’s all)

  • Fixed a potential issue when clearing active stickers makes new sticker bubbles not show up

  • Fixed effects appearing from the original position of the player character when the sticker holding them were used rather than the current position (Caused by recent update)

  • Added a ClearAllStickers() function so you can remove all currently active stickers from the server. A new block has been added as an example in the test place

  • Toggle the use of stickers with SetStickersEnabled() from the server during run time. Players in your bypass list can bypass this. A new block has also been added as an example for this one in the test place

  • You can now send custom notifications to players from the server with the same SendNotification function

  • Added “Random” sort order option

  • Added a ton of sounds to various stickers

  • Added 7 new stickers: Doom Metal Jam, Kuru Kuru, Ninja Facepalm, Emoji Cringe, Wojak Boomer, Pirate Smirk, Emoji Wilted Rose

fnaf-five-nights-at-freddy's
Sticker of the day: Animatronic Dance

I finally added a section for API in the main post
It took me around 2 hours to type, shorten and decorate the post!

This is a really nice resource!! I used some stickers for my game.

1 Like

That looks awesome!
Finally someone who tells me about their game using stickers :cold_face:
I only know 2 games with this system due to that reason lol

1 Like

Oh yeah what is the name of the game if its open?
I wanna check it out if possible

It isnt open yet, the game is called “Kombat”
Send me friend request on discord so I send you the server invitation!
r.enka

1 Like

The test place should save in your home page and show up in search now
It was hidden for certain regions like mine because the age label was incorrect

Also working on a QOL update to give more server controls + displaying permanent stickers

Super unrelated, but this game looks so cool. Remake of combat warriors?

1 Like

Moved this to a reply to save space in the main post

// ==UserScript==
// @name         EzGif to Sprite Settings
// @match        https://ezgif.com/gif-to-sprite*
// @match        https://ezgif.com/resize/*
// @grant        none
// @version      1.6
// ==/UserScript==

(function() {
    'use strict';

    const MAX_CELL_SIZE = 1024;
    let overLimitStreak = 0;

    function createOutputPanel() {
        if (document.getElementById('roblox-config-container')) return;
        const container = document.createElement('div');
        container.id = 'roblox-config-container';
        Object.assign(container.style, {
            position: 'fixed', bottom: '20px', right: '20px', zIndex: '99999',
            background: '#1a1a1a', padding: '12px', borderRadius: '8px',
            border: '2px solid #0084ff', boxShadow: '0 4px 20px rgba(0,0,0,0.8)',
            display: 'flex', flexDirection: 'column', gap: '8px', width: '320px'
        });

        const header = document.createElement('div');
        header.style.display = 'flex';
        header.style.justifyContent = 'space-between';
        header.style.alignItems = 'center';

        const label = document.createElement('span');
        label.innerText = "Set Columns:";
        label.style.color = '#00ff00'; label.style.fontSize = '12px'; label.style.fontWeight = 'bold';

        const colInput = document.createElement('input');
        colInput.type = 'number';
        colInput.id = 'rbx-manual-cols';
        colInput.value = localStorage.getItem('rbx_cols') || "0";
        Object.assign(colInput.style, {
            width: '60px', background: '#333', color: '#fff', border: '1px solid #00ff00',
            borderRadius: '4px', padding: '4px', textAlign: 'center', fontWeight: 'bold'
        });

        colInput.oninput = () => { localStorage.setItem('rbx_cols', colInput.value); };

        const output = document.createElement('div');
        output.id = 'roblox-config-output';
        Object.assign(output.style, {
            color: '#00ff00', fontFamily: 'monospace', fontSize: '11px',
            whiteSpace: 'pre', overflowX: 'auto', background: '#000',
            padding: '12px', borderRadius: '4px', border: '1px solid #333',
            userSelect: 'text', cursor: 'text', minHeight: '150px'
        });

        const copyBtn = document.createElement('button');
        copyBtn.innerText = "📋 COPY ALL";

        Object.assign(copyBtn.style, {
            padding: '8px',
            cursor: 'pointer',
            background: '#0084ff',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            fontWeight: 'bold',
            transition: '0.15s ease'
        });

        copyBtn.onclick = async () => {
            await navigator.clipboard.writeText(output.innerText);

            const oldText = copyBtn.innerText;
            const oldColor = copyBtn.style.background;

            copyBtn.innerText = "✅ COPIED!";
            copyBtn.style.background = '#00aa44';

            setTimeout(() => {
                copyBtn.innerText = oldText;
                copyBtn.style.background = oldColor;
            }, 900);
        };

        header.style.cursor = 'move';
        header.addEventListener('mousedown', (e) => {
            if (e.target.tagName === 'INPUT') return;
            const rect = container.getBoundingClientRect();
            const offsetX = e.clientX - rect.left;
            const offsetY = e.clientY - rect.top;
            container.style.left = rect.left + 'px';
            container.style.top = rect.top + 'px';
            container.style.right = 'auto';
            container.style.bottom = 'auto';
            const move = (ev) => {
                container.style.left = ev.clientX - offsetX + 'px';
                container.style.top = ev.clientY - offsetY + 'px';
            };
            const up = () => {
                document.removeEventListener('mousemove', move);
                document.removeEventListener('mouseup', up);
            };
            document.addEventListener('mousemove', move);
            document.addEventListener('mouseup', up);
            e.preventDefault();
        });

        header.appendChild(label);
        header.appendChild(colInput);
        container.appendChild(header);
        container.appendChild(output);
        container.appendChild(copyBtn);
        document.body.appendChild(container);
    }

    function getOutputImage() {
        const inOutput = Array.from(document.querySelectorAll('#output img')).filter(img => img.naturalWidth > 10);
        const pool = inOutput.length ? inOutput : Array.from(document.querySelectorAll('img[src*="/resize/"], img[src*="ezgif.com/tmp/"]')).filter(img => img.naturalWidth > 10);
        if (!pool.length) return null;
        return pool.reduce((a, b) =>
                           (a.naturalWidth * a.naturalHeight >= b.naturalWidth * b.naturalHeight) ? a : b
                          );
    }

    function setOutputState(text, valid) {
        const output = document.getElementById('roblox-config-output');
        output.innerText = text;
        output.style.color = valid ? '#00ff00' : '#ff3333';
        output.style.border = valid ? '1px solid #333' : '1px solid #ff3333';
    }

    function update() {
        if (window.getSelection().toString().length > 0) return;

        const manualInput = document.getElementById('rbx-manual-cols');
        const ezInput = document.getElementById('hor-images');

        let cols = parseInt(localStorage.getItem('rbx_cols')) || 0;
        if (ezInput && parseInt(ezInput.value) > 0) {
            cols = parseInt(ezInput.value);
            localStorage.setItem('rbx_cols', cols);
            if (manualInput) manualInput.value = cols;
        } else if (manualInput) {
            const manualVal = parseInt(manualInput.value);
            cols = (manualVal > 0) ? manualVal : 0;
        }

        const colsValid = cols > 0;
        if (manualInput) {
            manualInput.style.border = colsValid ? '1px solid #00ff00' : '1px solid #ff3333';
            manualInput.style.color = colsValid ? '#fff' : '#ff3333';
        }

        const pageText = document.body.innerText;
        const info = pageText.match(/frames: (\d+).*length: (?:(\d{2}:\d{2}:\d{2}\.\d{2})|(\d+\.\d+))/i);

        let frames, fps, name;

        if (info) {
            frames = parseInt(info[1]);
            let duration = parseFloat(info[2] || info[3]) || 1;
            if (info[2]?.includes(':')) {
                duration = info[2].split(':').reduce((acc, t) => (acc * 60) + +t);
            }
            fps = Math.round(frames / duration);
            const nameEl = document.querySelector('.file-menu strong');
            name = nameEl ? nameEl.innerText.split('.')[0] : "Sprite";

            localStorage.setItem('rbx_frames', frames);
            localStorage.setItem('rbx_fps', fps);
            localStorage.setItem('rbx_name', name);
        } else {
            frames = parseInt(localStorage.getItem('rbx_frames')) || 0;
            fps = parseInt(localStorage.getItem('rbx_fps')) || 0;
            name = localStorage.getItem('rbx_name') || "Sprite";
        }

        const img = getOutputImage();
        if (!img) return;

        const w = img.naturalWidth, h = img.naturalHeight;

        if (!colsValid) {
            overLimitStreak = 0;
            setOutputState("Set a valid column count (> 0) above.", false);
            return;
        }

        const rows = Math.ceil(frames / cols);
        const cellW = w / cols;
        const cellH = rows > 0 ? h / rows : 0;

        const overLimit = cellW >= MAX_CELL_SIZE || cellH >= MAX_CELL_SIZE;
        overLimitStreak = overLimit ? overLimitStreak + 1 : 0;
        const confirmedOverLimit = overLimitStreak >= 2;

        const text = `["${name}"] = {
    Type = "Animated",
    Color = Color3.fromRGB(255, 255, 255),
    SpriteSettings = {
        ImageId = 0,
        ImageSize = Vector2.new(${w}, ${h}),
        CellSize = Vector2.new(${w}/${cols}, ${h}/${rows}),
        Display = 1,
        FPS = ${fps},
        End = ${frames},
        Looped = true
    },
},`;

        if (confirmedOverLimit) {
            setOutputState(text + `\n\n⚠ CellSize exceeds ${MAX_CELL_SIZE}px, reduce columns/rows`, false);
        } else {
            setOutputState(text, true);
        }
    }

    createOutputPanel();
    setInterval(update, 400);
})();

Moved this to a reply to save space in the main post

// ==UserScript==
// @name         Auto Update Decal Privacy
// @match        *://create.roblox.com/*
// @grant        window.close
// @grant        window.focus
// @version      1.6
// ==/UserScript==

(function () {
    const BATCH_OPEN_DELAY = 300;
    const QUEUE_KEY = "robloxDecalQueue";

    function updateStatus(msg, color = "#fff") {
        let status = document.getElementById("script-status-box");
        if (status && status.dataset.msg === msg) return;
        if (!status) {
            status = document.createElement("div");
            status.id = "script-status-box";
            Object.assign(status.style, {
                position: "fixed", top: "10px", left: "50%", transform: "translateX(-50%)",
                zIndex: "999999", padding: "8px 15px", background: "rgba(0,0,0,0.9)",
                color: color, borderRadius: "20px", fontSize: "12px", fontWeight: "bold",
                pointerEvents: "none", border: "1px solid #444"
            });
            document.body.appendChild(status);
        }
        status.dataset.msg = msg;
        status.innerText = "🤖 " + msg;
        status.style.color = color;
        status.style.display = "block";
        clearTimeout(status.hideTimer);
        status.hideTimer = setTimeout(() => { status.style.display = "none"; }, 3000);
    }

    // Instead of just closing, move on to the next queued decal page in this
    // same tab. Only close (and hand focus back to the dashboard) once the
    // queue is empty.
    function goToNextOrClose() {
        if (window.leaving) return;
        window.leaving = true;
        let queue = [];
        try { queue = JSON.parse(localStorage.getItem(QUEUE_KEY) || "[]"); } catch (e) { queue = []; }

        if (queue.length > 0) {
            const next = queue.shift();
            localStorage.setItem(QUEUE_KEY, JSON.stringify(queue));
            updateStatus("Next decal...", "#00ff00");
            window.location.href = next;
        } else {
            localStorage.setItem('roblox_decal_next_tab', Date.now());
            setTimeout(() => window.close(), 500);
        }
    }

    function runAutomationStep() {
        const url = window.location.href;
        if (!url.includes("/configure")) return;

        const bodyText = document.body.innerText;
        const buttons = Array.from(document.querySelectorAll('button'));
        const allSpans = Array.from(document.querySelectorAll('span'));

        // 1. Success toast
        const successFound = bodyText.includes("Successfully changed") || document.querySelector('div[class*="success"]');
        if (successFound) {
            updateStatus("Success! Moving on...", "#00ff00");
            goToNextOrClose();
            return;
        }

        // 2. Detect Enable banner presence (used in multiple steps below)
        const enableBtn = buttons.find(b => b.innerText.trim() === "Enable");
        const enableText = bodyText.includes("Click here to enable Asset Privacy");
        const enableBannerPresent = !!(enableBtn && enableText);

        // 3. Click Enable if banner is present
        if (enableBannerPresent) {
            updateStatus("Enabling Asset Privacy...", "#ffaa00");
            enableBtn.click();
            return;
        }

        // 4. Confirmation modal
        const confirmBtn = buttons.find(b => b.innerText.includes("Make Open Use"));
        if (confirmBtn) {
            updateStatus("Confirming Open Use...", "#0084ff");
            confirmBtn.click();
            return;
        }

        // 5. Detect radio controls (MUI or native)
        const openUseSpan = allSpans.find(s => s.innerText.trim() === "Open Use");
        const restrictedSpan = allSpans.find(s => s.innerText.trim() === "Restricted");

        const openUseRadio = document.querySelector('input[type="radio"][value*="open" i], input[type="radio"][value*="public" i]');
        const restrictedRadio = document.querySelector('input[type="radio"][value*="restrict" i], input[type="radio"][value*="private" i]');

        const hasRadioControls = openUseRadio || restrictedRadio
        || openUseSpan?.closest('[role="radio"]')
        || restrictedSpan?.closest('[role="radio"]');

        // 6. No radio controls visible
        if (!hasRadioControls) {
            // If Enable banner is still present in any form, page is still loading — wait
            if (enableBannerPresent || enableText || enableBtn) {
                updateStatus("Waiting for privacy options to load...", "#aaa");
                return;
            }

            // Only safe to move on when Enable banner is fully gone AND plain Open Use text is present
            const isPlainOpenUse = bodyText.includes("Anyone on Roblox can use this asset");
            if (isPlainOpenUse) {
                updateStatus("Already Open Use (no controls). Moving on...", "#00ff00");
                goToNextOrClose();
                return;
            }

            updateStatus("Waiting for privacy options...", "#aaa");
            return;
        }

        // 7. Determine current selection via aria-checked or input.checked
        const openUseAriaChecked = openUseSpan?.closest('[role="radio"]')?.getAttribute('aria-checked') === 'true'
        || openUseSpan?.parentElement?.getAttribute('aria-checked') === 'true';
        const isAlreadyOpenUse = openUseRadio?.checked || openUseAriaChecked;

        // 8. Already on Open Use — save if needed, else move on
        if (isAlreadyOpenUse) {
            const saveBtn = buttons.find(b => b.innerText.includes("Save Changes") && !b.disabled);
            if (saveBtn) {
                updateStatus("Saving...", "#0084ff");
                saveBtn.click();
            } else {
                updateStatus("Already Open Use. Moving on...", "#00ff00");
                goToNextOrClose();
            }
            return;
        }

        // 9. Switch to Open Use
        if (openUseSpan) {
            updateStatus("Switching to Open Use...", "#0084ff");
            const radioParent = openUseSpan.closest('[role="radio"]') || openUseSpan.parentElement;
            radioParent ? radioParent.click() : openUseSpan.click();
            return;
        }

        // 10. Save if available
        const saveBtn = buttons.find(b => b.innerText.includes("Save Changes") && !b.disabled);
        if (saveBtn) {
            updateStatus("Saving...", "#0084ff");
            saveBtn.click();
            return;
        }

        updateStatus("Waiting...", "#aaa");
    }

    // Best-effort extraction of a decal/image's display name from its link.
    // Tries the most likely spots in order: image alt text, title attribute,
    // aria-label, then finally falls back to whatever text is on the link.
    function getDecalName(link) {
        const img = link.querySelector('img');
        const raw = img?.alt || link.getAttribute('title') || link.getAttribute('aria-label') || link.innerText || "";
        // The link's text is "Name\nCreated <date>" — only keep the name line.
        const firstLine = raw.split('\n').map(s => s.trim()).find(s => s && !s.startsWith("Created"));
        return (firstLine || "").trim();
    }

    function handleDashboard() {
        const url = window.location.href;
        if (!url.includes("activeTab=Image") && !url.includes("/creations?")) return;

        if (!window.hasSetupFocusListener) {
            window.addEventListener('storage', (e) => {
                if (e.key === 'roblox_decal_next_tab') window.focus();
            });
            window.hasSetupFocusListener = true;
        }

        if (!document.getElementById("batchControlPanel")) {
            const panel = document.createElement("div");
            panel.id = "batchControlPanel";
            Object.assign(panel.style, {
                position: "fixed", bottom: "20px", right: "20px", zIndex: "99999",
                background: "#1a1a1a", padding: "15px", borderRadius: "8px", border: "1px solid #444",
                display: "flex", flexDirection: "column", gap: "8px", boxShadow: "0 4px 15px rgba(0,0,0,0.5)"
            });

            const createInput = (id, val, labelText) => {
                const container = document.createElement("div");
                container.style.display = "flex";
                container.style.justifyContent = "space-between";
                container.style.alignItems = "center";
                container.style.gap = "10px";

                const l = document.createElement("label");
                l.innerText = labelText;
                l.style.color = "white"; l.style.fontSize = "11px";

                const i = document.createElement("input");
                i.type = "number"; i.id = id; i.value = val;
                Object.assign(i.style, {
                    width: "50px", background: "#333", color: "white", border: "1px solid #555", borderRadius: "4px", padding: "3px"
                });

                container.appendChild(l);
                container.appendChild(i);
                return container;
            };

            const createTextInput = (id, val, labelText) => {
                const container = document.createElement("div");
                container.style.display = "flex";
                container.style.justifyContent = "space-between";
                container.style.alignItems = "center";
                container.style.gap = "10px";

                const l = document.createElement("label");
                l.innerText = labelText;
                l.style.color = "white"; l.style.fontSize = "11px";

                const i = document.createElement("input");
                i.type = "text"; i.id = id; i.value = val;
                Object.assign(i.style, {
                    width: "50px", background: "#333", color: "white", border: "1px solid #555", borderRadius: "4px", padding: "3px"
                });

                container.appendChild(l);
                container.appendChild(i);
                return container;
            };

            const createCheckbox = (id, labelText) => {
                const container = document.createElement("div");
                container.style.display = "flex";
                container.style.justifyContent = "space-between";
                container.style.alignItems = "center";
                container.style.gap = "10px";

                const l = document.createElement("label");
                l.innerText = labelText;
                l.htmlFor = id;
                l.style.color = "white"; l.style.fontSize = "11px";

                const i = document.createElement("input");
                i.type = "checkbox"; i.id = id;

                container.appendChild(l);
                container.appendChild(i);
                return container;
            };

            const startInp = createInput("rangeStart", "1", "Start at:");
            const endInp = createInput("rangeEnd", "10", "End at:");
            const sepInp = createTextInput("nameSeparator", ", ", "Separator:");
            const reverseInp = createCheckbox("reverseOrder", "Reverse order:");

            const btn = document.createElement("button");
            btn.innerText = "🚀 Set Privacy From Range";
            Object.assign(btn.style, {
                marginTop: "5px", padding: "10px", background: "#0084ff", color: "white",
                fontWeight: "bold", borderRadius: "6px", cursor: "pointer", border: "none"
            });

            // Instead of opening every target as its own tab, queue them up
            // and open just ONE tab. That tab will walk through the whole
            // queue itself (see goToNextOrClose) instead of closing and
            // dumping you back on this dashboard each time.
            btn.onclick = () => {
                const start = parseInt(document.getElementById("rangeStart").value) - 1;
                const end = parseInt(document.getElementById("rangeEnd").value);
                const links = Array.from(document.querySelectorAll('a[href*="/configure"]'));
                const reverse = document.getElementById("reverseOrder").checked;
                let targets = [...new Set(links.map(l => l.href))].slice(start, end);
                if (reverse) targets = targets.reverse();
                if (targets.length === 0) return alert("No decals found in that range!");

                const [first, ...rest] = targets;
                localStorage.setItem(QUEUE_KEY, JSON.stringify(rest));
                window.open(first, '_blank');
            };

            const copyBtn = document.createElement("button");
            copyBtn.innerText = "📋 Copy Names From Range";
            Object.assign(copyBtn.style, {
                marginTop: "5px", padding: "10px", background: "#444", color: "white",
                fontWeight: "bold", borderRadius: "6px", cursor: "pointer", border: "none"
            });

            copyBtn.onclick = () => {
                const start = parseInt(document.getElementById("rangeStart").value) - 1;
                const end = parseInt(document.getElementById("rangeEnd").value);
                const sep = document.getElementById("nameSeparator").value;
                const links = Array.from(document.querySelectorAll('a[href*="/configure"]'));
                const reverse = document.getElementById("reverseOrder").checked;
                let names = [...new Map(links.map(l => [l.href, l])).values()].slice(start, end).map(getDecalName).filter(Boolean);
                if (reverse) names = names.reverse();
                if (names.length === 0) return alert("No decals found in that range!");

                const joined = names.join(sep);
                navigator.clipboard.writeText(joined)
                    .then(() => updateStatus(`Copied ${names.length} names!`, "#00ff00"))
                    .catch(() => alert(joined));
            };

            panel.style.cursor = "move";
            panel.addEventListener("mousedown", (e) => {
                if (["INPUT", "BUTTON", "LABEL"].includes(e.target.tagName)) return;
                const rect = panel.getBoundingClientRect();
                const offsetX = e.clientX - rect.left;
                const offsetY = e.clientY - rect.top;
                panel.style.left = rect.left + "px";
                panel.style.top = rect.top + "px";
                panel.style.right = "auto";
                panel.style.bottom = "auto";
                const move = (ev) => {
                    panel.style.left = ev.clientX - offsetX + "px";
                    panel.style.top = ev.clientY - offsetY + "px";
                };
                const up = () => {
                    document.removeEventListener("mousemove", move);
                    document.removeEventListener("mouseup", up);
                };
                document.addEventListener("mousemove", move);
                document.addEventListener("mouseup", up);
                e.preventDefault();
            });

            panel.appendChild(startInp);
            panel.appendChild(endInp);
            panel.appendChild(sepInp);
            panel.appendChild(reverseInp);
            panel.appendChild(btn);
            panel.appendChild(copyBtn);
            document.body.appendChild(panel);
        }
    }

    setInterval(runAutomationStep, 1000);
    setInterval(handleDashboard, 1500);
})();

Free Model

Test Place

10/10/2026: [1.11k] Major Update, Occlusion Culling, Test Place: Simplified & Added More Examples, Packet Module, Permanent Displays, Search Bar: Autofill Suggestion & Command Syntax, Theme Setting, Organized Settings, +17 Stickers

  • Super duper uber performance optimizations using occlusion culling. Now sets bubble size to 0, stops tweening and running connections for sprite animation once out of view or max distance. BillboardGuis are very expensive, my FPS dropped a lot with over 1k animation sprites running, but it returned to normal once I looked away or moved out of the display range. My laptop is potato yet I can play just fine

  • The uncopylocked Test Place now simply has the free model inserted into ServerScriptService without any folders moved, in order to demonstrate that it is capable of setting things up automatically. This also makes updating things easier and avoids confusion for new devs who are not used to the interface. In short, everything is in 1 folder only (Optional)

  • Switched from using RemoteEvent and UnreliableEvent to Packet module. Less likely to miss an event

  • New SetStat() & AdjustStat() functions

  • New DisplaySticker() function for displaying a permanent sticker that also shows up for players who join late. It can be called from a server script but the visuals are still client sided for performance and can be removed from the server for everyone. Example: Use this to display a sticker on a TV’s SurfaceGui

  • Added a TV to play stickers one by one with intermission breaks in the Test Place. It has 2 built-in buttons, one is for skipping to another “channel” and another one is for muting the sound of the current channel

  • The previously empty wall now displays various types of stickers in different orders

  • Added autocomplete suggestion to the search bar. Selecting an option will autofill the search with that specific text. Typing # will show all tags, and typing / will show available commands

  • New /help command, typing it in the search bar will show show helpful info

  • New Theme Button. Cycle through themes in settings for a different GUI look

  • Fully reorganized and divided the Stickers module into smaller modules and settings

  • Added 17 new stickers: Elf Lets Groove Tonight, Adventurer Fist Bump, Adventurer Hairflip, Adventurer High Five, Groove, Cat Doomscrolling, Hamster Happy, Pepe Strong, Cupid Celebrate, Cat Wiggle, Small Scuba, Room Loop, Sniper Aim, TV Dance, Trio Heroes, Sword Boss Fight, Traumatized

LetsGrooveTonight HD
Sticker of the day: Elf Lets Groove Tonight