The EmbedBuilder provides a fluent API for creating rich embeds with automatic validation. It's based on Discord.Net's implementation and makes it easy to build complex, visually appealing messages.
using Fluxer.Net.EmbedBuilder;
using Fluxer.Net.Data.Models;
var embed = new EmbedBuilder()
.WithTitle("Hello World")
.WithDescription("This is my first embed!")
.WithColor(0x5865F2) // Blurple color
.Build();
await apiClient.SendMessage(channelId, new()
{
Embeds = new List<Embed> { embed }
});
Embeds have the following platform limits (automatically enforced by EmbedBuilder):
var embed = new EmbedBuilder()
.WithTitle("Server Statistics")
.WithDescription("Current statistics for the server")
.Build();
Set the embed color using RGB integer or individual components:
// Using RGB integer
var embed = new EmbedBuilder()
.WithColor(0x5865F2) // Blurple
.Build();
// Using RGB components
var embed = new EmbedBuilder()
.WithColor(88, 101, 242) // R, G, B
.Build();
// Common colors
0x5865F2 // Blurple
0x57F287 // Green
0xED4245 // Red
0xFEE75C // Yellow
0xEB459E // Pink
Make the title clickable:
var embed = new EmbedBuilder()
.WithTitle("Fluxer.Net Documentation")
.WithUrl("https://docs.fluxer.dev")
.Build();
// Current timestamp
var embed = new EmbedBuilder()
.WithCurrentTimestamp()
.Build();
// Specific timestamp
var embed = new EmbedBuilder()
.WithTimestamp(DateTime.UtcNow)
.Build();
var embed = new EmbedBuilder()
.WithImageUrl("https://example.com/image.png") // Large image at bottom
.WithThumbnailUrl("https://example.com/thumb.png") // Small image at top right
.Build();
Add author information to the top of the embed:
var embed = new EmbedBuilder()
.WithAuthor("Username", "https://example.com/avatar.png")
.Build();
var embed = new EmbedBuilder()
.WithAuthor(
name: "Username",
iconUrl: "https://example.com/avatar.png",
url: "https://example.com/profile"
)
.Build();
var author = new EmbedAuthorBuilder()
.WithName("Username")
.WithIconUrl("https://example.com/avatar.png")
.WithUrl("https://example.com/profile");
var embed = new EmbedBuilder()
.WithAuthor(author)
.Build();
var embed = new EmbedBuilder()
.WithAuthor(author =>
{
author.Name = "Username";
author.IconUrl = "https://example.com/avatar.png";
})
.Build();
Add footer text and icon at the bottom of the embed:
var embed = new EmbedBuilder()
.WithFooter("Fluxer.Net v1.0.0")
.Build();
var embed = new EmbedBuilder()
.WithFooter("Fluxer.Net v1.0.0", "https://example.com/icon.png")
.Build();
var footer = new EmbedFooterBuilder()
.WithText("Fluxer.Net v1.0.0")
.WithIconUrl("https://example.com/icon.png");
var embed = new EmbedBuilder()
.WithFooter(footer)
.Build();
Fields are used to organize information in a structured way. You can have up to 25 fields, and they can be inline (side by side) or full-width.
var embed = new EmbedBuilder()
.AddField("Field 1", "Value 1", inline: true)
.AddField("Field 2", "Value 2", inline: true)
.AddField("Full Width", "This field spans the full width", inline: false)
.Build();
var field = new EmbedFieldBuilder()
.WithName("Statistics")
.WithValue("100 members")
.WithIsInline(true);
var embed = new EmbedBuilder()
.AddField(field)
.Build();
var embed = new EmbedBuilder()
.AddField(field =>
{
field.Name = "Status";
field.Value = "Online";
field.IsInline = true;
})
.Build();
Inline fields are displayed in columns (typically 3 per row):
var embed = new EmbedBuilder()
.AddField("CPU", "45%", inline: true)
.AddField("Memory", "2.1 GB", inline: true)
.AddField("Uptime", "3d 12h", inline: true)
.AddField("Status", "All systems operational", inline: false)
.Build();
var embed = new EmbedBuilder()
.WithTitle("Server Information")
.WithDescription("Detailed information about this server")
.WithUrl("https://fluxer.gg/myserver")
.WithColor(0x5865F2)
.WithAuthor(
name: "Server Bot",
iconUrl: "https://cdn.fluxer.dev/icons/bot.png"
)
.WithThumbnailUrl("https://cdn.fluxer.dev/icons/server.png")
.AddField("👥 Total Members", "1,234", inline: true)
.AddField("💬 Channels", "42", inline: true)
.AddField("📅 Created", "Jan 1, 2024", inline: true)
.AddField("📊 Activity", "Very High", inline: true)
.AddField("🌍 Region", "US East", inline: true)
.AddField("⭐ Boosts", "15", inline: true)
.AddField("📜 Description", "A friendly community for gamers and developers", inline: false)
.WithImageUrl("https://cdn.fluxer.dev/banners/server-banner.png")
.WithFooter("Fluxer.Net v1.0.0", "https://cdn.fluxer.dev/icons/fluxer.png")
.WithCurrentTimestamp()
.Build();
await apiClient.SendMessage(channelId, new()
{
Content = "Here's the server information:",
Embeds = new List<Embed> { embed }
});
var user = await apiClient.GetUser(userId);
var embed = new EmbedBuilder()
.WithTitle("User Information")
.WithColor(0x5865F2)
.WithThumbnailUrl($"https://cdn.fluxer.dev/avatars/{user.Id}/{user.Avatar}.png")
.AddField("Username", user.Username, inline: true)
.AddField("ID", user.Id.ToString(), inline: true)
.AddField("Premium", user.Premium > 0 ? "✅ Yes" : "❌ No", inline: true)
.AddField("Account Created", user.CreatedAt.ToString("MMM dd, yyyy"), inline: false)
.WithFooter($"Requested by {requestingUser.Username}")
.WithCurrentTimestamp()
.Build();
await apiClient.SendMessage(channelId, new() { Embeds = new() { embed } });
var embed = new EmbedBuilder()
.WithTitle("❌ Error")
.WithDescription("Failed to execute command: Permission denied")
.WithColor(0xED4245) // Red
.AddField("Error Code", "PERMISSION_DENIED", inline: true)
.AddField("Required Permission", "Administrator", inline: true)
.WithFooter("Contact a server administrator if you believe this is a mistake")
.WithCurrentTimestamp()
.Build();
await apiClient.SendMessage(channelId, new() { Embeds = new() { embed } });
var embed = new EmbedBuilder()
.WithTitle("✅ Success")
.WithDescription($"Successfully banned user {targetUser.Username}")
.WithColor(0x57F287) // Green
.AddField("User", $"{targetUser.Username}#{targetUser.Discriminator}", inline: true)
.AddField("Reason", reason, inline: true)
.AddField("Moderator", $"<@{moderator.Id}>", inline: true)
.WithCurrentTimestamp()
.Build();
await apiClient.SendMessage(channelId, new() { Embeds = new() { embed } });
var embed = new EmbedBuilder()
.WithTitle("📊 Poll: What's your favorite programming language?")
.WithDescription("React with the corresponding emoji to vote!")
.WithColor(0xFEE75C) // Yellow
.AddField("1️⃣ C#", "Modern and powerful", inline: true)
.AddField("2️⃣ JavaScript", "Versatile and popular", inline: true)
.AddField("3️⃣ Python", "Simple and elegant", inline: true)
.AddField("4️⃣ Rust", "Fast and safe", inline: true)
.WithFooter($"Poll created by {creator.Username}")
.WithCurrentTimestamp()
.Build();
var message = await apiClient.SendMessage(channelId, new() { Embeds = new() { embed } });
// Add reaction options
await apiClient.AddReaction(channelId, message.Id, "1️⃣");
await apiClient.AddReaction(channelId, message.Id, "2️⃣");
await apiClient.AddReaction(channelId, message.Id, "3️⃣");
await apiClient.AddReaction(channelId, message.Id, "4️⃣");
var embed = new EmbedBuilder()
.WithTitle("📚 Bot Commands")
.WithDescription("Here are all available commands:")
.WithColor(0x5865F2)
.AddField("📝 General", "`/help` - Show this message\n`/info` - Bot information\n`/ping` - Check bot latency", inline: false)
.AddField("🎮 Fun", "`/roll [sides]` - Roll a dice\n`/joke` - Get a random joke", inline: false)
.AddField("🛠️ Moderation", "`/kick @user` - Kick a member\n`/ban @user` - Ban a member", inline: false)
.WithFooter("Use /help [command] for more details")
.Build();
await apiClient.SendMessage(channelId, new() { Embeds = new() { embed } });
The EmbedBuilder throws exceptions when validation fails:
try
{
var embed = new EmbedBuilder()
.WithTitle("A".PadRight(300, 'A')) // Too long!
.Build();
}
catch (ArgumentException ex)
{
Log.Error("Embed validation failed: {Message}", ex.Message);
// Title length must be less than or equal to 256
}
try
{
var embed = new EmbedBuilder()
.WithUrl("invalid-url") // Missing protocol!
.Build();
}
catch (InvalidOperationException ex)
{
Log.Error("Embed validation failed: {Message}", ex.Message);
// Embed URL must include a protocol (http:// or https://)
}
// Good: Use colors to indicate status
var successEmbed = new EmbedBuilder().WithColor(0x57F287); // Green
var errorEmbed = new EmbedBuilder().WithColor(0xED4245); // Red
var warningEmbed = new EmbedBuilder().WithColor(0xFEE75C); // Yellow
var infoEmbed = new EmbedBuilder().WithColor(0x5865F2); // Blurple
// Good: Organized information
var embed = new EmbedBuilder()
.WithDescription("Main content here")
.AddField("Key Info 1", "Value", inline: true)
.AddField("Key Info 2", "Value", inline: true)
.Build();
// Bad: Too many fields make the embed hard to read
var embed = new EmbedBuilder()
.AddField("Field 1", "Value", inline: true)
.AddField("Field 2", "Value", inline: true)
// ... 20 more fields ...
// Good: Clear and concise
var embed = new EmbedBuilder()
.WithDescription("User has been successfully banned from the server.")
.Build();
// Bad: Too much text in description
var embed = new EmbedBuilder()
.WithDescription("The user has been successfully banned from the server. " +
"They will no longer be able to join or view any content. " +
"This action was performed by a moderator and has been logged.")
.Build();
var embed = new EmbedBuilder()
// Group related stats inline
.AddField("CPU", "45%", inline: true)
.AddField("RAM", "2.1 GB", inline: true)
.AddField("Disk", "67%", inline: true)
// Full-width for separate section
.AddField("Status", "All systems operational", inline: false)
.Build();
string userInput = GetUserInput();
// Truncate if too long
if (userInput.Length > EmbedBuilder.MaxDescriptionLength)
{
userInput = userInput.Substring(0, EmbedBuilder.MaxDescriptionLength - 3) + "...";
}
var embed = new EmbedBuilder()
.WithDescription(userInput)
.Build();
EmbedBuilder works seamlessly with the CommandService:
using Fluxer.Net.Commands;
using Fluxer.Net.Commands.Attributes;
using Fluxer.Net.EmbedBuilder;
public class InfoCommands : ModuleBase
{
[Command("serverinfo")]
[Summary("Get information about the current server")]
public async Task ServerInfoCommand()
{
if (Context.GuildId == null)
{
await ReplyAsync("This command can only be used in a server!");
return;
}
var guild = await Context.Client.GetGuild(Context.GuildId.Value);
var embed = new EmbedBuilder()
.WithTitle($"📊 {guild.Name}")
.WithDescription(guild.Description ?? "No description set")
.WithColor(0x5865F2)
.WithThumbnailUrl(guild.Icon != null
? $"https://cdn.fluxer.dev/icons/{guild.Id}/{guild.Icon}.png"
: null)
.AddField("Owner", $"<@{guild.OwnerId}>", inline: true)
.AddField("Created", guild.CreatedAt.ToString("MMM dd, yyyy"), inline: true)
.AddField("Members", guild.MemberCount?.ToString() ?? "Unknown", inline: true)
.WithFooter($"Server ID: {guild.Id}")
.WithCurrentTimestamp()
.Build();
await Context.Client.SendMessage(Context.ChannelId, new()
{
Embeds = new List