# null Source: https://canvacord.neplex.dev/builders/builtin-builders # null Source: https://canvacord.neplex.dev/builders/introduction-to-builders Builders provide a way to create complex images using React-like components API. Canvacord under the hood abstracts over [satori](https://github.com/vercel/satori), an enlightened library to convert HTML and CSS to SVG by providing JSX interface as well as rendering the SVG to other numerous formats like PNG, JPEG, WEBP, etc. This makes it possible to create complex images with little to no configuration. ## Anatomy of a Builder A builder is a class that extends the `Builder` class exported by Canvacord. This class contains all the complex logic behind rendering the jsx. ```tsx TypeScript import { JSX, Builder } from "canvacord"; // Options for the builder interface Props { message: string; } class MyBuilder extends Builder { public constructor() { // The super constructor takes the width and height of the output image super(500, 500); } public setMessage(value: string) { // The set method is used to set the value of a property this.options.set("message", value); return this; } // The render method is where the JSX is rendered public async render() { const message = this.options.get("message"); // You can render any component you want // this markup describes the shape/content of output image return

{message}

; } } ``` ```jsx ES Modules import { JSX, Builder } from "canvacord"; class MyBuilder extends Builder { constructor() { // The super constructor takes the width and height of the output image super(500, 500); } setMessage(value) { // The set method is used to set the value of a property this.options.set("message", value); return this; } // The render method is where the JSX is rendered async render() { const message = this.options.get("message"); // You can render any component you want // this markup describes the shape/content of output image return

{message}

; } } ``` ```jsx CommonJS const { JSX, Builder } = require("canvacord"); class MyBuilder extends Builder { constructor() { // The super constructor takes the width and height of the output image super(500, 500); } setMessage(value) { // The set method is used to set the value of a property this.options.set("message", value); return this; } // The render method is where the JSX is rendered async render() { const message = this.options.get("message"); // You can render any component you want // this markup describes the shape/content of output image return

{message}

; } } ```
**Good to know:** Rendering a text requires you to register at least one font. ## Usage ```tsx // Create an instance of the builder const builder = new MyBuilder() // Set the message property .setMessage("Hello, World!"); // Render the builder into image const result = await builder.build(); // ^ result is by default a png buffer ``` # JSX Syntax Source: https://canvacord.neplex.dev/builders/jsx-syntax Learn how to use JSX syntax with Canvacord. JSX is a syntax extension for JavaScript that looks similar to HTML. It allows you to write HTML-like code in your JavaScript files. If you're familiar with React, you'll feel right at home with JSX. A basic example of JSX syntax is shown below: ```jsx const message =

Hello, world!

; // ^^^^^^^^^^^^^^^^^^^^^^ JSX syntax ``` Notice how we are not using strings to define the HTML elements. Instead, we are using a syntax that looks like HTML. ## But this is not a valid JavaScript syntax! You are right! JSX is not a valid JavaScript syntax. It needs to be transformed into a valid JavaScript syntax before it can be executed by the JavaScript engine. This is where the transpiler comes into play. The transpiler is a tool that converts magical stuff, including the JSX syntax into the equivalent JavaScript code. Some of the most popular transpilers for JSX are [Babel](https://babeljs.io/), [TypeScript](https://www.typescriptlang.org/), [SWC](https://swc.rs/), [esbuild](https://esbuild.github.io/), etc. If you are TypeScript user, you dont even need to add anything else to your project, just use the `@jsx` pragma and you are good to go. ## The JSX pragma The JSX pragma is a comment that tells the transpiler how to transform JSX into the equivalent JavaScript code. The pragma is used to define the function that will be called when the JSX syntax is encountered. The pragma is defined at the top of the file and is usually in the form of a comment. ```js /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ ``` The above pragma comment tells the transpiler to use the `JSX.createElement` function to transform the JSX syntax into the equivalent JavaScript code. The `JSX.Fragment` is used to wrap multiple elements in a single parent element. These functions are exported by `canvacord` as `JSX` namespace. ## TypeScript global JSX pragma You can also set the pragma globally in your project by adding the following to your `tsconfig.json` file: ```json tsconfig.json { "compilerOptions": { "jsx": "react", // Canvacord uses React-like JSX "jsxFactory": "JSX.createElement", // works as @jsx "jsxFragmentFactory": "JSX.Fragment" // works as @jsxFrag } } ``` ## Don't want to/Can't use JSX? If you don't want to use JSX or can't use JSX in your project, you can still use Canvacord. Canvacord provides a way to create images without using JSX. You can use the `Builder` class to create images without using JSX. The `Builder` class provides a way to create images using a more traditional approach. ### Element object You can return element object from the render method as an alternative approach to JSX. ```js async render() { return { type: 'h1', props: { children: 'hello, world', }, }; } ``` ### Calling JSX function You can also call the JSX function directly to create elements. ```js async render() { return JSX.createElement('h1', {}, 'hello, world'); } ``` ## Using JSX with Canvacord ```tsx TypeScript /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ import { JSX } from "canvacord"; const message =

Hello, world!

; ``` ```jsx ES Modules /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ import { JSX } from "canvacord"; const message =

Hello, world!

; ``` ```jsx CommonJS /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ const { JSX } = require("canvacord"); const message =

Hello, world!

; ```
```tsx TypeScript /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ import { JSX } from "canvacord"; const message =

Hello, world!

; ``` ```jsx ES Modules /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ import { JSX } from "canvacord"; const message =

Hello, world!

; ``` ```jsx CommonJS /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ const { JSX } = require("canvacord"); const message =

Hello, world!

; ```
# Leaderboard Builder Source: https://canvacord.neplex.dev/builders/leaderboardbuilder A builtin builder to create leaderboard images. This page is a work in progress. Leaderboard builder is another builtin builder provided by Canvacord to create leaderboard images. It is useful for creating leaderboards for games, servers, or any other application where you need to display a list of players with their ranks, levels, and experience points. ## API Documentation Refer to [https://canvacord.js.org](https://canvacord.js.org/docs/canvacord/class/LeaderboardBuilder) for the complete API documentation. In the following sections, we will only cover the most common use cases. ## Let's get started ### Leaderboard image generation ```js ES Modules import { Font, LeaderboardBuilder } from "canvacord"; // load font Font.loadDefault(); // generate image const lb = new LeaderboardBuilder() // set title, image and subtitle .setHeader({ title: "NeplexLabs", image: "https://github.com/neplextech.png", subtitle: "3258 members", }) // set players, usually you would get this from a database but for this example we will hardcode it .setPlayers([ { avatar: "https://github.com/twlite.png", username: "twlite", displayName: "Archaeopteryx", level: 32, xp: 2420, rank: 1, }, { avatar: "https://github.com/notunderctrl.png", username: "avrajs", displayName: "Avraj", level: 30, xp: 2390, rank: 2, }, { avatar: "https://github.com/insypher.png", username: "insypher01", displayName: "insypher", level: 29, xp: 2280, rank: 3, }, { avatar: "https://github.com/insypher.png", username: "com6235", displayName: "CatGPT", level: 24, xp: 2280, rank: 5, }, // ... ]) .setBackground("./my-background-image.jpg"); // changing variant lb.setVariant("horizontal"); // or lb.setVariant("default"); const image = await lb.build({ format: "png" }); ``` ```js CommonJS const { Font, LeaderboardBuilder } = require("canvacord"); // load font Font.loadDefault(); // generate image const lb = new LeaderboardBuilder() // set title, image and subtitle .setHeader({ title: "NeplexLabs", image: "https://github.com/neplextech.png", subtitle: "3258 members", }) // set players, usually you would get this from a database but for this example we will hardcode it .setPlayers([ { avatar: "https://github.com/twlite.png", username: "twlite", displayName: "Archaeopteryx", level: 32, xp: 2420, rank: 1, }, { avatar: "https://github.com/notunderctrl.png", username: "avrajs", displayName: "Avraj", level: 30, xp: 2390, rank: 2, }, { avatar: "https://github.com/insypher.png", username: "insypher01", displayName: "insypher", level: 29, xp: 2280, rank: 3, }, { avatar: "https://github.com/insypher.png", username: "com6235", displayName: "CatGPT", level: 24, xp: 2280, rank: 5, }, // ... ]) .setBackground("./my-background-image.jpg"); // changing variant lb.setVariant("horizontal"); // or lb.setVariant("default"); const image = await lb.build({ format: "png" }); ``` Canvacord automatically adjusts the size of the output image based on the number of players. Maximum number of players is 10, but recommended size is 8 players or less. # Output ### Default variant ![Leaderboard](https://raw.githubusercontent.com/neplextech/canvacord/main/packages/canvacord/test/leaderboard.svg) ### Horizontal variant ![Leaderboard](https://raw.githubusercontent.com/neplextech/canvacord/main/packages/canvacord/test/leaderboard2.svg) # Rank Card Builder Source: https://canvacord.neplex.dev/builders/rankcardbuilder A builtin builder to create rank cards. This page is a work in progress. Rank card creation has been the most common use case for Canvacord to this date. Canvacord provides a `RankCardBuilder` class to create rank cards with ease. The `RankCardBuilder` class offers a lot of helper methods to customize the rank card to your liking. ## API Documentation Refer to [https://canvacord.js.org](https://canvacord.js.org/docs/canvacord/class/RankCardBuilder) for the complete API documentation. In the following sections, we will only cover the most common use cases. ## Let's get started ### Importing the Required Classes First, we need to import the `Font` and `RankCardBuilder` classes from the canvacord module. ```js ES Modules import { Font, RankCardBuilder } from "canvacord"; ``` ```js CommonJS const { Font, RankCardBuilder } = require("canvacord"); ``` ### Loading fonts Canvacord does not load fonts by default. If your use case does not involve writing texts, this step can be omitted. However, rank cards require texts to be written on them, so we need to load the font into canvacord's font registry. Canvacord by default ships with a font called [`Geist`](https://vercel.com/font?utm_source=canvacord\&utm_campaign=rank-card) (by [Vercel](https://vercel.com/?utm_source=canvacord\&utm_campaign=rank-card)). This font can be loaded with the `Font.loadDefault()` method: ```js Font.loadDefault(); ``` If you want to use a custom font instead, you can skip `Font.loadDefault()` method and utilize `Font.fromFile` or `Font.fromBuffer` method to load the font from a file or buffer respectively. ```js Load font from file // synchronous method Font.fromFileSync("./my-font.ttf"); // asynchronous method await Font.fromFile("./my-font.ttf"); ``` ```js Load font from buffer Font.fromBuffer(buffer); ``` **Good to know:** Currently only `TTF`, `OTF` and `WOFF` font formats are supported. ### Creating a rank card builder Now that we have loaded the font, we can create a new `RankCardBuilder` instance. This is a builder class exported by canvacord to specifically create rank cards. It offers a lot of helper methods to customize the rank card to your liking. The following is an example of a rank card builder with common properties set: ```js const card = new RankCardBuilder() .setDisplayName("Wumpus") // Big name .setUsername("@wumpus") // small name, do not include it if you want to hide it .setAvatar("https://cdn.discordapp.com/embed/avatars/0.png?size=256") // user avatar .setCurrentXP(300) // current xp .setRequiredXP(600) // required xp .setLevel(2) // user level .setRank(5) // user rank .setOverlay(90) // overlay percentage. Overlay is a semi-transparent layer on top of the background .setBackground("#23272a") // set background color or, .setBackground("./path/to/image.png") // set background image .setStatus("online"); // user status. Omit this if you want to hide it ``` ### Generating the image ```ts const image = await card.build({ format: "png", }); // image is a buffer. It can be written to a file or sent as an attachment over internet ``` ### Result ![xp-card](https://raw.githubusercontent.com/neplextech/canvacord/main/packages/canvacord/test/normal/rankCard.svg) ## Advanced Usage ### Overriding default texts The `setTextStyles` method is used to customize the text styles for different elements in a rank card or leaderboard. This method allows for the modification of default labels for level, experience points (XP), and rank display. ```js card.setTextStyles({ level: "NIVEAU :", // Custom text for the level xp: "EXP :", // Custom text for the experience points rank: "CLASSEMENT :", // Custom text for the rank }); ``` ### Result ![xp-card](https://raw.githubusercontent.com/neplextech/canvacord/main/packages/canvacord/test/normal/cardTranslated.svg) ### Customizing the colors The `setStyles` method can be used to customize the colors of different elements in a rank card or leaderboard. This method allows for the modification of the background, progress bar, and text colors, etc. The style object is a key-value pair of the style name and the value to be set. The style behaves similar to css properties. #### Syntax 1 (Style object) ```scss // Group of elements ElementGroup { // Element name ElementName { // Style object style { attribute-name: value; } } } ``` #### Syntax 2 (Tailwind classes) ```scss // Group of elements ElementGroup { // Element name ElementName { // Style object tw = "tailwind-classes" } } ``` #### Examples ```js // changing progress bar thumb color card.setStyles({ progressbar: { thumb: { style: { backgroundColor: "red", }, }, }, }); // alternative syntax card.setStyles({ progressbar: { thumb: { tw: "bg-red-500", }, }, }); ``` ### Modifying progress bar width The internal progress calculator may not be suitable for all use cases. You can set a custom progress calculator using the `setProgressCalculator` method. The progress calculator is a function that returns a number between 0 and 100, representing the progress percentage. ```js card.setProgressCalculator((currentXP, requiredXP) => { // do some crazy math here // The value returned must be in the range of 0 to 100. It represents the width of the progress bar return Math.floor((currentXP / requiredXP) * 100); }); ``` ### Overriding emoji providers Canvacord uses the `twemoji` provider by default. You can override this by using the `setGraphemeProvider` method. The `setGraphemeProvider` method accepts a `GraphemeProvider` enum value. ```js // Twemoji card.setGraphemeProvider(BuiltInGraphemeProvider.Twemoji); // FluentEmojiHighContrast card.setGraphemeProvider(BuiltInGraphemeProvider.FluentEmojiHighContrast); // FluentEmoji card.setGraphemeProvider(BuiltInGraphemeProvider.FluentEmoji); // FluentEmojiColor card.setGraphemeProvider(BuiltInGraphemeProvider.FluentEmojiColor); // FluentEmojiFlat card.setGraphemeProvider(BuiltInGraphemeProvider.FluentEmojiFlat); // Openmoji card.setGraphemeProvider(BuiltInGraphemeProvider.Openmoji); // Noto card.setGraphemeProvider(BuiltInGraphemeProvider.Noto); // Blobmoji card.setGraphemeProvider(BuiltInGraphemeProvider.Blobmoji); // None card.setGraphemeProvider(BuiltInGraphemeProvider.None); ``` # Analog Clock Source: https://canvacord.neplex.dev/examples/builders/analog-clock Create an analog clock with Canvacord. This page is still a work in progress. ## Code ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Usage ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Result analog-clock # Discord Embed Source: https://canvacord.neplex.dev/examples/builders/discord-embed Dynamic Discord embed builder. This page is still a work in progress. ## Code ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Usage ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Result discord-embed # Discord Profile (Large) Source: https://canvacord.neplex.dev/examples/builders/discord-profile-large Large version of the Discord Profile card. This page is still a work in progress. ## Code ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Usage ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Result discord-profile-large # Discord Profile (Small) Source: https://canvacord.neplex.dev/examples/builders/discord-profile-small Small version of the Discord Profile card. This page is still a work in progress. ## Code ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Usage ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Result discord-profile-small # Greetings Card Source: https://canvacord.neplex.dev/examples/builders/greetings-card Welcomer/Leaver cards with a custom background and text. ## Code ```tsx TypeScript /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ import { JSX, Builder, loadImage } from "canvacord"; interface Props { displayName: string; type: "welcome" | "goodbye"; avatar: string; message: string; } export class GreetingsCard extends Builder { constructor() { super(930, 280); this.bootstrap({ displayName: "", type: "welcome", avatar: "", message: "", }); } setDisplayName(value: string) { this.options.set("displayName", value); return this; } setType(value: Props["type"]) { this.options.set("type", value); return this; } setAvatar(value: string) { this.options.set("avatar", value); return this; } setMessage(value: string) { this.options.set("message", value); return this; } async render() { const { type, displayName, avatar, message } = this.options.getOptions(); const image = await loadImage(avatar); return (

{type === "welcome" ? "Welcome" : "Goodbye"},{" "} {displayName}!

{message}

); } } ``` ```js ES Modules import { JSX, Builder, loadImage } from "canvacord"; export class GreetingsCard extends Builder { constructor() { super(930, 280); this.bootstrap({ displayName: "", type: "welcome", avatar: "", message: "", }); } setDisplayName(value) { this.options.set("displayName", value); return this; } setType(value) { this.options.set("type", value); return this; } setAvatar(value) { this.options.set("avatar", value); return this; } setMessage(value) { this.options.set("message", value); return this; } async render() { const { type, displayName, avatar, message } = this.options.getOptions(); const image = await loadImage(avatar); return JSX.createElement( "div", { className: "h-full w-full flex flex-col items-center justify-center bg-[#23272A] rounded-xl", }, JSX.createElement( "div", { className: "px-6 bg-[#2B2F35AA] w-[96%] h-[84%] rounded-lg flex items-center", }, JSX.createElement("img", { src: image.toDataURL(), className: "flex h-[40] w-[40] rounded-full", }), JSX.createElement( "div", { className: "flex flex-col ml-6" }, JSX.createElement( "h1", { className: "text-5xl text-white font-bold m-0" }, type === "welcome" ? "Welcome" : "Goodbye", ",", " ", JSX.createElement( "span", { className: "text-blue-500" }, displayName, "!" ) ), JSX.createElement( "p", { className: "text-gray-300 text-3xl m-0" }, message ) ) ) ); } } ``` ```js CommonJS const { JSX, Builder, loadImage } = require("canvacord"); class GreetingsCard extends Builder { constructor() { super(930, 280); this.bootstrap({ displayName: "", type: "welcome", avatar: "", message: "", }); } setDisplayName(value) { this.options.set("displayName", value); return this; } setType(value) { this.options.set("type", value); return this; } setAvatar(value) { this.options.set("avatar", value); return this; } setMessage(value) { this.options.set("message", value); return this; } async render() { const { type, displayName, avatar, message } = this.options.getOptions(); const image = await loadImage(avatar); return JSX.createElement( "div", { className: "h-full w-full flex flex-col items-center justify-center bg-[#23272A] rounded-xl", }, JSX.createElement( "div", { className: "px-6 bg-[#2B2F35AA] w-[96%] h-[84%] rounded-lg flex items-center", }, JSX.createElement("img", { src: image.toDataURL(), className: "flex h-[40] w-[40] rounded-full", }), JSX.createElement( "div", { className: "flex flex-col ml-6" }, JSX.createElement( "h1", { className: "text-5xl text-white font-bold m-0" }, type === "welcome" ? "Welcome" : "Goodbye", ",", " ", JSX.createElement( "span", { className: "text-blue-500" }, displayName, "!" ) ), JSX.createElement( "p", { className: "text-gray-300 text-3xl m-0" }, message ) ) ) ); } } module.exports = { GreetingsCard }; ```
## Usage ```ts TypeScript import { Font } from "canvacord"; import { GreetingsCard } from "./GreetingsCard"; // load font, in this case we are loading the bundled font from canvacord Font.loadDefault(); // create card const card = new GreetingsCard() .setAvatar("https://cdn.discordapp.com/embed/avatars/0.png") .setDisplayName("Wumpus") .setType("welcome") .setMessage("Welcome to the server!"); const image = await card.build({ format: "png" }); // now do something with the image buffer ``` ```js ES Modules import { Font } from "canvacord"; import { GreetingsCard } from "./GreetingsCard.js"; // load font, in this case we are loading the bundled font from canvacord Font.loadDefault(); // create card const card = new GreetingsCard() .setAvatar("https://cdn.discordapp.com/embed/avatars/0.png") .setDisplayName("Wumpus") .setType("welcome") .setMessage("Welcome to the server!"); const image = await card.build({ format: "png" }); // now do something with the image buffer ``` ```js CommonJS const { Font } = require("canvacord"); const { GreetingsCard } = require("./GreetingsCard.js"); // load font, in this case we are loading the bundled font from canvacord Font.loadDefault(); // create card const card = new GreetingsCard() .setAvatar("https://cdn.discordapp.com/embed/avatars/0.png") .setDisplayName("Wumpus") .setType("welcome") .setMessage("Welcome to the server!"); async function main() { const image = await card.build({ format: "png" }); // now do something with the image buffer } main(); ``` ## Result greetings-card # Instagram Post Source: https://canvacord.neplex.dev/examples/builders/instagram-post Create an Instagram post with Canvacord. This page is still a work in progress. ## Code ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Usage ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Result instagram-post # Music Card Source: https://canvacord.neplex.dev/examples/builders/music-card Music player card with custom text and image. ## Code ```tsx TypeScript /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ import { JSX, Builder, loadImage } from "canvacord"; interface Props { image: string; title: string; author: string; currentTime: string; totalTime: string; progress: number; } export class MusicCard extends Builder { constructor() { super(377, 523); this.bootstrap({ author: "", currentTime: "00:00", totalTime: "00:00", progress: 0, image: "", title: "", }); } setImage(image: string) { this.options.set("image", image); return this; } setTitle(title: string) { this.options.set("title", title); return this; } setAuthor(author: string) { this.options.set("author", author); return this; } setCurrentTime(time: string) { this.options.set("currentTime", time); return this; } setTotalTime(time: string) { this.options.set("totalTime", time); return this; } setProgress(progress: number) { this.options.set("progress", progress); return this; } async render() { const { author, currentTime, image, progress, title, totalTime } = this.options.getOptions(); const art = await loadImage(image); return (
img

{title}

{author}

{currentTime} {totalTime}
); } } ``` ```js ES Modules import { JSX, Builder, loadImage } from "canvacord"; export class MusicCard extends Builder { constructor() { super(930, 280); this.bootstrap({ author: "", currentTime: "00:00", totalTime: "00:00", progress: 0, image: "", title: "", }); } setImage(image) { this.options.set("image", image); return this; } setTitle(title) { this.options.set("title", title); return this; } setAuthor(author) { this.options.set("author", author); return this; } setCurrentTime(time) { this.options.set("currentTime", time); return this; } setTotalTime(time) { this.options.set("totalTime", time); return this; } setProgress(progress) { this.options.set("progress", progress); return this; } async render() { const { author, currentTime, image, progress, title, totalTime } = this.options.getOptions(); const art = await loadImage(image); return JSX.createElement( "div", { style: { background: "linear-gradient(to top, #120C17, #010424, #201C5B)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 8, borderRadius: "0.5rem", height: "100%", width: "100%", }, }, JSX.createElement("img", { src: art.toDataURL(), alt: "img", style: { borderRadius: "50%", height: "12rem", width: "12rem", }, }), JSX.createElement( "div", { style: { color: "white", display: "flex", flexDirection: "column", alignItems: "center", }, }, JSX.createElement( "h1", { style: { fontSize: "1.5rem", lineHeight: 2, marginBottom: 0, marginTop: "0.75rem", }, }, title ), JSX.createElement( "h4", { style: { fontSize: "1.125rem", lineHeight: 1, marginTop: 0, color: "#FFFFFFAA", fontWeight: 500, }, }, author ) ), JSX.createElement( "div", { style: { display: "flex", flexDirection: "column", }, }, JSX.createElement( "div", { style: { position: "relative", height: "0.5rem", width: "20rem", backgroundColor: "white", display: "flex", flexDirection: "column", }, }, JSX.createElement("div", { style: { position: "absolute", height: "0.5rem", width: `${progress}%`, maxWidth: "20rem", backgroundColor: "#9333EA", }, }) ), JSX.createElement( "div", { style: { marginTop: "3px", display: "flex", alignItems: "center", justifyContent: "space-between", fontSize: "14", fontWeight: "500", color: "#FFFFFFAA", }, }, JSX.createElement("span", null, currentTime), JSX.createElement("span", null, totalTime) ) ) ); } } ``` ```js CommonJS const { JSX, Builder, loadImage } = require("canvacord"); class MusicCard extends Builder { constructor() { super(930, 280); this.bootstrap({ author: "", currentTime: "00:00", totalTime: "00:00", progress: 0, image: "", title: "", }); } setImage(image) { this.options.set("image", image); return this; } setTitle(title) { this.options.set("title", title); return this; } setAuthor(author) { this.options.set("author", author); return this; } setCurrentTime(time) { this.options.set("currentTime", time); return this; } setTotalTime(time) { this.options.set("totalTime", time); return this; } setProgress(progress) { this.options.set("progress", progress); return this; } async render() { const { author, currentTime, image, progress, title, totalTime } = this.options.getOptions(); const art = await loadImage(image); return JSX.createElement( "div", { style: { background: "linear-gradient(to top, #120C17, #010424, #201C5B)", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 8, borderRadius: "0.5rem", height: "100%", width: "100%", }, }, JSX.createElement("img", { src: art.toDataURL(), alt: "img", style: { borderRadius: "50%", height: "12rem", width: "12rem", }, }), JSX.createElement( "div", { style: { color: "white", display: "flex", flexDirection: "column", alignItems: "center", }, }, JSX.createElement( "h1", { style: { fontSize: "1.5rem", lineHeight: 2, marginBottom: 0, marginTop: "0.75rem", }, }, title ), JSX.createElement( "h4", { style: { fontSize: "1.125rem", lineHeight: 1, marginTop: 0, color: "#FFFFFFAA", fontWeight: 500, }, }, author ) ), JSX.createElement( "div", { style: { display: "flex", flexDirection: "column", }, }, JSX.createElement( "div", { style: { position: "relative", height: "0.5rem", width: "20rem", backgroundColor: "white", display: "flex", flexDirection: "column", }, }, JSX.createElement("div", { style: { position: "absolute", height: "0.5rem", width: `${progress}%`, maxWidth: "20rem", backgroundColor: "#9333EA", }, }) ), JSX.createElement( "div", { style: { marginTop: "3px", display: "flex", alignItems: "center", justifyContent: "space-between", fontSize: "14", fontWeight: "500", color: "#FFFFFFAA", }, }, JSX.createElement("span", null, currentTime), JSX.createElement("span", null, totalTime) ) ) ); } } module.exports = { MusicCard }; ``` ## Usage ```ts TypeScript import { MusicCard } from "./MusicCard"; const card = new MusicCard() .setAuthor("JVKE") .setTitle("Golden Hour") .setImage( "https://lh3.googleusercontent.com/i1qCCS4BbP6z11E08FkQg6fN-83Uj4fQg4bmBsD2E6SvGQ3RW7nXxpQ3hmcSlI5Ipek10H7R4BjV5mAY=w544-h544-l90-rj" ) .setProgress(39) .setCurrentTime("01:58") .setTotalTime("02:59"); const image = await card.build(); // now do something with the image buffer ``` ```js ES Modules import { MusicCard } from "./MusicCard.js"; const card = new MusicCard() .setAuthor("JVKE") .setTitle("Golden Hour") .setImage( "https://lh3.googleusercontent.com/i1qCCS4BbP6z11E08FkQg6fN-83Uj4fQg4bmBsD2E6SvGQ3RW7nXxpQ3hmcSlI5Ipek10H7R4BjV5mAY=w544-h544-l90-rj" ) .setProgress(39) .setCurrentTime("01:58") .setTotalTime("02:59"); const image = await card.build(); // now do something with the image buffer ``` ```js CommonJS const { MusicCard } = require("./MusicCard.js"); const card = new MusicCard() .setAuthor("JVKE") .setTitle("Golden Hour") .setImage( "https://lh3.googleusercontent.com/i1qCCS4BbP6z11E08FkQg6fN-83Uj4fQg4bmBsD2E6SvGQ3RW7nXxpQ3hmcSlI5Ipek10H7R4BjV5mAY=w544-h544-l90-rj" ) .setProgress(39) .setCurrentTime("01:58") .setTotalTime("02:59"); async function main() { const image = await card.build(); // now do something with the image buffer } ``` ## Result # Quote card Source: https://canvacord.neplex.dev/examples/builders/quote Create an quote card with Canvacord. ## Code ```js CommonJS const { JSX, Builder, loadImage, Font, FontFactory } = require("canvacord"); class QuoteCard extends Builder { constructor() { super(1200, 630); this.bootstrap({ text: "", author: "", tag: "", bgcolor: true, watermark: "", backgroundImage: "", }); if (!FontFactory.size) Font.loadDefault(); } setText(value) { this.options.set("text", value); return this; } setAuthor(value) { this.options.set("author", value); return this; } setTag(value) { this.options.set("tag", value); return this; } setColor(value) { this.options.set("bgcolor", value); return this; } setWatermark(value) { this.options.set("watermark", value); return this; } setBackgroundImage(value) { this.options.set("backgroundImage", value); return this; } async render() { const { text, author, tag, watermark, bgcolor, backgroundImage } = this.options.getOptions(); const img = await loadImage(backgroundImage); return JSX.createElement( "div", { className: "w-full h-full flex relative", style: { backgroundColor: "#000000", borderRadius: "0.5rem", overflow: "hidden", }, }, JSX.createElement( "div", { className: "w-1/2 flex relative", style: { width: "50%", height: "100%", }, }, JSX.createElement("img", { src: img.toDataURL(), className: "h-full w-full", style: { objectFit: "cover", objectPosition: "center", width: "100%", height: "100%", filter: bgcolor ? "none" : "grayscale(100%) brightness(0.9) contrast(1.2)", }, }), JSX.createElement("div", { className: "absolute inset-0 flex", style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, background: "linear-gradient(60deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 25%, rgba(0,0,0,0.4) 45%, rgba(0,0,0,0.8) 65%, rgba(0,0,0,0.95) 85%, #000000 100%)", }, }), JSX.createElement("div", { className: "absolute inset-0 flex", style: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, background: "linear-gradient(to right, rgba(0,0,0,0) 0%, rgba(0,0,0,0.2) 70%, rgba(0,0,0,0.9) 100%)", }, }) ), JSX.createElement( "div", { className: "w-1/2 relative flex flex-col justify-center items-center text-center", style: { display: "flex", position: "relative", width: "50%", height: "100%", flexDirection: "column", justifyContent: "center", alignItems: "center", textAlign: "center", padding: "2rem", }, }, JSX.createElement( "div", { style: { display: "flex", position: "relative", width: "100%", height: "100%", flexDirection: "column", justifyContent: "center", alignItems: "center", }, }, JSX.createElement( "h2", { className: "text-white flex font-bold", style: { fontSize: "3rem", fontWeight: "bold", color: "#ffffff", marginBottom: "1rem", lineHeight: "1.2", }, }, text ), author && JSX.createElement( "p", { className: "text-white flex", style: { fontSize: "1.5rem", color: "#ffffff", marginBottom: "0.5rem", }, }, `- ${author}` ), tag && JSX.createElement( "p", { className: "text-gray-400 flex", style: { fontSize: "1rem", color: "#9ca3af", marginBottom: "2rem", }, }, tag ), watermark && JSX.createElement( "div", { style: { position: "absolute", display: "flex", bottom: "1rem", right: "1rem", }, }, JSX.createElement( "p", { className: "text-gray-500 flex", style: { fontSize: "0.875rem", color: "#6b7280", }, }, watermark ) ) ) ) ); } } module.exports = { QuoteCard }; ``` ## Usage ```js CommonJS const { QuoteCard } = require("./QuoteCard"); const card = new QuoteCard() .setText("hello") .setAuthor("Ziji") .setTag("__ziji") .setWatermark("Ziji#7063") .setBackgroundImage( "https://lh3.googleusercontent.com/pw/AP1GczN0ncQYhFuV0qUcW68KX4a5DCwXw7MlobnY0aGOLnpUeareeV1pNxZoF4PayOrcqgBapur4iM0MlxdiW6T9uhwMqmlLP1A1TBKUIPOt7E0-eH0EV2FddVDvyyXHnx7tyGCLwheiZjiaVA9xSQ4a8xTnDw=w780-h712-s-no-gm" ) .setColor(true); const result = await card.build({ format: "png" }); // now do something with the image buffer ``` ## Result image # Tweet Card Source: https://canvacord.neplex.dev/examples/builders/tweet-card Tweet card built with Canvacord. This page is still a work in progress. ## Code ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Usage ```ts TypeScript import {} from "canvacord"; ``` ```js ES Modules import {} from "canvacord"; ``` ```js CommonJS const {} = require("canvacord"); ``` ## Result tweet-card # Stewie Griffin Source: https://canvacord.neplex.dev/examples/image-manipulation/stewie-griffin Become Stewie Griffin from Family Guy using Canvacord. ## Code ```ts TypeScript import { join } from "path"; import { createTemplate, createImageGenerator, TemplateImage, type ImageSource, } from "canvacord"; const StewieGriffin = createTemplate((image: ImageSource) => { return { width: 1024, height: 1024, steps: [ { image: [ { source: new TemplateImage(image), x: 180, y: 0, width: 680, height: 680, }, ], }, { image: [ { source: new TemplateImage( join(import.meta.dirname, "stewie-griffin-source.png") ), x: 0, y: 0, }, ], }, ], }; }); export async function stewieGriffin(image: ImageSource) { const output = await createImageGenerator(StewieGriffin(image)).render(); const result = await output.encode("png"); return result; } ``` ```js ES Modules import { join } from "path"; import { createTemplate, createImageGenerator, TemplateImage } from "canvacord"; const StewieGriffin = createTemplate((image) => { return { width: 1024, height: 1024, steps: [ { image: [ { source: new TemplateImage(image), x: 180, y: 0, width: 680, height: 680, }, ], }, { image: [ { source: new TemplateImage( join(import.meta.dirname, "stewie-griffin-source.png") ), x: 0, y: 0, }, ], }, ], }; }); export async function stewieGriffin(image) { const output = await createImageGenerator(StewieGriffin(image)).render(); const result = await output.encode("png"); return result; } ``` ```js CommonJS const { join } = require("path"); const { createTemplate, createImageGenerator, TemplateImage, } = require("canvacord"); const StewieGriffin = createTemplate((image) => { return { width: 1024, height: 1024, steps: [ { image: [ { source: new TemplateImage(image), x: 180, y: 0, width: 680, height: 680, }, ], }, { image: [ { source: new TemplateImage( join(__dirname, "stewie-griffin-source.png") ), x: 0, y: 0, }, ], }, ], }; }); module.exports.stewieGriffin = async function (image) { const output = await createImageGenerator(StewieGriffin(image)).render(); const result = await output.encode("png"); return result; }; ``` ## Usage ```ts TypeScript import { writeFile } from "node:fs/promises"; import { stewieGriffin } from "./stewie-griffin"; const targetImage = "https://cdn.discordapp.com/embed/avatars/0.png"; const result = await stewieGriffin(targetImage); await writeFile("./stewie-griffin-result.png", result); ``` ```js ES Modules import { writeFile } from "node:fs/promises"; import { stewieGriffin } from "./stewie-griffin.js"; const targetImage = "https://cdn.discordapp.com/embed/avatars/0.png"; const result = await stewieGriffin(targetImage); await writeFile("./stewie-griffin-result.png", result); ``` ```js CommonJS const { writeFile } = require("node:fs/promises"); const { stewieGriffin } = require("./stewie-griffin.js"); async function main() { const targetImage = "https://cdn.discordapp.com/embed/avatars/0.png"; const result = await stewieGriffin(targetImage); await writeFile("./stewie-griffin-result.png", result); } main(); ``` ## Result stewie-griffin # Canvacord Examples Source: https://canvacord.neplex.dev/examples/introduction Various examples of Canvacord API usage that you can copy and paste into your project. Got something cool to show? [Submit your own example](https://github.com/neplextech/canvacord) by making a pull request. ## Builder Examples Here are some examples of Canvacord's Builder API usage that you can copy and paste into your project. Welcomer/Leaver card with a custom background and text. A music player card with a custom background and text. An Instagram post card. A tweet card example. An analog clock example. A Discord embed example. A large Discord profile card. A smaller Discord profile card. ## Image Manipulation Examples Here are some examples of Canvacord's Image Manipulation API usage that you can copy and paste into your project. Become Stewie Griffin from Family Guy. # Built-in Image Manipulation APIs Source: https://canvacord.neplex.dev/image-manipulation/builtin-apis Use Canvacord's built-in builders to generate commonly used memes, such as triggered gif, jail image, and more. This page is still a work in progress. ## Usage Canvacord's built-in image manipulation APIs can be used from `canvacord` object. You need to import the `canvacord` object from the package as shown below: ```ts TypeScript import { canvacord } from "canvacord"; ``` ```js ES Modules import { canvacord } from "canvacord"; ``` ```js CommonJS const { canvacord } = require("canvacord"); ``` ## Image Manipulation (Filters) The filters API can be used to apply filters to an image, such as hue rotation, saturation, brightness, contrast, and more. ```ts TypeScript import { canvacord } from "canvacord"; const output = await canvacord(image).hueRotate(70).encode(); // or const output = await canvacord .filters(500, 500) .drawImage(image) .hueRotate(70) .encode(); ``` ```js ES Modules import { canvacord } from "canvacord"; const output = await canvacord(image).hueRotate(70).encode(); // or const output = await canvacord .filters(500, 500) .drawImage(image) .hueRotate(70) .encode(); ``` ```js CommonJS const { canvacord } = require("canvacord"); const output = await canvacord(image).hueRotate(70).encode(); // or const output = await canvacord .filters(500, 500) .drawImage(image) .hueRotate(70) .encode(); ``` ## Image Manipulation (Image Generation) The image generation API can be used to generate images, such as affected image, triggered gif, beautiful image, and more. ```ts TypeScript import { canvacord } from "canvacord"; import { createWriteStream, promises as fs } from "fs"; const img = "image-1.png"; const img2 = "image-2.png"; const img3 = "image-3.png"; // template const affected = await canvacord.affect(img); fs.writeFile("./affected.png", affected); // gif const triggered = await canvacord.triggered(img); triggered.pipe(createWriteStream("./triggered.gif")); // fuse const fused = await canvacord.fuse(img, img2); fs.writeFile("./fused.png", fused); // kiss const kissed = await canvacord.kiss(img, img2); fs.writeFile("./kissed.png", kissed); // spank const spanked = await canvacord.spank(img, img2); fs.writeFile("./spanked.png", spanked); // slap const slapped = await canvacord.slap(img, img2); fs.writeFile("./slapped.png", slapped); // beautiful const beautiful = await canvacord.beautiful(img); fs.writeFile("./beautiful.png", beautiful); // facepalm const facepalm = await canvacord.facepalm(img); fs.writeFile("./facepalm.png", facepalm); // rainbow const rainbow = await canvacord.rainbow(img); fs.writeFile("./rainbow.png", rainbow); // rip const rip = await canvacord.rip(img); fs.writeFile("./rip.png", rip); // trash const trash = await canvacord.trash(img); fs.writeFile("./trash.png", trash); // hitler const hitler = await canvacord.hitler(img); fs.writeFile("./hitler.png", hitler); // distracted const distracted = await canvacord.distracted(img, img2, img3); fs.writeFile("./distracted.png", distracted); ``` ```js ES Modules import { canvacord } from "canvacord"; import { createWriteStream, promises as fs } from "fs"; const img = "image-1.png"; const img2 = "image-2.png"; const img3 = "image-3.png"; // template const affected = await canvacord.affect(img); fs.writeFile("./affected.png", affected); // gif const triggered = await canvacord.triggered(img); triggered.pipe(createWriteStream("./triggered.gif")); // fuse const fused = await canvacord.fuse(img, img2); fs.writeFile("./fused.png", fused); // kiss const kissed = await canvacord.kiss(img, img2); fs.writeFile("./kissed.png", kissed); // spank const spanked = await canvacord.spank(img, img2); fs.writeFile("./spanked.png", spanked); // slap const slapped = await canvacord.slap(img, img2); fs.writeFile("./slapped.png", slapped); // beautiful const beautiful = await canvacord.beautiful(img); fs.writeFile("./beautiful.png", beautiful); // facepalm const facepalm = await canvacord.facepalm(img); fs.writeFile("./facepalm.png", facepalm); // rainbow const rainbow = await canvacord.rainbow(img); fs.writeFile("./rainbow.png", rainbow); // rip const rip = await canvacord.rip(img); fs.writeFile("./rip.png", rip); // trash const trash = await canvacord.trash(img); fs.writeFile("./trash.png", trash); // hitler const hitler = await canvacord.hitler(img); fs.writeFile("./hitler.png", hitler); // distracted const distracted = await canvacord.distracted(img, img2, img3); fs.writeFile("./distracted.png", distracted); ``` ```js CommonJS const { canvacord } = require("canvacord"); const { createWriteStream, promises: fs } = require("fs"); const img = "image-1.png"; const img2 = "image-2.png"; const img3 = "image-3.png"; // template const affected = await canvacord.affect(img); fs.writeFile("./affected.png", affected); // gif const triggered = await canvacord.triggered(img); triggered.pipe(createWriteStream("./triggered.gif")); // fuse const fused = await canvacord.fuse(img, img2); fs.writeFile("./fused.png", fused); // kiss const kissed = await canvacord.kiss(img, img2); fs.writeFile("./kissed.png", kissed); // spank const spanked = await canvacord.spank(img, img2); fs.writeFile("./spanked.png", spanked); // slap const slapped = await canvacord.slap(img, img2); fs.writeFile("./slapped.png", slapped); // beautiful const beautiful = await canvacord.beautiful(img); fs.writeFile("./beautiful.png", beautiful); // facepalm const facepalm = await canvacord.facepalm(img); fs.writeFile("./facepalm.png", facepalm); // rainbow const rainbow = await canvacord.rainbow(img); fs.writeFile("./rainbow.png", rainbow); // rip const rip = await canvacord.rip(img); fs.writeFile("./rip.png", rip); // trash const trash = await canvacord.trash(img); fs.writeFile("./trash.png", trash); // hitler const hitler = await canvacord.hitler(img); fs.writeFile("./hitler.png", hitler); // distracted const distracted = await canvacord.distracted(img, img2, img3); fs.writeFile("./distracted.png", distracted); ``` # Image Manipulation API Source: https://canvacord.neplex.dev/image-manipulation/image-manipulation-api Learn how to manipulate images using Canvacord's image manipulation api. This page is still a work in progress. Canvacord's image manipulation API works by allowing you to define how image should be processed by using a schema object. The schema object is a JavaScript object that defines the image manipulation process. This schema can generate both static as well as animated images. ## Example Check out [Stewie Griffin](/examples/image-manipulation/stewie-griffin) example to see how you can create your own image manipulation function. ### Usage ```ts TypeScript import { createTemplate, ImageFactory, TemplateImage, createImageGenerator, type ImageSource, } from "canvacord"; const Manipulator = createTemplate((image: ImageSource) => { return { steps: [ // base image { // one step can take multiple images image: [ { source: new TemplateImage(ImageFactory.AFFECT), // source image x: 0, // x position y: 0, // y position }, ], }, // target image { image: [ { source: new TemplateImage(image), // target image x: 180, // x position y: 383, // y position width: 200, // width height: 157, // height }, ], }, ], }; }); // get target photo to use on "affected" meme image const photo = await getPhotoForMemeSomehow(); const generator = createImageGenerator(Manipulator(photo)); // render out the image await generator.render(); // get the resulting image in png format const affectedMeme = await generator.encode("png"); ``` ```js ES Modules import { createTemplate, ImageFactory, TemplateImage, createImageGenerator, } from "canvacord"; const Manipulator = createTemplate((image) => { return { steps: [ // base image { // one step can take multiple images image: [ { source: new TemplateImage(ImageFactory.AFFECT), // source image x: 0, // x position y: 0, // y position }, ], }, // target image { image: [ { source: new TemplateImage(image), // target image x: 180, // x position y: 383, // y position width: 200, // width height: 157, // height }, ], }, ], }; }); // get target photo to use on "affected" meme image const photo = await getPhotoForMemeSomehow(); const generator = createImageGenerator(Manipulator(photo)); // render out the image await generator.render(); // get the resulting image in png format const affectedMeme = await generator.encode("png"); ``` ```js CommonJS const { createTemplate, ImageFactory, TemplateImage, createImageGenerator, } = require("canvacord"); const Manipulator = createTemplate((image) => { return { steps: [ // base image { // one step can take multiple images image: [ { source: new TemplateImage(ImageFactory.AFFECT), // source image x: 0, // x position y: 0, // y position }, ], }, // target image { image: [ { source: new TemplateImage(image), // target image x: 180, // x position y: 383, // y position width: 200, // width height: 157, // height }, ], }, ], }; }); // get target photo to use on "affected" meme image const photo = await getPhotoForMemeSomehow(); const generator = createImageGenerator(Manipulator(photo)); // render out the image await generator.render(); // get the resulting image in png format const affectedMeme = await generator.encode("png"); ``` ### Structure ```ts export interface ImageGenerationStep { /** * The image to render. */ image?: ImgenStep[]; /** * The text to render. */ text?: TextGenerationStep[]; /** * The custom steps to apply to the canvas. */ custom?: CustomGenerationStep[]; /** * The function to call before processing this step. */ preprocess?: ( canvas: Canvas, ctx: SKRSContext2D, step: ImageGenerationStep ) => Awaited; /** * The function to call when processing this step. */ process?: ( canvas: Canvas, ctx: SKRSContext2D, step: ImageGenerationStep ) => Awaited; /** * The function to call after processing has finished. */ postprocess?: ( canvas: Canvas, ctx: SKRSContext2D, step: ImageGenerationStep ) => Awaited; } export interface CustomGenerationStep { /** * The function to call when processing this step. */ process: ( canvas: Canvas, ctx: SKRSContext2D, step: ImageGenerationStep ) => Awaited; } export interface ImgenStep { /** * The image to render. */ source: TemplateImage; /** * The x position of the image. */ x: number; /** * The y position of the image. */ y: number; /** * The width of the image. */ width?: number; /** * The height of the image. */ height?: number; /** * The function to call before processing this step. */ preprocess?: ( canvas: Canvas, ctx: SKRSContext2D, source: ImgenStep ) => Awaited; /** * The function to call when processing this step. */ process?: ( canvas: Canvas, ctx: SKRSContext2D, source: ImgenStep ) => Awaited; /** * The function to call after processing has finished. */ postprocess?: ( canvas: Canvas, ctx: SKRSContext2D, source: ImgenStep ) => Awaited; } export interface TextGenerationStep { /** * The text to render. */ value: string; /** * The font of the text. */ font: string; /** * The color of the text. */ color: string; /** * Whether to stroke the text. */ stroke?: boolean; /** * The x position of the text. */ x: number; /** * The y position of the text. */ y: number; /** * The maximum width of the text. */ maxWidth?: number; /** * The line height of the text. */ lineHeight?: number; /** * The line width of the text. */ lineWidth?: number; /** * The alignment of the text. */ align?: "left" | "center" | "right"; /** * The baseline of the text. */ baseline?: "top" | "middle" | "bottom"; /** * The directionality of the text. */ direction?: "inherit" | "ltr" | "rtl"; /** * The function to call before processing this step. */ preprocess?: ( canvas: Canvas, ctx: SKRSContext2D, text: TextGenerationStep ) => Awaited; /** * The function to call when processing this step. */ process?: ( canvas: Canvas, ctx: SKRSContext2D, text: TextGenerationStep ) => Awaited; /** * The function to call after processing has finished. */ postprocess?: ( canvas: Canvas, ctx: SKRSContext2D, text: TextGenerationStep ) => Awaited; } /** * The template to use for image generation. */ export interface IImageGenerationTemplate { /** * The width of the template. */ width?: number; /** * The height of the template. */ height?: number; /** * The steps to apply to the canvas. */ steps: ImageGenerationStep[]; /** * The gif options. */ gif?: EncoderOptions; } ``` # Introduction Source: https://canvacord.neplex.dev/introduction Welcome to the canvacord documentation! *** ## What is canvacord? Canvacord is a powerful utility to generate beautiful images in JavaScript or TypeScript. You use React-like components to declare how you want your image to look, without ever having to calculate the position of elements or worry about the size of the canvas. Canvacord does all the heavy lifting for you, such as image rendering, formats conversion, and more. Canvacord abstracts the complexity of image generation and provides a simple and intuitive API to create images. This allows you to focus on the design and content of your images, rather than the technical details that goes into rendering them as needed. Whether you're a beginner or an expert, Canvacord is the perfect tool to create stunning images for your projects with little to no effort. *** ## Pre-requisites We try our best to make Canvacord as easy to use as possible. However, there are a few things you need to know before you start using Canvacord. To get the most out of Canvacord, you should have a basic understanding of the following: Since Canvacord is a JavaScript library, you should have a basic understanding of JavaScript to use it effectively. Since Canvacord relies heavily on HTML tags, you should have a basic understanding of it. Canvacord uses CSS to style the images, such as setting the font size, color, width, etc. Therefore, having a basic understanding of CSS will help you style your images effectively. Canvacord uses React-like components to generate images. Therefore, having a basic understanding of React and its terms will help you get started with Canvacord. ## Make it yours If you have the understanding of the above concepts, you're ready to start using Canvacord. You can start by installing Canvacord and creating your first image. If you're new to Canvacord, we recommend you start with the [Quick Start](/quickstart) guide to get a better understanding of how Canvacord works. Get started with Canvacord by creating your first image using built-in builders. Build your own image components using Canvacord's custom builders. Learn how to manipulate images using Canvacord's built-in image manipulation tools. Learn about Canvacord's API and how to use it effectively. Join our Discord server to get help, share your projects, and more. Contribute to Canvacord by submitting bug reports, feature requests, and more. # Quickstart Source: https://canvacord.neplex.dev/quickstart Get started with Canvacord ## Setup your development environment To get started with Canvacord, you need to have a few things set up on your local machine. * [Node.js](https://nodejs.org/en/download/): Canvacord is built on Node.js, so you need to have it installed on your machine. * [NPM](https://www.npmjs.com/get-npm): NPM is the package manager for Node.js. You will need it to install Canvacord and its dependencies. * Optionally [TypeScript](https://www.typescriptlang.org/download): To get the best out of Canvacord, we recommend you use TypeScript, but it's not required. ### Installation ```bash npm npm i canvacord ``` ```bash yarn yarn add canvacord ``` ```bash pnpm pnpm add canvacord ``` ```bash bun bun add canvacord ``` ### Use it in your project You can use Canvacord with or without JSX. JSX is a syntax extension for JavaScript that looks similar to HTML. It allows you to write HTML-like code in your JavaScript files. If you're familiar with React, you'll feel right at home with JSX. #### Using Canvacord with JSX ```jsx ES Modules /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ // The JSX pragma tells transpiler how to transform JSX into the equivalent JavaScript code // import Canvacord // Builder = The base class for creating custom builders // JSX = The JSX pragma for creating elements // Font = The Font class for loading custom fonts // FontFactory = The FontFactory for managing fonts import { Builder, JSX, Font, FontFactory } from "canvacord"; import { writeFile } from "node:fs/promises"; // define a builder class Generator extends Builder { constructor() { // set the size of the image super(300, 300); // if no fonts are loaded, load the default font if (!FontFactory.size) Font.loadDefault(); } async render() { // declare the shape of the image return (

Hello, World!

); } } // create an instance of the builder const generator = new Generator(); // build the image and save it to a file const image = await generator.build({ format: "png" }); await writeFile("image.png", image); ``` ```jsx CommonJS /** @jsx JSX.createElement */ /** @jsxFrag JSX.Fragment */ // The JSX pragma tells transpiler how to transform JSX into the equivalent JavaScript code // import Canvacord // Builder = The base class for creating custom builders // JSX = The JSX pragma for creating elements // Font = The Font class for loading custom fonts // FontFactory = The FontFactory for managing fonts const { Builder, JSX, Font, FontFactory } = require("canvacord"); const { writeFile } = require("node:fs/promises"); // define a builder class Generator extends Builder { constructor() { // set the size of the image super(300, 300); // if no fonts are loaded, load the default font if (!FontFactory.size) Font.loadDefault(); } async render() { // declare the shape of the image return (

Hello, World!

); } } async function main() { // create an instance of the builder const generator = new Generator(); // build the image and save it to a file const image = await generator.build({ format: "png" }); await writeFile("image.png", image); } main(); ```
#### Using Canvacord without JSX ```js ES Modules // import Canvacord // Builder = The base class for creating custom builders // JSX = The JSX pragma for creating elements // Font = The Font class for loading custom fonts // FontFactory = The FontFactory for managing fonts import { Builder, JSX, Font, FontFactory } from "canvacord"; import { writeFile } from "node:fs/promises"; // define a builder class Generator extends Builder { constructor() { // set the size of the image super(300, 300); // if no fonts are loaded, load the default font if (!FontFactory.size) Font.loadDefault(); } async render() { // declare the shape of the image return JSX.createElement( "div", { style: { display: "flex", alignItems: "center", justifyContent: "center", backgroundColor: "white", width: "100%", height: "100%", }, }, JSX.createElement("h1", null, "Hello, World!") ); } } // create an instance of the builder const generator = new Generator(); // build the image and save it to a file const image = await generator.build({ format: "png" }); await writeFile("image.png", image); ``` ```js CommonJS // import Canvacord // Builder = The base class for creating custom builders // JSX = The JSX pragma for creating elements // Font = The Font class for loading custom fonts // FontFactory = The FontFactory for managing fonts const { Builder, JSX, Font, FontFactory } = require("canvacord"); const { writeFile } = require("node:fs/promises"); // define a builder class Generator extends Builder { constructor() { // set the size of the image super(300, 300); // if no fonts are loaded, load the default font if (!FontFactory.size) Font.loadDefault(); } async render() { // declare the shape of the image return JSX.createElement( "div", { style: { display: "flex", alignItems: "center", justifyContent: "center", backgroundColor: "white", width: "100%", height: "100%", }, }, JSX.createElement("h1", null, "Hello, World!") ); } } async function main() { // create an instance of the builder const generator = new Generator(); // build the image and save it to a file const image = await generator.build({ format: "png" }); await writeFile("image.png", image); } main(); ```
## Result of the above code canvacord-quickstart-output ## Further reading To learn more about Canvacord, check out the following resources: Learn how to generate custom images using Canvacord's builder api. Learn how to manipulate images using Canvacord's built-in image manipulation utilities. Use Canvacord's built-in builders to create commonly used images quickly, such as rank cards, leaderboard images, and more. Use Canvacord's built-in builders to generate commonly used memes, such as triggered gif, jail image, and more. Find a list of builder examples that you can copy and paste into your project. Create an issue on GitHub if you have a suggestion or found a bug in Canvacord.