Referencia completa del lenguaje

Logic Script

El lenguaje de programación nativo de Ayami — ligero, seguro y hecho para automatizaciones en Discord. Escribe scripts, reacciona a eventos, envía embeds y gestiona los datos del servidor con código limpio y directo.

Inspirado en Lua Asíncrono En sandbox Extensión .logic Integrado con Logic Builder
Referencia rápida Abrir editor
🌸

Introducción

Logic Script es un lenguaje interpretado creado para automatizaciones dentro de servidores de Discord. Los scripts son archivos .logic que reaccionan a eventos de Discord — mensajes, miembros que entran, clics en botones — usando el bloque on.

Cada servidor tiene su propio entorno aislado: scripts, base de datos y configuraciones están completamente separados. Logic Script se ejecuta dentro del bot en un sandbox seguro — sin acceso al sistema operativo ni a recursos externos.

💡

Logic Script no reemplaza al Logic Builder — lo amplía. Los scripts pueden ser llamados desde flujos visuales y disparar eventos personalizados entre sí.

primeiro-script.logic
-- Meu primeiro script

on messageCreate(message)
  if message.content == "!ola" then
    message.reply("Olá! 👋")
  end
end
📦

Variables

Usa let para variables mutables y const para constantes. El alcance es léxico — las variables declaradas dentro de un bloque no existen fuera de él.

.logic
let nome   = "Ayami"
let pontos = 0
let ativo  = true
const PREFIX = "!"

-- Reatribuição (só funciona com let)
pontos = pontos + 10
🔢

Tipos de datos

TipoEjemploDescripción
number42, 3.14Enteros y decimales
string"texto", 'outro'Texto entre comillas simples o dobles
booltrue, falseBooleano
nilnilAusencia de valor
array[1, 2, 3]Lista ordenada
object{ nome: "A" }Mapa clave → valor
functionfunction() endLas funciones son valores de primera clase
.logic
let lista  = ["maçã", "pera", "uva"]
let pessoa = { nome: "Ayami", pontos: 100 }

print(lista[0])       -- "maçã"
print(pessoa.nome)    -- "Ayami"
print(type(42))       -- "number"
⚙️

Operadores

Matemáticos
Op.DescripciónEjemplo
+Suma2 + 35
-Resta10 - 46
*Multiplicación3 * 412
/División10 / 25
%Módulo10 % 31
..Concatenación"Oi " .. "Ayami"
Comparación y Lógicos
Op.Descripción
==Igual
!=Diferente
< / >Menor / Mayor
<= / >=Menor o igual / Mayor o igual
andY lógico
orO lógico
notNegación
🔀

Control de flujo

if / elseif / else
if pontos >= 100 then
  print("Ouro")
elseif pontos >= 50 then
  print("Prata")
else
  print("Bronze")
end
while / for numérico / for in
-- while
let i = 1
while i <= 5 do
  print(i)
  i = i + 1
end

-- for numérico: for var = início, fim [, passo] do
for i = 1, 10 do
  print(i)
end

-- for in (iteração)
let frutas = ["maçã", "pera", "uva"]
for fruta in frutas do
  print(fruta)
end
💡

Usa break para salir de un bucle y continue para saltar a la siguiente iteración.

🧩

Funciones

.logic
-- Declaração
function somar(a, b)
  return a + b
end

print(somar(3, 7))   -- 10

-- Funções anônimas (valores de primeira classe)
let dobrar = function(x)
  return x * 2
end

print(dobrar(5))    -- 10
📁

Import / Export

Organiza tu código en varios archivos. Usa export para exponer funciones e import para usarlas en otro script.

economia.logic
export function addCoins(user, qtd)
  db.user(user).add("coins", qtd)
  return db.user(user).get("coins")
end
trabalho.logic
import { addCoins } from "economia.logic"

on command("trabalhar", message, args)
  let ganho = random(10, 100)
  let total = addCoins(message.author, ganho)
  message.reply("💰 +" .. ganho .. " coins! Total: " .. total)
end

Eventos (on)

Los scripts reaccionan a eventos de Discord usando el bloque on. Para comandos por prefijo, el primer argumento es una cadena con el nombre del comando.

sintaxe
on nomeDoEvento(param1, param2)
  -- código aqui
end

-- Comando por prefixo (ex: !ping)
on command("ping", message, args)
  message.reply("🏓 Pong!")
end
EventoParámetrosSe dispara cuando
messageCreatemessageSe envía un mensaje
messageDeletemessageSe elimina un mensaje
messageEditmessageSe edita un mensaje
memberJoinmemberUn miembro entra al servidor
memberLeavememberUn miembro sale del servidor
buttonClickinteractionSe hace clic en un botón
selectMenuinteractionSe selecciona una opción de menú
command"nome", message, argsSe ejecuta un comando por prefijo
reactionAddemoji, user, messageSe añade una reacción
reactionRemoveemoji, user, messageSe elimina una reacción
voiceJoinmemberUn miembro entra a voz
voiceLeavememberUn miembro sale de voz
banAdduserUn usuario es baneado
banRemoveuserSe elimina un ban
channelCreatechannelSe crea un canal
channelDeletechannelSe elimina un canal
🗂️

Objetos de Discord

Message
Devuelto por messageCreate, sendMessage() y message.reply().
.idstringID del mensaje
.contentstringContenido de texto
.authorobjectAutor del mensaje (id, username, isBot…)
.channelstringID del canal
.edit(texto, opts?)functionEdita el mensaje. Acepta un embed en opts
.delete()functionElimina el mensaje
.reply(texto, opts?)functionResponde al mensaje
.react(emoji)functionAñade una reacción
.pin()functionFija el mensaje
User
Obtenido vía getUser() o message.author.
.idstringID del usuario
.usernamestringNombre de usuario
.nicknamestringApodo en el servidor
.rolesarrayIDs de roles
.isBotboolSi es un bot
.addRole(id)functionAñade un rol
.removeRole(id)functionElimina un rol
.timeout(ms)functionAplica un timeout en ms
.ban(motivo?)functionBanea al usuario
.kick()functionExpulsa al usuario
.send(texto, opts?)functionEnvía un DM
Interaction
Obtenido vía getInteraction(). Usado en buttonClick y selectMenu.
.customIdstringID del componente clicado
.valuesarrayValores seleccionados (SelectMenu)
.reply(texto, opts?)functionResponde. opts.ephemeral: true = privado
.defer(efemero?)functionAplaza la respuesta (loading)
.edit(texto, opts?)functionEdita la respuesta original
.followUp(texto, opts?)functionMensaje de seguimiento
.showModal(modal)functionAbre un Modal — debe haber pasado antes por .onSubmit(fn)
🎨

UI — Embed, Button, SelectMenu, Modal

Todos los métodos se pueden encadenar. Embed acepta todos los campos que admite Discord.

EmbedBuilder
let embed = new EmbedBuilder()
embed.setTitle("Título")
embed.setDescription("Descrição")
embed.setColor("#A9D6FF")
embed.setThumbnail("https://url.png")
embed.setFooter({ text: "Ayami" })
embed.addFields(
  { name: "Campo", value: "Valor", inline: true }
)
embed.setTimestamp(nil)  -- nil = agora

sendMessage(message.channel, "", { embed: embed })
Button & SelectMenu
let btn = Button()
btn.setLabel("Clique aqui")
btn.setStyle("primary")  -- primary | secondary | success | danger | link
btn.setCustomId("meu_botao")
btn.setEmoji("🎉")

let menu = SelectMenu()
menu.setCustomId("meu_menu")
menu.setPlaceholder("Escolha uma opção")
menu.addOptions(
  { label: "Opção 1", value: "op1" },
  { label: "Opção 2", value: "op2" }
)

sendMessage(message.channel, "Escolha:", {
  components: [btn, menu]
})
Capturando interações
on buttonClick(interaction)
  if interaction.customId == "meu_botao" then
    interaction.reply("✅ Clicou!", { ephemeral: true })
  end
end

on selectMenu(interaction)
  let valor = interaction.values[0]
  interaction.reply("Escolheu: " .. valor)
end
Modal
on buttonClick(interaction)
  if interaction.customId == "abrir_feedback" then
    let modal = Modal()
    modal.setTitle("Feedback")
    modal.addTextInput("nota", "Nota de 1 a 5", { style: "short" })
    modal.addTextInput("comentario", "Comentário", { style: "long", required: false })
    modal.onSubmit(function(interaction, fields)
      interaction.reply("Recebido! Nota: " .. fields.nota)
    end)

    interaction.showModal(modal)
  end
end

Solo funciona en respuesta a una interacción existente (buttonClick/selectMenu, o dentro de .onClick() de un Button/SelectMenu temporal) — no se puede abrir desde on(command).

🗄️

Base de datos

Base de datos persistente por servidor. Los datos sobreviven entre ejecuciones y reinicios.

db — global / user / guild
-- Global (por servidor)
db.set("chave", "valor")
db.get("chave")
db.has("chave")      -- → bool
db.delete("chave")

-- Por usuário
db.user(user).set("coins", 100)
db.user(user).get("coins")
db.user(user).add("coins", 50)   -- soma
db.user(user).sub("coins", 10)   -- subtrai

-- Por servidor (guild)
db.guild().set("config", { prefix: "!" })
db.guild().get("config")
🛠️

Funciones integradas

String
FunciónDescripción
length(s)Longitud de la cadena
contains(s, sub)Si contiene una subcadena
replace(s, de, para)Reemplazar texto
split(s, sep)Dividir en un array
join(arr, sep)Unir un array en una cadena
lower(s) / upper(s)Minúsculas / mayúsculas
trim(s)Elimina espacios
tostring(v)Convierte a cadena
tonumber(s)Convierte a número
Math
FunciónDescripción
random(min, max)Entero aleatorio entre min y max
round(n)Redondea
floor(n) / ceil(n)Piso / techo
abs(n)Valor absoluto
max(a, b, …) / min(a, b, …)Valor mayor / menor
Array & Object
FunciónDescripción
push(arr, v)Añade al final
pop(arr)Elimina y devuelve el último
insert(arr, i, v)Inserta en la posición i
remove(arr, i)Elimina en la posición i
size(v)Tamaño del array u objeto
keys(obj)Claves del objeto
values(obj)Valores del objeto
Utilidades
FunciónDescripción
print(…)Muestra en la consola del dashboard
type(v)Tipo del valor como cadena
wait(ms)Espera N ms (máx. 30 000ms/ejec.)
json.encode(v)Objeto → cadena JSON
json.decode(s)Cadena JSON → objeto
Tiempo
FunciónDescripción
schedule(tempo, canal, texto, opts?)Programa un mensaje — tiempo: ms, "1h" o "9:00". Con {recurrente:true} se repite
cancelSchedule(id)Cancela una programación pendiente
listSchedules()Lista las programaciones pendientes del servidor
cooldown(chave, tempo)true si puede actuar ahora (y lo marca); false si está en espera
cooldownRestante(chave)Ms restantes del cooldown
🔒

Sandbox y Límites

🚫

Lo que no existe en Logic Script: acceso al sistema de archivos, módulos de Node.js (require), red externa fuera de las APIs de Discord, acceso a otros servidores o bibliotecas externas.

LímiteValorDescripción
Pasos por ejecución50 000Evita bucles infinitos
Profundidad de recursión200Evita desbordamiento de pila
Total de wait() por ejecución30 000msLímite acumulado de espera
Scripts simultáneos por guild20Límite de concurrencia
TTL de los logs7 diasLos logs expiran automáticamente

Ejemplos completos

👋
Bienvenida con embed
Envía un embed personalizado cuando un miembro entra
boas-vindas.logic
on memberJoin(member)
  let canal = getChannel("ID_DO_CANAL")
  let guild = getGuild()

  let embed = new EmbedBuilder()
  embed.setTitle("Bem-vindo(a)! 🌸")
  embed.setDescription("Olá, <@" .. member.id .. ">!\nVocê é o membro nº " .. guild.memberCount)
  embed.setColor("#A9D6FF")
  embed.setFooter({ text: "Ayami Hoshiori" })
  embed.setTimestamp(nil)

  canal.send("", { embed: embed })
end
💰
Sistema de economía
Comandos !trabajar, !saldo y !transferir
economia.logic
on command("trabalhar", message, args)
  let ganho = random(10, 100)
  db.user(message.author).add("coins", ganho)
  let total = db.user(message.author).get("coins")
  message.reply("💰 +" .. ganho .. " coins! Saldo: " .. total)
end

on command("saldo", message, args)
  let raw   = db.user(message.author).get("coins")
  let total = raw or 0
  message.reply("💳 Saldo: **" .. total .. " coins**")
end

on command("transferir", message, args)
  let valor = tonumber(args[0])
  let alvo  = args[1]

  if valor <= 0 or alvo == nil then
    message.reply("❌ Use: !transferir <valor> <@usuário>")
    return
  end

  let saldo = db.user(message.author).get("coins") or 0

  if saldo < valor then
    message.reply("❌ Saldo insuficiente.")
    return
  end

  db.user(message.author).sub("coins", valor)
  db.user(alvo).add("coins", valor)
  message.reply("✅ Transferência de **" .. valor .. " coins** realizada!")
end
🎭
Panel de roles por botón
Comando que envía botones; el clic añade el rol
cargos.logic
on command("painel", message, args)
  let btn1 = Button()
  btn1.setLabel("🎨 Designer")
  btn1.setStyle("primary")
  btn1.setCustomId("cargo_designer")

  let btn2 = Button()
  btn2.setLabel("💻 Dev")
  btn2.setStyle("secondary")
  btn2.setCustomId("cargo_dev")

  let embed = new EmbedBuilder()
  embed.setTitle("🎭 Selecione seu cargo")
  embed.setDescription("Clique no botão da sua área.")
  embed.setColor("#7C8FFF")

  message.reply("", { embed: embed, components: [btn1, btn2] })
end

on buttonClick(interaction)
  let user = getUser()
  let id   = interaction.customId

  if id == "cargo_designer" then
    user.addRole("ID_CARGO_DESIGNER")
    interaction.reply("✅ Cargo Designer adicionado!", { ephemeral: true })
  elseif id == "cargo_dev" then
    user.addRole("ID_CARGO_DEV")
    interaction.reply("✅ Cargo Dev adicionado!", { ephemeral: true })
  end
end

¿Listo para empezar?

Añade a Ayami a tu servidor y abre el editor en el Dashboard para crear tus primeros scripts.