📜 Referência completa da linguagem

Logic Script

A linguagem de programação nativa da Ayami — leve, segura e feita para automações no Discord. Escreva scripts, reaja a eventos, envie embeds e gerencie dados do servidor com código limpo e direto.

🧠 Inspirada no Lua ⚡ Assíncrona 🔒 Sandboxada 📜 Extensão .logic 🎨 Logic Builder integrado
📋 Referência rápida ✨ Abrir editor
🌸

Introdução

O Logic Script é uma linguagem interpretada criada para automações dentro de servidores Discord. Scripts são arquivos .logic que reagem a eventos do Discord — mensagens, membros entrando, cliques em botões — usando o bloco on.

Cada servidor tem seu próprio ambiente isolado: scripts, banco de dados e configurações são completamente separados. O Logic Script roda dentro do bot em uma sandbox segura — sem acesso ao sistema operacional ou a recursos externos.

💡

O Logic Script não substitui o Logic Builder — ele o expande. Scripts podem ser chamados a partir de fluxos visuais e disparar eventos personalizados entre si.

primeiro-script.logic
-- Meu primeiro script

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

Variáveis

Use let para variáveis mutáveis e const para constantes. O escopo é léxico — variáveis declaradas dentro de um bloco não existem fora dele.

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

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

Tipos de dados

TipoExemploDescrição
number42, 3.14Inteiros e decimais
string"texto", 'outro'Texto entre aspas simples ou duplas
booltrue, falseBooleano
nilnilAusência de valor
array[1, 2, 3]Lista ordenada
object{ nome: "A" }Mapa chave → valor
functionfunction() endFunções são valores de primeira classe
.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.DescriçãoExemplo
+Adição2 + 35
-Subtração10 - 46
*Multiplicação3 * 412
/Divisão10 / 25
%Módulo10 % 31
..Concatenação"Oi " .. "Ayami"
Comparação & Lógicos
Op.Descrição
==Igual
!=Diferente
< / >Menor / Maior
<= / >=Menor ou igual / Maior ou igual
andE lógico
orOU lógico
notNegação
🔀

Controle de fluxo

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
💡

Use break para sair de um loop e continue para pular para a próxima iteração.

🧩

Funções

.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

Organize código em múltiplos arquivos. Use export para expor funções e import para usá-las em outro 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)

Scripts reagem a eventos do Discord usando o bloco on. Para comandos por prefixo, o primeiro argumento é uma string com o nome do 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âmetrosDisparado quando
messageCreatemessageUma mensagem é enviada
messageDeletemessageUma mensagem é deletada
messageEditmessageUma mensagem é editada
memberJoinmemberMembro entra no servidor
memberLeavememberMembro sai do servidor
buttonClickinteractionBotão é clicado
selectMenuinteractionOpção de menu selecionada
command"nome", message, argsComando por prefixo executado
reactionAddemoji, user, messageReação adicionada
reactionRemoveemoji, user, messageReação removida
voiceJoinmemberMembro entra em voz
voiceLeavememberMembro sai de voz
banAdduserUsuário é banido
banRemoveuserBan removido
channelCreatechannelCanal criado
channelDeletechannelCanal deletado
🗂️

Objetos Discord

Message
Retornado por messageCreate, sendMessage() e message.reply().
.idstringID da mensagem
.contentstringConteúdo de texto
.authorobjectAutor da mensagem (id, username, isBot…)
.channelstringID do canal
.edit(texto, opts?)functionEdita a mensagem. Aceita embed em opts
.delete()functionDeleta a mensagem
.reply(texto, opts?)functionResponde à mensagem
.react(emoji)functionAdiciona uma reação
.pin()functionFixa a mensagem
User
Obtido via getUser() ou message.author.
.idstringID do usuário
.usernamestringNome de usuário
.nicknamestringApelido no servidor
.rolesarrayIDs de cargos
.isBotboolSe é um bot
.addRole(id)functionAdiciona cargo
.removeRole(id)functionRemove cargo
.timeout(ms)functionAplica timeout em ms
.ban(motivo?)functionBane o usuário
.kick()functionExpulsa o usuário
.send(texto, opts?)functionEnvia DM
Interaction
Obtido via getInteraction(). Usado em buttonClick e selectMenu.
.customIdstringID do componente clicado
.valuesarrayValores selecionados (SelectMenu)
.reply(texto, opts?)functionResponde. opts.ephemeral: true = privado
.defer(efemero?)functionAdia a resposta (loading)
.edit(texto, opts?)functionEdita a resposta original
.followUp(texto, opts?)functionMensagem de acompanhamento
.showModal(modal)functionAbre um Modal — precisa já ter passado por .onSubmit(fn)
🎨

UI — Embed, Button, SelectMenu, Modal

Todos os métodos podem ser encadeados. Embed aceita todos os campos enviáveis pelo 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

Só funciona em resposta a uma interação existente (buttonClick/selectMenu, ou dentro de .onClick() de um Button/SelectMenu temporário) — não dá pra abrir a partir de on(command).

🗄️

Banco de dados

Banco persistente por servidor. Os dados sobrevivem entre execuções e reinicializações.

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")
🛠️

Funções built-in

String
FunçãoDescrição
length(s)Tamanho da string
contains(s, sub)Se contém substring
replace(s, de, para)Substituir texto
split(s, sep)Dividir em array
join(arr, sep)Unir array em string
lower(s) / upper(s)Minúsculas / maiúsculas
trim(s)Remove espaços
tostring(v)Converte para string
tonumber(s)Converte para número
Math
FunçãoDescrição
random(min, max)Inteiro aleatório entre min e max
round(n)Arredonda
floor(n) / ceil(n)Piso / teto
abs(n)Valor absoluto
max(a, b, …) / min(a, b, …)Maior / menor valor
Array & Object
FunçãoDescrição
push(arr, v)Adiciona ao final
pop(arr)Remove e retorna o último
insert(arr, i, v)Insere na posição i
remove(arr, i)Remove na posição i
size(v)Tamanho do array ou objeto
keys(obj)Chaves do objeto
values(obj)Valores do objeto
Utilitários
FunçãoDescrição
print(…)Exibe no console do dashboard
type(v)Tipo do valor como string
wait(ms)Aguarda N ms (máx 30 000ms/exec.)
json.encode(v)Objeto → JSON string
json.decode(s)JSON string → objeto
Tempo
FunçãoDescrição
schedule(tempo, canal, texto, opts?)Agenda mensagem — tempo: ms, "1h" ou "9:00". Com {recorrente:true} repete
cancelSchedule(id)Cancela um agendamento pendente
listSchedules()Lista agendamentos pendentes do servidor
cooldown(chave, tempo)true se pode agir agora (e já marca); false se em espera
cooldownRestante(chave)Ms restantes do cooldown
🔒

Sandbox & Limites

🚫

O que não existe no Logic Script: acesso ao sistema de arquivos, módulos Node.js (require), rede externa fora das APIs do Discord, acesso a outros servidores ou bibliotecas externas.

LimiteValorDescrição
Passos por execução50 000Previne loops infinitos
Profundidade de recursão200Previne stack overflow
Total de wait() por execução30 000msLimite acumulado de espera
Scripts simultâneos por guild20Limite de concorrência
TTL dos logs7 diasLogs expiram automaticamente

Exemplos completos

👋
Boas-vindas com embed
Envia um embed personalizado quando um membro 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 economia
Comandos !trabalhar, !saldo e !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
🎭
Painel de cargos por botão
Comando que envia botões; clique adiciona o cargo
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

Pronto para começar? ⭐

Adicione a Ayami ao seu servidor e abra o editor no Dashboard para criar seus primeiros scripts.