Kembali ke katalog plugin
maker
attp
Bikin stiker teks animasi warna-warni
Make an animated colorful text sticker
plugins/maker/attp.js
Lokasi file di repo kana-md
1
Perintah termasuk alias
2.9 KB
Ukuran file sumber
4/11/2026
Update terakhir, commit 7d56ace
Daftar perintah
Ketuk tombol salin untuk menyalin perintah, lalu tempel di chat WhatsApp bot KANA.
.attpCara pakai
.attp <teks>
Contoh
.attp keren banget
Kode sumber plugin
Cara pasang: simpan file ini ke folder plugins/maker/ di bot KANA kamu, lalu restart bot. Pemilik source code lain bisa mengambil update plugin terbaru dari halaman ini kapan saja.
import { execFile } from 'node:child_process'
import { promisify } from 'node:util'
import { readFile, writeFile } from 'node:fs/promises'
import { join } from 'node:path'
import { textImage } from '../../src/services/text-image.js'
import { toStickerWebp } from '../../src/services/sticker.js'
import { withTempDir } from '../../src/scrapers/runner.js'
import { sendButtons } from '../../src/ui/buttons.js'
import { sendSticker } from './sticker.js'
const execFileP = promisify(execFile)
const FRAME_COLORS = ['magenta', 'cyan', 'yellow']
export const config = {
name: 'attp',
alias: [],
category: 'maker',
description: { id: 'Bikin stiker teks animasi warna-warni', en: 'Make an animated colorful text sticker' },
usage: '.attp <teks>',
example: '.attp keren banget',
cooldown: 5,
limit: 3,
}
export const i18n = {
id: {
attp: {
needText: 'Ketik teksnya dulu yaa, contoh: .attp keren banget~',
failed: 'Mouu, gagal bikin stiker attp: {message}~',
done: 'Stiker attpnya jadii~',
menuButton: 'Menu Maker',
},
},
en: {
attp: {
needText: 'Type the text first, example: .attp so cool~',
failed: 'Mouu, failed to make the attp sticker: {message}~',
done: 'Your attp sticker is ready~',
menuButton: 'Maker Menu',
},
},
}
async function animatedWebp(frames) {
return withTempDir(async (dir) => {
for (let i = 0; i < frames.length; i++) await writeFile(join(dir, `frame-${i + 1}.png`), frames[i])
const out = join(dir, 'out.webp')
const args = [
'-y', '-framerate', '2', '-i', join(dir, 'frame-%d.png'),
'-vf', 'scale=512:512,format=rgba',
'-c:v', 'libwebp', '-lossless', '0', '-quality', '80', '-loop', '0', '-an', out,
]
await execFileP('ffmpeg', args, { timeout: 60000 })
return readFile(out)
})
}
export const test = { input: '.attp keren banget', expect: /Stiker attpnya/i }
export async function handler(ctx) {
const text = ctx.text.trim()
if (!text) return ctx.reply(ctx.t('attp.needText'))
try {
const frames = []
for (const color of FRAME_COLORS) {
frames.push(
await textImage({
width: 512,
height: 512,
background: '0x111111',
lines: [{ text, size: 52, color, bold: true, y: 210 }],
})
)
}
let webp
try {
webp = await animatedWebp(frames)
} catch {
// Jalur animasi gagal: fallback stiker statis dari frame pertama.
webp = await toStickerWebp(frames[0], { animated: false })
}
await sendSticker(ctx, webp)
await sendButtons(ctx.sock, ctx.chat, {
title: 'KANA',
body: ctx.t('attp.done'),
footer: ctx.t('menu.footer'),
replies: [{ text: ctx.t('attp.menuButton'), id: '.menu maker' }],
textFallback: ctx.t('attp.done'),
})
} catch (err) {
return ctx.reply(ctx.t('attp.failed', { message: err.message }))
}
}
