Overhead sticker popup and live chat reaction
☆⸻●⸻☆
Imagine a Twitch or Youtube livestream chat, full of funny memes and reactions
Place stickers on surfaces or your head with different placement modes!
Sticker popups also play music, effects & animations (emotes)

or delete the "Read_Me" script then manually set things up
New Script Capabilities might require you to set the model’s property to Sandboxed = false
Open and edit the Test Place if the model is unavailable!
Everything is located inside ReplicatedStorage, ServerScriptService,
StarterGui, StarterPlayer -> StarterPlayerScripts!
Click to see older videos:
Tons of stickers being used in a server with over 100 players
(Footage taken on PC when there were 899 stickers)
Click to watch in higher quality:
Showing tons of stickers in multiplayers, in the Test Place
(Footage taken on PC when there were 727 stickers)
Showcase in an actual game - MEGA Boss Survival
(Footage taken on MOBILE when there were 111 stickers)
Introduction 
Introduction ![]()
Hi everyone!
We all know Roblox made one of the greatest decisions of all time recently
By making chat exclusive to different age groups + The totally amazing chat filter it has become way too good for us normal players, that’s why I decided to release this system for free
I’ll continue to provide updates to add new stickers, fix bugs or improve the system (Any help would be appreciated!)
How To Use | For All Questions 
How To Use | For All Questions ![]()
How this system works:
- When used, a sticker bubble popup will appear on the user's head, swinging for a short moment before going away. A sticker frame will also show up on the screen to show who and which sticker they used, just like a livestream chat but only image icons
- Players can select a sticker from the selection GUI, which sends a signal to the server to check.
- After checking the cooldown, the server will send a signal back to all clients to play the visuals
- Players are able to disable viewing new stickers locally, set stickers as favorite in an order which is saved using datastore service, and way more features...
How to award/remove a locked sticker:
-- Only stickers with Locked = true in the settings can be given (Not this one)
-- Server script. Assuming you already have the Player variable
-- There is a better example in Bocchi The Block model in the Test Place
local Manager = require(game.ServerScriptService.StickerHandler.Manager)
-- Awarding
Manager.UnlockSticker(Player, "Amogus")
-- Removing
Manager.RemoveSticker(Player, "Amogus")
How to make an NPC or anything use a sticker:
-- Server/Local script inside a part in a model
-- There is a better example in Bocchi The Block model in the Test Place
local ClientFunctionBank = require(game:GetService("ReplicatedStorage").Modules.ClientFunctionBank)
ClientFunctionBank.VisualizeEffect(
"Sticker", -- Don't change
StickerName, -- Put the sticker name
script.Parent, -- The target part
--{Color = script.Parent.Color, PositionOffset = Vector3.new(0, 0, 0), SpeedMultiplier = 1, DelayTime = 0} -- Extra but not needed
)
Tutorial on how to set up model OR what to bring over from the Test Place to your game:
Starting from 24/05/2026 update, you don’t need to move the folders anymore if you keep the “Read_Me” script and place the system in somewhere that can run scripts, since it will set up everything automatically
-
Insert the model and move these folders into the correct locations according to their names, respectively and then ungroup them
-
Open this Stickers ModuleScript to change settings or add your own stickers
How to turn a GIF image into an animated sticker:

-
Upload the GIF file to a website like Ezgif to convert the GIF into a Png file with frames (Aka sprite sheets)
-
Pick a number of columns so that the the number of columns and number of rows are close or equal. Example: 5 columns, 4 rows / 20 columns, 20 rows / 1 column, 2 row
If the result comes out as a square then it’s perfect
Why? Roblox can distort uploaded decals if they are too thin, too wide or too long
And then convert it
Keep track of the number of frames and its length (You can go back after the final step or open a new tab)
- In my example, there were 10 frames so I decided to split into 4 columns and 3 rows
Look at the width and height. If any of them is over 1024px then you need to resize the image (Step 4)
In some cases, you need to add a tiny bit of margin space between cells so they don’t look weird with clipping errors
- (Skip this step if both dimensions of the image is under 1024px)
Adjust the percentage and scale the image down until its size is smaller than 1024x1024
- Download the result and upload it to Roblox
-
Open this module and scroll down to find the list of stickers
-
Copy any premade sticker settings and change things up
Remember the number of frames and original GIF length from step 1? Number of frames / Length and you should know how many FPS you need to play the animated sticker at the same speed
- Don’t want to type all of that? Scroll down and use the extension script mentioned below to speed up by like 10x
["Cat Dance"] = {
Type = "Animated",
Color = Color3.fromRGB(255, 0, 255),
ImageId = 78156591234395, -- Remember, ImageId, NOT Decal Id or it won't show up
SpriteSettings = {
ImageSize = Vector2.new(448, 336), -- Width, Height
CellSize = Vector2.new(448/4, 336/3), -- Width/Number of columns, Height/Number of rows
Display = 1, -- What to display if the sticker is not looped
FPS = 20, -- Frames Per Second, aka speed, more = faster
End = 10, -- How many frames the image has
Looped = true -- Animation plays forever or only once
},
},
- Voilà!
How to add a normal sticker with many sound effects:
-
Open this module and scroll down to find the list of stickers
-
Copy any existing sticker and change the settings
["GOAT"] = {
Type = "Static",
Color = Color3.fromRGB(85, 0, 255), -- Color of the sticker name
ImageId = 14396413470, -- TextureId, remember to convert if it's a decal Id by pasting it into any decal or image label, then copying the AssetId if it changes into a new number
Cooldown = 15, -- I recommend giving stickers with sounds a longer cooldown to avoid trolling
Duration = 10, -- Some stickers are up to a minute in length or even longer, literally music player, a walking boombox!
PlayRandomSound = false, -- Set to true if you want it to pick a random sound from all SoundSettings. Make sure to check the DelayTime
Description = "Art: @simla1239", -- Optional, you can delete this and the description will not show up
SoundSettings = { -- You can remove this entire block for no sounds
SoundId = 133573554622776,
Volume = 0.2, -- I suggest keeping it small to prevent trolling
DelayTime = 0, -- Time to wait before the sound plays
PlaybackSpeed = 1, -- Literally
TimePosition = 0, -- Sound starts at this second
Looped = false
},
-- Want multiple sounds?
-- Add an incremental number after the string.
-- Ex: SoundSettings -> SoundSettings2 -> SoundSettings3 -> SoundSettingsX...
-- DelayTime should be used to separate the sounds
SoundSettings2 = {
SoundId = 137612233332702,
Volume = 0.3,
DelayTime = 0,
PlaybackSpeed = 1,
TimePosition = 0,
Looped = false
},
},
How to add an explosion effect:
-
Open this module and scroll down to find the list of stickers
-
Use Ctrl + F to search for “EffectSettings”
-
Copy a premade one, paste it in your sticker info and change it to however you like
-- Example
-- It's also possible to add more effects, just add a number after the string like how you add more sounds
-- Ex: EffectSettings -> EffectSettings2 -> EffectSettings3 -> EffectSettingsX...
-- And use DelayTime for the timing
EffectSettings = {
Effect = "Explosion",
Type = "Realistic", -- Look below to see other types of effect
PositionOffset = Vector3.new(0, 0.75, 0), -- By default it will be right at the sticker position (Before the sticker moves up)
Radius = 15, -- Size of the explosion
OuterColor = Color3.fromRGB(255, 204, 117), -- Some explosions might have 2 colors
InnerColor = Color3.fromRGB(255, 170, 0),
DelayTime = 9.8, -- Time to wait before the effect appears
}
Check here to see every possible explosion types: Default, Lightning, Doom, Realistic, Ice, Inferno, Firework, etc…
Where are settings like hotkey/keybind, Gui color, tween time, animation speed, global volume control, default cooldown, amount of stickers used before closing the Gui, etc...:
-
Open this module in ReplicatedStorage → Stickers
-
Change them however you want. I have explanations next to each of them
Is this free? Yes. Can I use it for my game? Yes. Can I sell your default stickers for real money? Not really, read this and the notes below the post as some assets are from the toolbox or other places:
Lol no problem! This is in Resources > Community Resources of course you can use it in your game for free
No credits needed, it’s already great if you keep the default stickers, and perhaps lemme know about your game so I can try it out
A lot of stickers are from various amazing artists, I tried to put credits to as many as I could, so you should not sell those default ones for robux
Extension Scripts To Help With Adding New Stickers & Speed Up The Process
Use something like the Tampermonkey extension to run these scripts
Auto Create Sprite Settings So You Just Need To Copy & Paste Into Stickers Settings Module
// ==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.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);
})();
Auto Set Image/Decal Privacy Settings To Open Use
// ==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 = 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.innerText = "🤖 " + msg;
status.style.color = color;
}
// 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() {
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 = links.slice(start, end).map(l => l.href);
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 = links.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.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);
})();
Features 
Features ![]()
-
Supports
Mobile,
PC (Keybind & Scroll wheel for navigating), and
Console (Keybind), even NPCs or literal parts can use stickers (They just need to have a part in their models, check the example script in Bocchi The Block) -
Many types of stickers like
Text (Emojis like
or “strings”),
Static (Still image), &
Animated (GIF like), and their usage can be restricted to owners of a badge/gamepass only -
Auto saves your favorite stickers in a chosen order and simple settings. Datastore also includes saving unlocked stickers (You can award locked stickers from quests, missions, etc…)
-
Can be used like an Emote wheel! Add any animations to any stickers you want in order to play them on both R6 & R15
-
Supports sounds, animations, and effects like explosions. A sticker can have many of them so with some good timing you can make very cool stuff. All of them are client sided for optimizations
-
No spamming! It has server sanity check with cooldowns for the same sticker or between different ones, maximum selections before the GUI automatically closes and so on
-
Stickers can be placed as overhead bubbles or on various surfaces by changing placement modes
-
There’s also a live sticker GUI that appears on the screen like a livestream chat. The name text color matches with the player’s name color in the Roblox chat
-
Wheel selection and tween animation for the GUI, PC device can use scroll button to scroll through pages without clicking
-
A search bar to easily find matching names, descriptions, tagged stickers or navigate through pages
Limitations 
Limitations ![]()
-
Some sounds might not work because they could be from the toolbox or not shared by me since I don’t have perms
-
Please don’t add individual numbers and letters. They might be combined to form full sentences, personal info or used for a bad purpose because there is no filtering like the chat system
-
Please also don’t put the premade stickers on sales (for Robux) because they might be copyrighted. All the memes, arts and other creations belong to the original creators
Update Logs 
Update Logs ![]()
Show all:
Click on the arrow to read in details!
Credits 
Credits ![]()
Massive thanks to them for making this possible!
- @ForeverHD - TopbarPlus - Very cool topbar buttons
- @arbitiu - EasySprite - Spritesheet handler for animated GIFs
- @verret001 - DebrisGobbler - Replacement for Roblox’s outdated Debris service which stops working at 1k objects limit
- @loleris - ProfileService - Datastore for saving favorite stickers, stats and other settings
- @ThunderDaNub - Creator, made basically everything else - Please credit me if possible or let me know about your game when using this so I can try it out :D
Honorable mentions:
- Various artists, musicians, creators, memers for making this possible (Credits in each sticker’s description, I’m still adding more as I learn about their origins)
- Toolbox - Effects, sounds and images
Support Me - Check out my game!
Mega Boss Battles (Showcase) | Clothing Store |
Youtube Channel
Support Me - Check out my game!
Model and uncopylocked place link at the top so scroll up lmao
























