Uma das perguntas mais frequentes de quem começa a estudar a linguagem Zig é: como criar uma GUI com Zig? A busca por “ziglang gui” cresce mês a mês, refletindo o interesse de desenvolvedores que querem ir além da programação de sistemas pura e construir aplicações desktop com interface gráfica.
A verdade é que o ecossistema de Zig GUI evoluiu bastante nos últimos dois anos. Embora Zig tenha nascido como uma linguagem voltada para programação de sistemas — um substituto moderno para C — a comunidade já oferece caminhos concretos para quem quer desenvolver interfaces gráficas em Zig, desde frameworks nativos até bindings para bibliotecas consagradas como GTK e Dear ImGui.
Neste guia, vamos explorar todas as opções disponíveis para criar uma interface gráfica com Zig, com exemplos práticos de código e uma análise honesta sobre a maturidade de cada abordagem.
O Estado Atual de GUI em Zig
Vamos ser diretos: Zig não possui um framework GUI nativo e maduro no nível de Qt, GTK ou SwiftUI. Isso não é uma limitação exclusiva de Zig — Rust passou anos até que crates como egui e iced se tornassem opções viáveis, e Go ainda depende fortemente de bindings C para GUIs sérias.
O que Zig oferece, porém, são vantagens estruturais que tornam o desenvolvimento de GUI especialmente interessante:
- Interoperabilidade nativa com C: Zig pode importar headers C diretamente com
@cImport, sem precisar de geradores de bindings. Isso significa acesso imediato a GTK, SDL2, Dear ImGui, Vulkan e qualquer outra biblioteca C de GUI. - Cross-compilation embutida: O compilador Zig consegue compilar para Linux, Windows, macOS e WebAssembly a partir de qualquer plataforma, sem configuração adicional.
- Sem runtime pesado: Aplicações GUI em Zig produzem binários pequenos e rápidos, sem garbage collector ou runtime virtual.
- Comptime (computação em tempo de compilação): Permite construir APIs declarativas elegantes, como faz o framework Capy.
O cenário atual se divide em quatro abordagens principais, cada uma com seus trade-offs. Vamos examinar cada uma.
Principais Bibliotecas GUI para Zig
Capy — O Framework GUI Nativo de Zig
Repositório: github.com/capy-ui/capy
Capy é o projeto mais ambicioso do ecossistema de GUI para Zig. Trata-se de um framework de interface gráfica escrito inteiramente em Zig, com uma API declarativa que tira proveito do sistema de comptime da linguagem.
O diferencial do Capy é que ele renderiza usando backends nativos de cada plataforma: GTK no Linux, Win32 no Windows, Cocoa no macOS, e WebAssembly para o navegador. Isso significa que sua aplicação terá a aparência nativa do sistema operacional, sem parecer “estranha” para o usuário.
Principais características:
- API declarativa inspirada em frameworks modernos como SwiftUI e Flutter
- Backend nativo por plataforma (GTK3, Win32, Cocoa, WebAssembly)
- Sistema de layout baseado em constraints
- Gerenciamento de estado reativo
- Suporte a widgets comuns: botões, labels, text inputs, listas e containers
Nível de maturidade: Em desenvolvimento ativo, mas ainda em estágio alpha. A API pode mudar entre versões. Já é possível construir aplicações simples e protótipos.
raylib-zig — GUI para Jogos e Aplicações Gráficas
Repositório: github.com/Not-Nik/raylib-zig
Se o seu caso de uso envolve jogos, visualizações de dados ou aplicações gráficas que não precisam de widgets nativos do sistema operacional, raylib-zig é provavelmente a melhor opção disponível.
raylib é uma biblioteca C extremamente popular para desenvolvimento de jogos — simples, sem dependências externas e com uma API amigável. O projeto raylib-zig fornece bindings idiomáticos para Zig, aproveitando o sistema de tipos da linguagem.
Principais características:
- Renderização 2D e 3D acelerada por hardware
- Suporte a texturas, fontes, áudio e input
- raygui: módulo de GUI imediata (immediate mode) com botões, sliders, checkboxes e mais
- Funciona em Linux, Windows, macOS, Android e Web
- Extremamente fácil de configurar: basta adicionar como dependência no
build.zig
Nível de maturidade: Estável. raylib é um projeto maduro e os bindings Zig são bem mantidos.
Mach Engine — Motor Gráfico Zig-Nativo
Repositório: github.com/hexops/mach
Mach Engine é um projeto mais ambicioso: um motor gráfico completo escrito em Zig, com backends Vulkan, Metal e Direct3D 12. Embora seja voltado primariamente para jogos, o Mach pode ser utilizado para construir interfaces gráficas ricas e customizadas.
Principais características:
- Abstração multiplataforma sobre Vulkan, Metal e DirectX 12
- Pipeline de renderização moderno e eficiente
- Sistema de entidades (ECS) integrado
- Suporte a shaders WGSL
- Windowing e input multiplataforma
Nível de maturidade: Em desenvolvimento ativo. Indicado para quem precisa de renderização de alto desempenho e está disposto a investir mais tempo na implementação da interface.
Zig + C Interop (GTK, SDL2, Dear ImGui)
A quarta abordagem — e muitas vezes a mais pragmática — é usar a interoperabilidade nativa de Zig com C para acessar bibliotecas GUI já estabelecidas. Essa é uma das maiores vantagens de Zig sobre outras linguagens modernas: o @cImport importa headers C diretamente, sem necessidade de FFI manual ou ferramentas de geração de bindings.
As bibliotecas mais usadas por essa via são:
- Dear ImGui: GUI de modo imediato, extremamente popular em ferramentas de desenvolvimento e debug. Existem bindings Zig prontos em github.com/cimgui/dear_bindings.
- SDL2: Biblioteca multimídia que oferece windowing, renderização, áudio e input. Não é um framework GUI completo, mas serve como base sólida.
- GTK4: Para quem quer widgets nativos no Linux. Funciona via
@cImportcom os headers GTK.
Nível de maturidade: As bibliotecas C são maduras e estáveis. A integração via Zig funciona bem, mas exige familiaridade com as APIs C originais.
Exemplo Prático: Hello World com Capy
Vamos começar com o exemplo mais direto: criar uma janela simples com o framework Capy. Primeiro, adicione o Capy como dependência no seu build.zig.zon:
// build.zig.zon
.{
.name = "meu-app-gui",
.version = "0.1.0",
.dependencies = .{
.capy = .{
.url = "https://github.com/capy-ui/capy/archive/refs/heads/master.tar.gz",
},
},
}
Em seguida, configure o build.zig para usar o módulo Capy:
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const capy_dep = b.dependency("capy", .{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "meu-app-gui",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("capy", capy_dep.module("capy"));
b.installArtifact(exe);
}
Agora, o código principal da aplicação em src/main.zig:
const std = @import("std");
const capy = @import("capy");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var app = try capy.App.init(allocator, .{
.title = "Meu App Zig GUI",
.size = .{ .width = 640, .height = 480 },
});
defer app.deinit();
try app.setContent(
capy.Column(.{ .spacing = 10, .padding = .{ .all = 20 } }, .{
capy.Label(.{ .text = "Olá, mundo!" }),
capy.Label(.{ .text = "Esta é uma interface gráfica criada com Zig e Capy." }),
capy.Button(.{
.label = "Clique aqui",
.on_click = struct {
fn callback(_: *anyopaque) void {
std.debug.print("Botão clicado!\n", .{});
}
}.callback,
}),
}),
);
try app.run();
}
Este exemplo cria uma janela com um título, duas labels de texto e um botão funcional. O layout usa Column para organizar os elementos verticalmente — uma API declarativa que lembra SwiftUI ou Jetpack Compose.
Para compilar e executar:
zig build run
Exemplo com raylib-zig
Para quem precisa de algo mais gráfico — como um jogo, uma ferramenta de visualização ou uma aplicação com renderização customizada — raylib-zig é o caminho mais direto. Veja como criar uma janela com um botão usando raygui:
const std = @import("std");
const rl = @import("raylib");
pub fn main() void {
// Inicializa a janela
rl.initWindow(800, 600, "Zig GUI com raylib");
defer rl.closeWindow();
rl.setTargetFPS(60);
var show_message = false;
// Loop principal de renderização
while (!rl.windowShouldClose()) {
// --- Atualização ---
// Verifica se o botão foi clicado (área retangular)
const btn_rect = rl.Rectangle{
.x = 300,
.y = 250,
.width = 200,
.height = 50,
};
if (rl.isMouseButtonPressed(.mouse_button_left)) {
const mouse = rl.getMousePosition();
if (rl.checkCollisionPointRec(mouse, btn_rect)) {
show_message = !show_message;
}
}
// --- Desenho ---
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(rl.Color.ray_white);
// Título
rl.drawText("Zig GUI com raylib", 250, 80, 30, rl.Color.dark_gray);
// Botão
rl.drawRectangleRec(btn_rect, rl.Color.blue);
rl.drawText("Clique aqui", 330, 265, 20, rl.Color.white);
// Mensagem condicional
if (show_message) {
rl.drawText(
"Olá, Zig!",
310,
350,
24,
rl.Color.green,
);
}
}
}
Este exemplo demonstra o paradigma de modo imediato (immediate mode): a cada frame, toda a interface é redesenhada. Isso é diferente do paradigma retido (retained mode) usado por frameworks como Qt e GTK, onde você cria widgets que mantêm estado entre frames.
A vantagem do modo imediato é a simplicidade: não há callbacks complexos, hierarquias de widgets ou gerenciamento de estado implícito. A desvantagem é que, para interfaces muito complexas com muitos widgets, você precisa gerenciar o estado manualmente.
Zig + Dear ImGui via C Interop
Dear ImGui é a biblioteca de GUI de modo imediato mais popular do mundo, usada em engines como Unity e Unreal para ferramentas internas. Graças ao @cImport de Zig, podemos usá-la diretamente:
const std = @import("std");
const c = @cImport({
@cDefine("CIMGUI_DEFINE_ENUMS_AND_STRUCTS", "");
@cInclude("cimgui.h");
});
pub fn renderGui() void {
// Inicia um novo frame do ImGui
c.igNewFrame();
// Cria uma janela ImGui
var open: bool = true;
if (c.igBegin("Painel de Controle", &open, 0)) {
c.igText("Bem-vindo ao Zig + Dear ImGui!");
// Campo de texto
var buffer: [256]u8 = std.mem.zeroes([256]u8);
if (c.igInputText("Nome", &buffer, buffer.len, 0, null, null)) {
// O usuário digitou algo
}
// Botão
if (c.igButton("Enviar", .{ .x = 120, .y = 30 })) {
std.debug.print("Formulário enviado: {s}\n", .{
std.mem.sliceTo(&buffer, 0),
});
}
// Slider
var valor: f32 = 0.5;
_ = c.igSliderFloat("Volume", &valor, 0.0, 1.0, "%.2f", 0);
}
c.igEnd();
// Renderiza
c.igRender();
}
O ponto chave aqui é que o @cImport lê o header C (cimgui.h) em tempo de compilação e disponibiliza todas as funções como se fossem funções Zig nativas. Não há overhead de FFI em runtime — as chamadas são diretas.
Para usar Dear ImGui com Zig, você precisará do cimgui (wrapper C do ImGui, que é C++) e de um backend de renderização como OpenGL ou Vulkan. Projetos como zig-gamedev fornecem integrações prontas.
Quando Usar Cada Abordagem
A escolha da biblioteca depende do tipo de aplicação que você está construindo. Aqui está uma comparação direta:
| Biblioteca | Melhor para | Maturidade | Plataformas |
|---|---|---|---|
| Capy | Apps desktop com widgets nativos | Alpha | Linux, Windows, macOS, Web |
| raylib-zig | Jogos, visualizações, apps gráficos | Estável | Linux, Windows, macOS, Android, Web |
| Mach Engine | Renderização 3D de alto desempenho | Beta | Linux, Windows, macOS |
| Dear ImGui (via C) | Ferramentas de desenvolvimento, painéis de debug | Madura | Todas (depende do backend) |
| GTK4 (via C) | Apps desktop Linux | Madura | Linux (primariamente) |
| SDL2 (via C) | Windowing e input multiplataforma | Madura | Todas |
Recomendações por Caso de Uso
Você quer uma aplicação desktop com aparência nativa: Use Capy se estiver disposto a trabalhar com uma API em evolução, ou GTK4 via @cImport se precisa de estabilidade imediata no Linux.
Você está criando um jogo ou aplicação gráfica: Use raylib-zig para projetos 2D e jogos simples, ou Mach Engine para renderização 3D avançada.
Você precisa de uma ferramenta interna ou painel de debug: Use Dear ImGui via cimgui — é o padrão da indústria para esse tipo de interface.
Você quer atingir o máximo de plataformas, incluindo o browser: Combine Capy (que já suporta WebAssembly) ou compile raylib para Web usando o target WASM de Zig.
O Futuro de GUI em Zig
O ecossistema de GUI em Zig está em um momento de transição. Alguns sinais apontam para um futuro promissor:
- Capy está ganhando tração: O projeto recebe contribuições regulares e a comunidade está crescendo. A API declarativa baseada em
comptimepode se tornar um diferencial real em relação a outras linguagens. - O package manager de Zig amadureceu: Com o sistema de dependências integrado ao
build.zig.zon, instalar e usar bibliotecas GUI ficou significativamente mais fácil. - WebAssembly como alvo: A capacidade de Zig compilar para WASM abre a possibilidade de criar aplicações GUI que rodam tanto no desktop quanto no navegador com o mesmo código.
- Crescimento do zig-gamedev: O repositório zig-gamedev se tornou um hub de bindings de alta qualidade para DirectX 12, Vulkan, Dear ImGui e mais — facilitando o desenvolvimento de interfaces ricas.
Não seria surpreendente ver, nos próximos 1-2 anos, o surgimento de um framework GUI em Zig que atinja a maturidade necessária para uso em produção. A linguagem tem todas as características técnicas para isso: desempenho, interoperabilidade C perfeita e um sistema de metaprogramação poderoso via comptime.
Conclusão
Criar interfaces gráficas com Zig é possível e cada vez mais acessível, mas o caminho que você escolhe depende do seu caso de uso.
Para aplicações desktop com widgets nativos, comece com Capy. Ele é o projeto mais alinhado com a filosofia de Zig e tem o potencial de se tornar o framework GUI padrão da linguagem.
Para jogos e aplicações gráficas, raylib-zig oferece o melhor equilíbrio entre facilidade de uso e capacidade. Você pode ter uma janela com renderização funcionando em menos de 10 linhas de código.
Para ferramentas de desenvolvimento, Dear ImGui via @cImport é a escolha pragmática — uma biblioteca madura e testada em produção por milhares de projetos.
E lembre-se: uma das maiores forças de Zig é que você nunca está preso a uma única opção. A interoperabilidade transparente com C significa que qualquer biblioteca GUI do ecossistema C está a um @cImport de distância.
Leia Também
- Zig e WebAssembly — Compile GUI para o browser
- Interoperabilidade com C — Use bibliotecas C de GUI
- Zig em Produção: Case Studies — Projetos reais usando Zig