DEV Community

Cover image for Seamless emoji creation on Discord with bots and Vercel
Ante Barić
Ante Barić

Posted on • Originally published at Medium

1

Seamless emoji creation on Discord with bots and Vercel

Seamless emoji creation on Discord with bots and Vercel
Photo by Zen Chung from PexelsCustom emojis are a great way to add identity and a sense of fellowship to any Discord server. Users quickly get ideas for new emojis from messages shared in the server but the most common issue is that it takes some work to transfer those ideas and images to emojis. Discord has restrictions on the resolution, type, and size of an image that is required to create an emoji. But, people are lazy, and with those restrictions and additional work required to create them, many cool emojis are left as just ideas…

If you have ever been a part of Discord server you will know that many of them have different bots installed to help with various tasks. Bots can send messages to channels, perform moderation, embed remote content like tweets, and also reply and react to commands from users. The last feature, commands, is especially interesting because it allows users to perform advanced and custom actions inside the Discord server. For example, we could develop a command to create emoji from any image.

Since my (and many other) servers already have a custom bot I decided to try and add a new command that would do just that. The idea sounded great in my head but at first, I was not sure what would take to actually develop it. Manipulating images usually requires some processing power, a dedicated server, and storage. To entertain this idea let's see what would be required for this feature to be added to our server:

  • Discord bot (my server already had one but if you want to create your own take a look at https://discordjs.guide)
  • A way for users to input an image and some data like emoji name
  • Server or application capable of processing the image and adjusting it to given Discord restrictions
  • Uploading adjusted emoji image to Discord as new emoji

As mentioned above, my Discord bot is implemented in Node.js with the help of Discord.js package. Their guide has an in-depth instructions on how to set up a basic bot, register it for use on Discord, and also some ideas on where and how to deploy it. I won't be going into those details in this blog post but will provide a basic skeleton of it using the above package.

Once I had my Discord bot up and running the first thing was to solve the handling of user input. Users usually have an image they would like to convert to an emoji so we can start with that. Also, each emoji needs a unique name with which it can be used in messages and reactions, it is an alphanumeric phrase (_ is also allowed) without spaces or special characters. If you speak regex this would match:

const emojiNameMatcher = /^[a-z0-9_]+$/

Luckily Discord command can accept text and images as input so we can collect all the data needed to create an emoji from our user right from Discord interface. Discord.js exports SlashCommandBuilder class which allows us to define what inputs our command accepts.

new SlashCommandBuilder()
.setName('create-emoji')
.setDescription('create emoji')
.addStringOption(option => option.setName('name')
.setDescription('Emoji name')
.setRequired(true)
.setMinLength(2)
)
.addAttachmentOption(option => option.setName('image')
.setDescription('Emoji image')
.setRequired(true)
)

What we need now is to handle the above input. The most important thing is the image and its conversion. To convert the image we will use the cool feature of Vercel which is called Open Graph (OG) Image Generation. This feature is available as a standalone package and also inside Next.js framework. Since I used Next.js for my general purpose server and API I decided to add a new API endpoint to handle image adjustment. The above image generation package uses JSX to create images from HTML and CSS markup or even custom React components. So to adjust the image all I needed to do was to render <img /> tag inside JSX and set style attribute to correct size and fit values. This is how my request handler looks like:

import { ImageResponse } from '@vercel/og'
import { NextRequest } from 'next/server'
const handler = async (req: NextRequest) => {
const [width, height] = [128, 128]
const { searchParams } = new URL(req.url)
const image = searchParams.get('image')
const fit = searchParams.get('fit') || 'none'
const imageResponse = new ImageResponse((
<img
style={{
width: `${width}px`,
height: `${height}px`,
objectFit: fit
}}
src={image}
/>
), { width, height })
return imageResponse
}
export default handler

I also added the fit param to allow further customization of how image should be fitted to square dimension of the emoji. If the image aspect ratio is 16:9 with fit: cover we can cut it in the middle and alternatively with fit: contain we can resize it to fit 1:1 aspect. If you don't use Next.js you should still be able to use @vercel/og package with your Node.js framework of choice. It is a great way to adjust the image per Discord requirements without using any heavy image processing or requiring additional storage.

Now that we have our image ready we can connect it with the rest of the data and create a handler for our slash command.

const command = async interaction => {
// extract options from slash command
const emojiName = interaction.options.get('name', true).value
const { attachment } = interaction.options.get('image', true)
const fit = interaction.options.get('fit', false)?.value || 'cover'
// construct params for API endpoint
const emojiImageParams = new URLSearchParams()
emojiImageParams.append('image', attachment.url)
emojiImageParams.append('fit', fit)
// since fetch is async we show a loading indicator to user
await interaction.deferReply({ ephemeral: true, fetchReply: true })
// my API endpoint
const emojiImage = await fetch(`/discord/emoji?${emojiImageParams.toString()}`)
.then(res => res.arrayBuffer())
const emoji = await interaction.guild.emojis.create({
name: emojiName,
attachment: Buffer.from(emojiImage)
})
await interaction.editReply({ content: `Done! You can use new emoji with :${emoji.name}:` })
}
export default command

In the above command, we take options from Interaction object passed from our slash command. We then take the original image URL from Discord and pass it to our API endpoint together with fit option. The response of our endpoint (which is an image) is then parsed as ArrayBuffer and then passed to Discord.js function which registers new emoji in the Discord server that our bot is currently running in. ✅
Here is a sneak peek of how all of this works together inside Discord app:

GIF showing usage of created command inside Discord interface

Done and done.The above is also a good example of how an image with a wide aspect ratio fits perfectly in the square emoji after conversion. 🙌


Thats it! This was a pretty cool usage of different services and technologies to create something new and a great example of what is possible with the tools we have available today. If you want to learn more about Discord and the different integrations it offers for developers you can also check out their developer portal.

P.S. More complete code snippet with validation and additional command for removing an emoji can be found here.

If you are interested in programming, tech or want to see some of my other side projects check below:

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up