Make a bot
Examples
Ready-to-run bots. Each one is a whole program: save it as a .js file in your bot's folder and run it like in the first-bot guide. They're in the Roar.js download too, in examples/.
Ping
The smallest useful bot: it answers !ping.
// The smallest bot: answers !ping. Run it with ROAR_TOKEN=... node ping.js
import { Bot } from "roar.js";
const bot = new Bot({ token: process.env.ROAR_TOKEN });
bot.on("ready", () => console.log(`${bot.user.username} is online!`));
bot.on("message", async (msg) => {
if (msg.content === "!ping") await msg.reply("Pong! ๐");
});
bot.start();Dice and coins
Two slash commands, one with a list of choices.
// Slash commands with options: /roll and /coin.
import { Bot } from "roar.js";
const bot = new Bot({ token: process.env.ROAR_TOKEN });
bot.command({
name: "roll",
description: "Roll a die",
options: [
{ name: "sides", description: "How many sides", type: "integer", choices: [4, 6, 8, 10, 12, 20] },
],
}, async (i) => {
const sides = i.options.sides ?? 6;
const n = 1 + Math.floor(Math.random() * sides);
await i.reply(`๐ฒ ${i.user.displayName} rolled **${n}** (d${sides})`);
});
bot.command("coin", "Flip a coin", (i) => i.reply(Math.random() < 0.5 ? "๐ช Heads!" : "๐ช Tails!"));
bot.start();Welcome new members
Greets people in #welcome (or the server's system channel) and gives them the Member role. For the role, give the bot a role with Manage Roles that sits above Member in Server Settings โ Roles.
// Welcomes new members and gives them a role.
// The bot needs a role with Manage Roles placed above "Member" (Server Settings โ Roles).
import { Bot, mention } from "roar.js";
const bot = new Bot({ token: process.env.ROAR_TOKEN });
bot.on("memberJoin", async (member) => {
const channel = member.guild.channel("welcome") ?? member.guild.systemChannel;
if (channel) await channel.send(`Welcome to **${member.guild.name}**, ${mention(member)}! ๐`);
if (member.guild.role("Member")) await member.addRole("Member", "New member");
});
bot.on("memberLeave", async (member) => {
const channel = member.guild?.channel("welcome");
if (channel) await channel.send(`${member.user.displayName} left. ๐ข`);
});
bot.start();Reaction roles
Post a menu with !rolemenu; people react to get a role, and un-react to drop it. Make the roles first, and give the bot Manage Roles above them.
// Reaction roles: !rolemenu posts a message; reacting gives a role, removing the reaction takes it away.
// The bot needs Manage Roles, above the roles it hands out.
import { Bot } from "roar.js";
const bot = new Bot({ token: process.env.ROAR_TOKEN });
const ROLES = { "๐ฎ": "Gamer", "๐จ": "Artist", "๐ต": "Music" };
const menus = new Set(); // ids of the menu messages (kept in memory: post a new menu after a restart)
bot.on("message", async (msg) => {
if (msg.content !== "!rolemenu" || !msg.guild) return;
const lines = Object.entries(ROLES).map(([emoji, role]) => `${emoji} ${role}`);
const menu = await msg.channel.send(`**Pick your roles**\n${lines.join("\n")}`);
menus.add(menu.id);
for (const emoji of Object.keys(ROLES)) await menu.react(emoji);
});
bot.on("reactionAdd", async (r) => {
if (menus.has(r.messageId) && ROLES[r.emoji]) await r.guild.addRole(r.userId, ROLES[r.emoji]);
});
bot.on("reactionRemove", async (r) => {
if (menus.has(r.messageId) && ROLES[r.emoji]) await r.guild.removeRole(r.userId, ROLES[r.emoji]);
});
bot.start();Server info cards
Embeds, and a command option that picks a person.
// Embeds: /serverinfo and /whois.
import { Bot } from "roar.js";
const bot = new Bot({ token: process.env.ROAR_TOKEN });
bot.command("serverinfo", "About this server", (i) => i.reply({
embed: {
title: i.guild.name,
color: "#5fd96a",
fields: [
{ name: "Members", value: String(i.guild.memberCount), inline: true },
{ name: "Channels", value: String(i.guild.channels.size), inline: true },
{ name: "Roles", value: String(i.guild.roles.size), inline: true },
],
footer: `Server id ${i.guild.id}`,
},
}));
bot.command({
name: "whois",
description: "About someone",
options: [{ name: "person", description: "Who", type: "user", required: true }],
}, (i) => {
const member = i.guild.member(i.options.person);
if (!member) return i.reply({ content: "I can't find them here.", ephemeral: true });
return i.reply({
embed: {
title: member.displayName,
description: `@${member.user.username}`,
thumbnail: member.user.avatarUrl ?? undefined,
fields: [
{ name: "Joined", value: member.joinedAt?.toDateString() ?? "?", inline: true },
{ name: "Account made", value: member.user.createdAt.toDateString(), inline: true },
],
},
});
});
bot.start();Reminders
Answers straight away (only to you), then pings you in the channel later. Reminders live in memory, so they're forgotten if the bot restarts.
// /remind: answers straight away, then pings you later.
import { Bot, mention } from "roar.js";
const bot = new Bot({ token: process.env.ROAR_TOKEN });
bot.command({
name: "remind",
description: "Remind me later",
options: [
{ name: "minutes", description: "In how many minutes", type: "integer", required: true },
{ name: "what", description: "What to remind you about", type: "string", required: true },
],
}, async (i) => {
const minutes = Math.min(Math.max(1, i.options.minutes), 24 * 60);
await i.reply({ content: `โฐ OK, I'll remind you in ${minutes === 1 ? "1 minute" : `${minutes} minutes`}.`, ephemeral: true });
setTimeout(() => bot.send(i.channelId, `โฐ ${mention(i.user)}: ${i.options.what}`), minutes * 60000);
});
bot.start();A webhook script
Not a bot at all: a script that posts once and ends. Run it from a build, a game server or a scheduled task. See Webhooks.
// No bot needed: post to a channel from any program with a webhook URL
// (Channel Settings โ Webhooks โ New Webhook โ Copy URL).
import { Webhook } from "roar.js";
const hook = new Webhook(process.env.ROAR_WEBHOOK_URL);
await hook.send({
username: "Build Bot",
content: "The build passed โ
",
embed: { title: "main @ 63444f4", color: "#5fd96a", footer: "from webhook.js" },
});Putting them together
One bot can do all of these. Keep one new Bot(...) and one bot.start(), and paste the bot.on and bot.command parts in between. Two programs with the same token both receive every event, so they'd answer everything twice.