Executando verificação de segurança...
2

Pitch: Se o Luau foi a linguagem que te ensinou a programar — agora você pode usá-la pra ganhar dinheiro também. Boa sorte e vê se não faz `while true do end` em produção!

Luau não é só pro Roblox: criei um runtime de alta performance em Rust pra uso geral

Esse artigo conta a história de como eu, um desenvolvedor que aprendeu a programar com Luau — sim, aquela linguagem do Roblox — decidi que ela merecia voar fora do playground e construí um runtime completo do zero, em Rust, pra rodar Luau em qualquer lugar: backend, scripts, sistemas embarcados, o que for.


Começo: por que Luau?

Pra quem não conhece, Luau é uma linguagem derivada do Lua 5.1, mantida pela Roblox. É a linguagem de scripting deles e, pra muita gente — inclusive eu —, foi a primeira linguagem de programação de verdade. Ela virou open source em 3 de novembro de 2021, a partir da versão 0.501. A Roblox abriu o código pra comunidade ajudar a evoluir a linguagem e pra que ela pudesse ser usada fora do motor do Roblox — exatamente o que eu tô fazendo aqui. Quando abriu, o Luau já veio com tipagem gradual e análise estática, então não precisou esperar nada pra ter uma linguagem que cresce com o projeto.

Mesmo assim, na prática, continuou sendo "coisa do Roblox". Não existia runtime standalone fácil de usar pra nada fora do Studio.

Mas a situação tá mudando. A equipe do luau-lang tá construindo o Lute, um runtime oficial em C++ que começou em outubro de 2024. É um projeto sério com nightly builds todo dia, stdlib com I/O, rede, sockets, e até um build tool chamado luthier. Mas enquanto isso, eu resolvi não esperar e fiz a minha própria versão em Rust.

O que eu construí

Criei o Nicy Runtime — um runtime de Luau genérico, de alta performance, feito em Rust. Não é um fork, não é um wrapper gambiarra. É a engine do Luau compilada como biblioteca nativa (cdylib) usando o binding mlua-sys, com uma camada de FFI em C pra qualquer linguagem conseguir chamar.

GitHub: https://github.com/nicy-luau/Runtime

A arquitetura é modular em dois pedaços:

  • nicy — o binário CLI. É o frontend que você usa no terminal pra rodar scripts, avaliar código, compilar pra bytecode.
  • nicyruntime — a biblioteca dinâmica. É o cérebro: engine Luau, scheduler assíncrono, resolvedor de módulos, FFI, tudo.
nicy run script.luau          # Rodar um script
nicy eval "print('oi')"       # Avaliar código inline
nicy compile script.luau      # Compilar pra bytecode (.luauc)

E a biblioteca também pode ser carregada via FFI em qualquer linguagem que suporte .dll, .so, .dylib — C, C++, Python, C#, Node.js, Go, Swift, Rust...

O que tem dentro

Task Scheduler assíncrono

O Luau do Roblox tem a task library — task.spawn, task.defer, task.delay, task.wait, task.cancel. Eu reimplementei toda ela do zero, em Rust, com cooperative multitasking real.

task.spawn(function()
    print("comecei")
    task.wait(1)  -- pausa por 1 segundo sem travar o resto
    print("acabei")
end)

Tem teste de estresse com 10k+ operações pra garantir que não tem race condition nem deadlock. E tem um detalhe de segurança: o task.cancel valida que o ID não ultrapassa 2^53, porque acima disso f64 perde precisão e você pode cancelar a task errada sem saber.

Require resolver com cache e aliases

O require() do Nicy não é só "procura arquivo no disco". Ele tem cache de módulos com file fingerprinting, suporte a aliases via .luaurc, detecção de dependências circulares, carregamento de bytecode compilado (.luauc) e módulos nativos via runtime.loadlib().

E o loadlib carrega qualquer shared library do sistema — .dll no Windows, .so no Linux, .dylib no macOS. Você pode escrever código em C, Rust, Zig, compilar pra library e carregar direto do Luau.

JIT/CodeGen nativo

Luau tem um compilador de bytecode pra código nativo. Basta colocar --!native na primeira linha do arquivo e o runtime ativa o CodeGen automaticamente. É uma diferença absurda de performance pra código numérico e loops pesados.

Desativei no Android por estabilidade, mas nas demais plataformas funciona full. O mlua-sys é compilado com features diferentes por target pra lidar com as diferenças de binário do Luau entre arquiteturas — como o tamanho de TValue no x86 Linux que obriga a remover vector4.

C-ABI completo

A biblioteca exporta ~90 funções via extern "C":

  • nicy_start(filepath) — inicializa e roda um script
  • nicy_eval(code) — avalia código isolado
  • nicy_compile(filepath) — compila pra bytecode
  • nicy_version() / nicy_lua_version() — versões
  • nicy_error_name(code) / nicy_is_nicy_error(code) — utilitários de erro
  • Todas as funções da Lua C API (nicy_lua_*, nicy_luaL_*)

Qualquer linguagem com libloading consegue usar. Você pode colocar Luau dentro de um servidor web, um editor, um jogo, um sistema embarcado, o que for.

Por que Rust?

Lua é C puro. C é rápido, mas FFI com C é um campo minado — ponteiro nulo, use-after-free, double-free, stack desbalanceado depois de erro. Rust resolve tudo isso de uma vez:

  • catch_unwind em todas as 5 operações do scheduler — pânico não escapa e não crasha o processo host
  • null_guard! em todas as ~90 exports de FFI — ponteiro nulo retorna erro, não undefined behavior
  • unsafe scopes mínimos — só o contato direto com a FFI é unsafe, o resto é Rust seguro
  • State tracking — o runtime rastreia se o lua_State ainda é válido (via CURRENT_L_VALID) pra evitar chamadas em estados já fechados

O resultado é um runtime que é difícil de crashar mesmo quando o script faz coisa errada.

E a tipagem?

Você pode usar o luau-analyze (que vem com o Luau oficial) ou o Luau LSP pra checar tipos antes de rodar. O runtime em si não faz type checking (por enquanto...) — ele executa o bytecode.

Na prática, isso significa que você pode iterar rápido sem tipos durante prototipagem e depois ir adicionando anotações conforme o código cresce. Sem breaking change, sem reescrita. É o mesmo modelo que TypeScript fez pro JavaScript, só que embutido na linguagem de verdade, não como um superset separado.

Cross-platform

PlataformaFeatures
Windows x64Full (codegen + vector4)
Linux x64Full (codegen + vector4)
Linux x86 (32-bit)Sem vector4 (TValue size mismatch)
macOS aarch64/x64Full (codegen + vector4)
Android aarch64Sem codegen (estabilidade)

O build.ps1 cuida do target setup automaticamente no Windows.

"Ah, mas o Lute já existe"

Então, sim, e é concorrente direto. Mas por que o Nicy importa? Primeiro, porque é bom ter opção — ecossistema com runtime só não é saudável. Segundo, porque o Nicy é feito em Rust, o que dá garantias de segurança de memória que C++ não tem sem esforço extra. Terceiro, porque o Nicy já nasceu com task scheduler async completo, C-ABI pra embutir em qualquer linguagem, e um modelo de require com cache e aliases que não depende de gerenciador de build.

Os dois projetos são complementares na prática. Se você quer algo integrado com o ecossistema oficial do luau-lang, vai de Lute. Se quer um runtime leve, seguro, embutível e independente, o Nicy já tá pronto. De qualquer forma, Luau ter mais de uma opção de runtime agora é bom pra todo mundo.

Status atual

O projeto tá na versão 1.1.0, com todos os testes passando (142/142). Tem documentação completa no repo, guia de contribuição, code of conduct, security policy.

Por que open source?

Porque eu acredito que Luau merece existir fora do Roblox. Se esse runtime ajudar alguém a construir algo legal — um backend, uma ferramenta, um motor de scripting pra outro projeto — então valeu a pena.

O código tá todo no GitHub sob MPL 2.0. Pode usar, pode contribuir, pode abrir issue. Não precisa pedir permissão.


Se você curte Luau, curte Rust, ou só curte ver linguagem de scripting ganhando vida nova fora do ecossistema original — dá uma olhada. E se quiser contribuir, o CONTRIBUTING.md explica tudo.

E se tambem o Luau foi a linguagem que te ensinou a programar — agora você pode usá-la pra ganhar dinheiro também. Boa sorte e vê se não faz while true do end em produção!

Carregando publicação patrocinada...
2