Skip to content

Instantly share code, notes, and snippets.

@ayashiiiyo
Last active April 18, 2026 09:20
Show Gist options
  • Select an option

  • Save ayashiiiyo/5426682446e39c0f130d20a00fbc3b11 to your computer and use it in GitHub Desktop.

Select an option

Save ayashiiiyo/5426682446e39c0f130d20a00fbc3b11 to your computer and use it in GitHub Desktop.
import { Canvas, loadImage, FontLibrary } from 'skia-canvas'
import fs from 'fs'
import path from 'path'
import { execSync } from 'child_process'
const FONT_URL = 'https://raw.githubusercontent.com/uploader762/dat2/main/uploads/ebea8a-1776501237434.ttf'
const FONT_PATH = './Poppins-Bold.ttf'
const BG_URL = 'https://raw.githubusercontent.com/uploader762/dat1/main/uploads/4f8284-1776503052781.jpg'
async function downloadFont(url, pathFile) {
const res = await fetch(url)
const buffer = Buffer.from(await res.arrayBuffer())
fs.writeFileSync(pathFile, buffer)
}
if (!fs.existsSync(FONT_PATH)) {
await downloadFont(FONT_URL, FONT_PATH)
}
FontLibrary.use('Poppins', [FONT_PATH])
const left = 275
const right = 1011
const topY = 574
const bottomY = 1032
const centerX = (left + right) / 2
const centerY = 804
function wrapLines(ctx, text, maxWidth) {
const words = text.split(' ')
let line = ''
const lines = []
for (let i = 0; i < words.length; i++) {
const test = line + words[i] + ' '
const width = ctx.measureText(test).width
if (width > maxWidth && i > 0) {
lines.push(line)
line = words[i] + ' '
} else {
line = test
}
}
lines.push(line)
return lines
}
function drawText(ctx, text) {
const maxWidth = right - left
const maxHeight = bottomY - topY
let fontSize = 95
let lines, lineHeight, totalHeight
do {
ctx.font = `${fontSize}px Poppins`
lines = wrapLines(ctx, text, maxWidth)
lineHeight = fontSize * 1.15
totalHeight = lines.length * lineHeight
fontSize -= 2
} while (totalHeight > maxHeight && fontSize > 10)
ctx.font = `${fontSize}px Poppins`
ctx.fillStyle = '#000000'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
const finalLineHeight = fontSize * 1.15
const startY = centerY - (lines.length * finalLineHeight / 2) + (finalLineHeight / 2)
lines.forEach((line, i) => {
ctx.fillText(line, centerX, startY + (i * finalLineHeight))
})
}
async function renderImage(text) {
const canvas = new Canvas(1280, 1280)
const ctx = canvas.getContext('2d')
const bg = await loadImage(BG_URL)
canvas.width = bg.width
canvas.height = bg.height
ctx.drawImage(bg, 0, 0)
drawText(ctx, text)
return await canvas.png
}
async function renderVideo(text) {
const words = text.split(' ')
const tmpDir = './tmp_frames'
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir)
const frames = []
for (let i = 0; i < words.length; i++) {
const partial = words.slice(0, i + 1).join(' ')
const canvas = new Canvas(1280, 1280)
const ctx = canvas.getContext('2d')
const bg = await loadImage(BG_URL)
canvas.width = bg.width
canvas.height = bg.height
ctx.drawImage(bg, 0, 0)
drawText(ctx, partial)
const framePath = path.join(tmpDir, `frame_${i}.png`)
const buffer = await canvas.png
fs.writeFileSync(framePath, buffer)
frames.push(framePath)
}
const listPath = path.join(tmpDir, 'list.txt')
let list = ''
frames.forEach(f => {
const abs = path.resolve(f).replace(/\\/g, '/')
list += `file '${abs}'\n`
list += `duration 0.8\n`
})
const last = path.resolve(frames[frames.length - 1]).replace(/\\/g, '/')
list += `file '${last}'\n`
list += `duration 2\n`
fs.writeFileSync(listPath, list)
const listAbs = path.resolve(listPath).replace(/\\/g, '/')
execSync(`ffmpeg -y -f concat -safe 0 -i "${listAbs}" -vf "fps=30,format=yuv420p" "output.mp4"`)
frames.forEach(f => fs.unlinkSync(f))
fs.unlinkSync(listPath)
fs.rmdirSync(tmpDir)
return fs.readFileSync('output.mp4')
}
let handler = async (m, { conn, text, command }) => {
try {
if (!text) return m.reply(`Example: .${command} Halo dunia`)
m.reply(global.wait)
switch (command) {
case 'bratnime': {
const buffer = await renderImage(text)
return await conn.sendSticker(m.chat, Buffer.from(buffer), m)
}
case 'bratnimevid': {
const buffer = await renderVideo(text)
const file = './temp.mp4'
fs.writeFileSync(file, buffer)
const out = './cut.mp4'
execSync(`ffmpeg -y -i "${file}" -t 9.9 -c copy "${out}"`)
const final = fs.readFileSync(out)
fs.unlinkSync(file)
fs.unlinkSync(out)
return await conn.sendSticker(m.chat, Buffer.from(final), m)
}
}
} catch (e) {
m.reply(e.message)
}
}
handler.help = ['bratnime', 'bratnimevid']
handler.tags = ['tools']
handler.command = ['bratnime', 'bratnimevid']
export default handler
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment