Canvas
Desenhe caixas de texto, painéis, barras de progresso, imagens, círculos no chão e rotas com seta sobre a tela do jogo. O runtime desenha tudo a cada frame, sem alterar o estado do jogo, então é seguro em partidas multijogador; funciona por Python, HTTP ou escrevendo direto na memória compartilhada.
Programas externos podem desenhar caixas de texto, painéis, barras de progresso, imagens, círculos no chão e rotas no chão (com seta) sobre a tela do jogo, e o runtime desenha tudo sozinho a cada frame. Serve para o seu próprio HUD, linhas de apoio, avisos, anotações didáticas e painéis de informação para lives.
Canvas ou funções visuais do JASS: qual usar
| Canvas (esta página) | Funções visuais do JASS | |
|---|---|---|
| Quem desenha | O próprio runtime | O próprio jogo (texto flutuante, efeitos, painéis, diálogo com retrato…) |
| Partidas multijogador | Seguro: só desenha na tela desta máquina, sem criar objetos nem alterar o estado do jogo | Só partidas solo |
| Estilo | Livre: fontes com suporte a chinês, cantos arredondados, semitransparência, bordas, qualquer cor, imagens locais | Estilo nativo do jogo |
| Acompanhar coisas | Segue unidades, coordenadas do mundo, posições da tela; círculos no chão acompanham o relevo | Depende da função |
| Custo | Medido: 0.2 ~ 0.35 ms por frame (9 elementos) | Cerca de 13 ms por chamada |
Dá para usar os dois juntos: efeitos com cara nativa pelo JASS; painéis, linhas de apoio e avisos personalizados pelo canvas.
Python
c = g.canvas # no primeiro uso, o runtime instala o hook de desenho (cerca de 0.1 s)
c.text("title", "Olá, este é o canvas", screen=(40, 110), color=(255, 220, 80),
bg=(0, 0, 0, 170), border="#C49C40", size=22, bold=True)
c.panel("status", "Companheiro · Luz", ["Humor: feliz", "Abates: 12"], screen=(16, 330))
c.bar("hp", 0.62, unit=hero, lift=260, width=100, height=12, color=(80, 220, 80), text="62%") # segue a unidade
c.text("tag", "O chefe vai soltar o golpe especial!", unit=boss, lift=320, color=(255, 80, 80), size=22, bold=True)
c.circle("danger", (x, y), 300, color=(255, 60, 60), fill=(255, 60, 60, 60), width=3) # área de perigo no chão
c.circle("aura", hero, 450, color=(80, 200, 255, 220)) # círculo que segue a unidade
c.path("route", [(x1, y1), (x2, y2), (x3, y3)], color=(255, 220, 0), width=5, arrow=True)
c.image("icon", "icon.png", screen=(40, 170), width=64, height=64)
c.remove("danger"); c.hide("tag"); c.clear() # clear só limpa o que você desenhou
c.expire("tag", 5) # some sozinho depois de 5 s
with c.batch(): ... # muda vários itens de uma vez, escrevendo na memória compartilhada uma vez só
c.stats() # drawnFrames subindo = está desenhando de verdade
Cada elemento é identificado por uma key: desenhar de novo com a mesma key atualiza o elemento.
Clicável: acrescente clickable=True a caixas de texto e painéis (a cor ao passar o mouse é definida por hover=). Quando o jogador clica, chega um ui.click no fluxo de eventos, com ev.key igual a essa key, e o jogo não recebe esse clique. Botões, cartões de escolha, atalhos de teclado e cliques no chão prontos estão em Interface e entrada.
Posição (uma por elemento):
screen=(x, y): pixels da tela; números negativos contam a partir da direita / de baixo;center=Truealinha pelo centro;frac=(0.5, 0.1): fração da tela;world=(x, y): coordenadas do mundo;unit=unidade: segue a unidade. Textos e barras no mundo e em unidades ficam com o ponto médio da borda inferior sobre aquele ponto;liftos levanta.
Por padrão, elementos no mundo e em unidades evitam o painel de comando embaixo e o relógio de dia e noite no topo (over_ui=True desenha por cima deles). Cores podem ser (r, g, b), (r, g, b, a), "#RRGGBB" ou "#RRGGBBAA".
| Método | O que desenha | Parâmetros comuns |
|---|---|---|
text(key, texto, ...) | Caixa de texto; várias linhas com \n | color, bg fundo (sem ele, transparente), border, size, bold, shadow, width (quebra a linha nessa largura), radius cantos arredondados |
panel(key, título, [linhas...], ...) | Painel (fundo escuro semitransparente, borda dourada) | Os mesmos de text |
bar(key, 0..1, ...) | Barra de progresso: vida, recarga, conjuração | width, height, color, bg, border, text |
image(key, caminho, ...) | Imagem local (png / jpg / bmp / gif) | width, height (sem eles, tamanho original) |
circle(key, unidade ou ponto, raio, ...) | Círculo no chão, acompanhando o terreno | color cor da linha, fill preenchimento (com transparência), width espessura da linha |
path(key, [pontos...], ...) | Linha poligonal no chão | color, width, arrow seta no fim; os pontos podem ser coordenadas ou unidades |
HTTP (qualquer linguagem)
Backend do Farsight (só escuta na máquina local):
POST /api/instances/20/canvas
{"set": [
{"key": "banner", "kind": "text", "text": "Canvas via HTTP", "frac": [0.5, 0.12], "center": true,
"color": "#FFDC50", "bg": [0, 0, 0, 180]},
{"key": "hp", "kind": "bar", "value": 0.8, "unit": 596125988, "lift": 260, "text": "80%"},
{"key": "zone", "kind": "circle", "center": 596125988, "radius": 600, "color": [255, 200, 0], "width": 4},
{"key": "route", "kind": "path", "points": [[-4587, -9092], [-5387, -8792]], "color": "#50C8FF"}
],
"remove": ["old"], "clear": false}
GET /api/instances/20/canvas elementos desenhados agora + quantos frames já foram desenhados
kind é o nome do método em Python, e os nomes dos parâmetros também são os mesmos; para unidades, use o endereço addr do snapshot.
Escrevendo direto na memória compartilhada
Também dá para dispensar o Python e o Farsight: envie uma vez o comando semântico canvas_enable (opcode W3P 73), e o runtime cria o bloco de memória compartilhada Local\War3Canvas_<pid>: cabeçalho de 64 bytes + 256 entradas × 112 bytes + pool de 64 KB para textos / pontos. A escrita segue o seqlock (o número de sequência fica ímpar → as entradas e o pool são escritos → o número fica par); o runtime lê uma vez por frame, reaproveita o frame anterior se pegar uma escrita pela metade e devolve o número de frames desenhados, o número de elementos e o contador de falhas. A implementação de referência em Python é sdk/python/w3canvas.py, e as estruturas estão definidas no header do protocolo; veja Protocolo W3P.
Vários programas desenhando ao mesmo tempo
Mods, Farsight, MCP e gateway podem desenhar na mesma partida ao mesmo tempo, mas só existe um canvas. A regra é: cada programa só mexe nos próprios elementos.
- Antes de escrever, pega-se um lock nomeado, leem-se os elementos existentes, mantêm-se os dos outros, trocam-se os próprios e grava-se tudo de volta;
- Cada elemento registra quem o desenhou (PID + número sequencial dentro do processo); quando o programa que o desenhou termina, ele é limpo na próxima vez que alguém escrever, e os botões dele deixam de interceptar cliques;
- Os números dos elementos vêm de um contador compartilhado, então não colidem.
O SDK em Python já faz assim, e clear() também só limpa o que é seu. Se você escrever direto na memória compartilhada, siga essas regras; do contrário, vai apagar o que os outros desenharam. Os detalhes do layout estão em Protocolo W3P.
Medições e cuidados
- Medido em 2026-09-25 (1920×1080, velocidade 2×): 9 elementos, 0.27 ~ 0.34 ms por frame, cerca de 63 frames / s, 0 falhas; escrever 9 itens leva 6 ms; com o herói andando, os círculos, textos e barras de vida que seguem unidades acompanham sem atraso. A textura só é redesenhada quando o conteúdo muda; mudar só a posição não redesenha.
- O canvas é desenhado depois da interface do jogo e antes do cursor do mouse: fica por cima das barras de vida, das unidades e da interface do próprio jogo, e o cursor fica por cima dele. Ele evita o painel de comando embaixo e o relógio de dia e noite no topo, mas não evita os painéis do próprio mapa (placar e contagem regressiva no canto superior direito) — não coloque os seus painéis no canto superior direito.
- Fora de uma partida (menu principal, tela de resultados), elementos posicionados em coordenadas do mundo ou em unidades não são desenhados; os que estão numa posição da tela continuam aparecendo.
- O círculo no chão projeta cada um dos 64 pontos da circunferência no terreno, então, quando o terreno tem altos e baixos, a forma acompanha o relevo — e isso está certo: ele é desenhado sobre o chão de verdade.
- Na primeira ativação, é preciso instalar o hook e pré-aquecer as fontes, o que leva cerca de 1 segundo; nesse intervalo, os elementos de texto ainda não aparecem, mas círculos e linhas sim.
- Se ocorrer uma falha durante o desenho, nada mais é desenhado nesta sessão (a mesma proteção dos balões sobre a cabeça), e
faultsemstats()passa a 1. - Textos, caminhos de imagem e pontos somam no máximo 64 KB, com até 256 elementos; o caminho da imagem precisa ser um caminho local que o processo do jogo consiga ler.
O painel de status do companheiro de IA é desenhado com o canvas: barra de vida, o que ele está fazendo, humor, abates e número de curas.