Moud

Badges#

A badge is a small award a player earns in your game: finishing the tutorial, winning a round, finding a secret room. Players see every badge of a game on its page, with how rare each one is, and the badges they earned on their own profile. When a player earns one, a card saying Badge earned slides in at the bottom right of their screen.

You make the badges on the website and hand them out from server scripts. The website holds the name, description and picture; the script only says which player gets which badge, by its key.

Making a badge#

Open your game's page on the website, follow Settings and pick the Badges tab. Each badge has:

Field
Name what players read, like "Speedrunner"
Key what scripts use, like speedrunner. Lowercase letters, digits, - and _. Made from the name when you leave it empty, and it cannot change later
Description one line on how to earn it
Icon a PNG, JPEG or WebP picture, shown in a circle, so a square picture looks best
Players can earn it turn it off to stop handing it out without deleting it

A game has at most 100 badges. A badge that is turned off disappears from the game's page, and awarding it from a script fails with an error, so you notice a script still using it.

Awarding a badge#

game.badges is on the server. award takes a player and a badge key:

luau
-- server
local finish = game.world:find("FinishLine") :: Part

finish.touched:connect(function(other)
    local player = game.players:playerOf(other)
    if not player then
        return
    end
    task.spawn(function()
        local fresh = game.badges:award(player, "first-win")
        if fresh then
            game.chat:system(player.name .. " won for the first time!")
        end
    end)
end)
  • game.players:playerOf finds the player whose body touched the finish line. Anything else touching it, a falling block or a ball, gives nil and the handler stops there.
  • award asks Moud to give first-win to that player and waits for the answer, so the line after it runs once the badge is saved. A signal handler cannot wait, which is why the award runs inside task.spawn. It returns true when the player got the badge just now and false when they already had it. Awarding the same badge twice is safe, the second call changes nothing and shows no card.
  • The chat line only goes out on the first win, because fresh is false every time after.

award throws when the key is not a badge of this game, when the badge is turned off, or when the server awards too many badges at once (see Limits). Wrap it in pcall when a failure should not stop the rest of the handler.

Checking a badge#

has answers whether a player owns a badge. A common use is giving owners of a badge something extra, here a title on their body that a nameplate script can show:

luau
-- server
game.players.spawned:connect(function(player)
    task.spawn(function()
        if game.badges:has(player, "beta-tester") then
            (player.character :: Character):setAttribute("title", "Beta tester")
        end
    end)
end)

The first has for a player asks Moud for every badge they own in this game; after that the server remembers them, and badges it awards are added to what it remembers, so later checks for the same player answer at once.

game.badges:list() gives every badge of the game as tables with key, name, description, icon and enabled. Use it to build your own badge board in the game's interface.

Testing in the editor#

When you play in the editor, the server is not part of a published game, so there is nowhere to save badges. award still works: it remembers the badge until the playtest stops and shows the card with the key as its name, so you can see where your script hands badges out. has answers from the same memory, and list is empty. Nothing reaches the website until the game runs on a fleet.

On the website#

The game's page lists its badges with three numbers, the same ones Roblox shows:

  • Rarity, the share of everyone who ever played the game that owns the badge, with a word for it from Freebie (90% or more) to Insane (under 0.1%).
  • Won yesterday, how many players earned it during the last full day, in UTC.
  • Won ever, how many players own it.

A player who is signed in sees Owned on the badges they have. Their profile shows every badge they earned in public games, newest first, each linking to the game.

Limits#

A server can award or check about 30 badges a minute, plus 10 for each player on it. That is far more than a game needs when it awards on real events; it stops a loop that awards on every frame. Going over makes award and has throw until the minute refills.