← Projetos

Tutorial

Wireframes com PlantUML Salt

Como desenhar protótipos de tela em texto: widgets, grades, grupos, árvores, tabelas, abas, menus, ícones e sprites, com exemplos gerados pelo próprio PlantUML.

Salt e wireframes

Um wireframe é o esqueleto de uma tela: mostra onde ficam os campos, botões e listas, sem se preocupar com cores, fontes ou imagens. Ele serve para discutir a estrutura de uma interface cedo, quando mudar ainda é barato. [4]

Depois do wireframe costumam vir o mockup, uma versão visual com cores e imagens reais, e o protótipo, que já pode ser navegado e clicado. [5] [6]

Quatro etapas lado a lado, cada uma com a mesma tela de login: o rascunho, feito à mão; o wireframe, em preto e branco, destacado com o selo Salt; o mockup, com cores; e o protótipo, com um cursor clicando no botão. Abaixo, duas setas mostram que a fidelidade e o custo de mudar crescem da esquerda para a direita.
Quanto mais cedo, mais barato mudar: o Salt trabalha na etapa do wireframe.

O Salt é a parte do PlantUML que desenha wireframes a partir de texto. Você descreve a tela com símbolos simples, como [OK] para um botão ou [X] para uma caixa marcada, e o PlantUML gera a imagem. Como tudo é texto, o wireframe cabe no controle de versão, ao lado do código e da documentação. [2] [3]

O que é preciso

  • Java e o arquivo plantuml.jar, ou uma extensão de editor, como a do VS Code, ou o servidor on-line do PlantUML. [7] [8]
  • A sintaxe Creole, que o PlantUML usa para formatar textos (como <b> para negrito), e os comandos comuns, como scale. [10] [11]
  • O texto original também lista o Graphviz, mas ele só é usado por diagramas UML como os de classe e de componentes; o Salt funciona sem ele. [9]

Todos os exemplos deste tutorial foram testados no PlantUML 1.2026.8, e as figuras com fundo branco foram geradas por ele. O texto original foi escrito para a versão 1.2020.23; as diferenças encontradas estão indicadas ao longo do texto. [1]

Estrutura de um arquivo

Um wireframe fica entre @startsalt e @endsalt e tem um bloco principal entre chaves. Dentro dele, cada linha é uma linha da tela, e a barra vertical | separa as colunas. [2]

@startsalt
{
  Usuário | "MeuNome   "
  Senha | "****      "
  [Cancelar] | [  OK  ]
}
@endsalt

Linhas que começam com aspa simples (') são comentários e não aparecem no desenho.

Wireframe gerado pelo PlantUML: uma tela com os rótulos Usuário e Senha, cada um ao lado de um campo de texto, e abaixo os botões Cancelar e OK, alinhados em duas colunas.
Resultado real: a grade alinha rótulos, campos e botões em duas colunas.

Comandos comuns do PlantUML também valem aqui; o mais útil é scale, que aumenta a imagem (scale 1.5). A forma antiga, @startuml seguido de uma linha com salt, gera erro nas versões atuais: use sempre @startsalt. [11]

Widgets básicos

Widgets são os controles de uma interface: botões, campos, listas. No Salt, cada um tem uma marcação curta. [12]

Tabela com sete linhas. À esquerda, o código Salt; no meio, o controle desenhado; à direita, o nome: texto simples vira rótulo; [Enviar] vira botão; () e (X) viram botões de opção desmarcado e marcado; [] e [X] viram caixas de seleção; texto entre aspas vira campo de texto; texto entre acentos circunflexos vira lista suspensa; e <&person> insere um ícone de pessoa.
Sete marcações cobrem quase todos os controles de um formulário.
WidgetSintaxeObservação
TextoQualquer textoTexto solto vira rótulo.
Botão[Enviar]Espaços dentro dos colchetes alargam o botão: [ OK ].
Botão de opção() · (X)Desmarcado · marcado.
Caixa de seleção[] · [X]Desmarcada · marcada. [ ], com espaço, também funciona.
Campo de texto"Digite aqui "A largura segue o texto entre aspas, incluindo os espaços.
Lista suspensa^Escolha^Fechada. Com mais itens, ^Item 1^Item 2^Item 3^, ela aparece aberta.

O texto original descreve a lista suspensa como “create a input box representation”, a mesma frase do campo de texto; é só um erro de cópia. A lista aberta não aparece no original, mas é útil para mostrar as opções disponíveis. [1] [2]

@startsalt
{
  Texto simples | [Botão]
  () Opção desmarcada | (X) Opção marcada
  [] Caixa desmarcada | [X] Caixa marcada
  "Digite aqui    " | ^Lista suspensa^
  . | ^Modo inteligente^Original^Ajustar à tela^
  .
  .
  .
}
@endsalt
Wireframe gerado pelo PlantUML em duas colunas: o texto simples e o botão; um botão de opção desmarcado e outro marcado; uma caixa desmarcada e outra marcada; um campo de texto e uma lista suspensa fechada; e, abaixo, uma lista suspensa aberta mostrando Modo inteligente, Original e Ajustar à tela.
Resultado real: cada widget básico, e uma lista suspensa aberta.

Grades e linhas

Toda chave abre uma grade (uma tabela invisível que alinha os elementos), e o caractere logo depois da chave muda o tipo do bloco. A figura resume as dez variações que este tutorial cobre.

Dez cartões, cada um com um código de abertura e uma miniatura: { grade simples; {# tabela com todas as linhas; {! só linhas verticais; {- só linhas horizontais; {+ só a borda externa; {^ com título, caixa de grupo; {S área com barras de rolagem; {T árvore; {/ abas; {* barra de menu.
Um caractere depois da chave muda o tipo do bloco.

Nas grades, três símbolos controlam as linhas desenhadas: [2]

AberturaLinhas desenhadas
{Nenhuma: a grade só alinha.
{#Todas, verticais e horizontais.
{!Só as verticais.
{-Só as horizontais.
{+Só a borda externa.
Wireframe gerado pelo PlantUML com o mesmo formulário de login repetido cinco vezes: com todas as linhas, com linhas verticais, com linhas horizontais, só com a borda e sem linhas.
Resultado real: o mesmo formulário com #, !, -, + e sem símbolo.

Dentro de uma grade, um ponto (.) cria uma célula vazia, útil para deixar margens ou pular colunas. Em tabelas, um asterisco (*) faz a célula da esquerda se estender por cima da atual, como veremos adiante.

Grupos, rolagem e separadores

Caixa de grupo

{^"Título" desenha uma moldura com um título, para reunir controles relacionados.

Barras de rolagem

{S cria uma área com as duas barras de rolagem; {SI, só a vertical (é um I maiúsculo, de uma barra em pé); e {S-, só a horizontal.

{^"Meu grupo"
  Usuário  | "MeuNome   "
  [Cancelar] | [ OK ]
}

{SI
  Mensagem
  .
  .
}
Wireframe gerado pelo PlantUML: à esquerda, uma caixa de grupo com o título Meu grupo, contendo o campo Usuário e os botões Cancelar e OK; à direita, três áreas com o texto Mensagem: a primeira com barras vertical e horizontal, a segunda só com a vertical e a terceira só com a horizontal.
Resultado real: uma caixa de grupo e os três tipos de rolagem.

Separadores

Uma linha contendo só dois caracteres repetidos desenha um separador horizontal:

LinhaSeparador
..pontilhado
==duplo
~~grosso
--simples
Wireframe gerado pelo PlantUML: Texto 1, uma linha pontilhada, o campo Algum campo, uma linha dupla, Observação de uso, uma linha grossa, Outro texto, uma linha simples e o botão OK.
Resultado real: os quatro separadores, na ordem .., ==, ~~ e --.

Árvores e tabelas

Árvore

{T cria uma árvore. Cada linha começa com sinais de mais, e a quantidade de + indica o nível: + é a raiz, ++ um filho, +++ um neto.

Árvore com colunas

Somando | às linhas, a árvore ganha colunas, como uma tabela. A primeira linha pode servir de cabeçalho, e os mesmos símbolos das grades definem as linhas: {T!, {T-, {T+ e {T#.

{T#
  +Região     | População
  + Mundo     | 8,2 bilhões
  ++ América  | 1,0 bilhão
  +++ Brasil  | 212 milhões
  ++ Europa   | 745 milhões
}
Wireframe gerado pelo PlantUML: à esquerda, uma árvore com Mundo na raiz; América, com Brasil e Canadá; Europa, com Itália e Portugal, que tem Lisboa; e África. À direita, uma árvore com colunas Região e População e todas as linhas desenhadas.
Resultado real: uma árvore simples e uma árvore com colunas usando {T#.

No exemplo original, a coluna “Age” tem o valor 30 em todas as linhas; é um dado de preenchimento. Aqui usamos populações aproximadas de 2025. [1]

Tabela avançada

Em uma tabela {#, o ponto deixa uma célula vazia e o asterisco estende a célula da esquerda:

{#
  .       | Coluna 2         | Coluna 3
  Linha 1 | valor 1          | valor 2
  Linha 2 | Uma célula longa | *
}
Tabela gerada pelo PlantUML com três colunas: a primeira célula está vazia, a linha 1 tem valor 1 e valor 2, e na linha 2 o texto Uma célula longa ocupa as duas últimas colunas.
Resultado real: célula vazia no canto e uma célula que ocupa duas colunas.

Blocos dentro de blocos

Qualquer célula pode abrir uma nova chave. Assim se alinham vários controles na mesma célula, como no exemplo do original, que imita a janela de criar uma classe Java:

{
  Name         | "                 "
  Modifiers:   | { (X) public | () default | () private | () protected
                  [] abstract | [] final   | [] static }
  Superclass:  | { "java.lang.Object " | [Browse...] }
}
Wireframe gerado pelo PlantUML: o campo Name; a linha Modifiers com quatro botões de opção, public marcado, default, private e protected, e abaixo três caixas, abstract, final e static; e a linha Superclass com o campo java.lang.Object e o botão Browse.
Resultado real: grades aninhadas nas células Modifiers e Superclass.

Abas e menus

Abas

{/ cria uma barra de abas, separadas por |. Para destacar a aba ativa, use negrito do Creole: <b>Geral. [10]

Para abas verticais, coloque uma aba por linha e termine o bloco com } |: a barra vertical depois da chave põe o conteúdo seguinte ao lado das abas, e não abaixo. O original repete aqui a mesma descrição das abas horizontais, sem mencionar esse detalhe. [1]

{+
  {/ <b>Geral
     Tela cheia
     Comportamento
     Salvar } |
  {
    { Abrir imagem em: | ^Modo inteligente^ }
    [X] Suavizar imagens ampliadas
    [X] Confirmar exclusão
    [] Mostrar imagens ocultas
  }
  [Fechar]
}
Duas janelas geradas pelo PlantUML. À esquerda, abas horizontais Geral, em negrito, Tela cheia, Comportamento e Salvar, acima de uma lista suspensa, três caixas de seleção e o botão Fechar. À direita, o mesmo conteúdo com as abas empilhadas verticalmente à esquerda.
Resultado real: abas horizontais e verticais.

Menus

{* cria uma barra de menus. Uma segunda linha mostra um menu aberto: ela começa com o nome do item e lista as opções, e um hífen isolado (-) vira um separador.

{* Arquivo | Editar | Código | Refatorar
   Arquivo | Novo | Abrir arquivo | - | Fechar | Fechar todos }
Janela gerada pelo PlantUML com a barra de menus Arquivo, Editar, Código e Refatorar; o menu Arquivo está aberto, mostrando Novo, Abrir arquivo, um separador, Fechar e Fechar todos, por cima do conteúdo da janela.
Resultado real: o menu Arquivo aberto se sobrepõe ao conteúdo, como numa tela de verdade.

Ícones e pseudo-sprites

Open Iconic

O PlantUML inclui o conjunto de ícones livres Open Iconic. Para usar um, escreva <&nome-do-ícone> em qualquer texto, como <&person> ou <&key>. Para ver a lista completa, gere um diagrama com o comando listopeniconic. [13] [14]

@startuml
listopeniconic
@enduml

Pseudo-sprites

Um pseudo-sprite é um pequeno desenho feito de texto: entre <<nome e >>, cada X vira um pixel preto e cada ponto um pixel vazio. Depois, basta escrever <<nome>> para repetir o desenho. [2]

À esquerda, o código de um pseudo-sprite chamado pasta: dez linhas de pontos e X entre << e >>. No meio, a mesma grade ampliada, com cada X como um pixel preto, formando o desenho de uma pasta. À direita, uma tela de exemplo com quatro pastas, Documentos, Imagens, Músicas e Vídeos, todas usando o mesmo sprite.
Um pseudo-sprite é definido uma vez e reutilizado pelo nome.

Dois detalhes testados: só o X é desenhado (qualquer outro caractere fica em branco), e <<nome>> precisa estar sozinho na célula; no meio de um texto, ele aparece como «nome». Para pôr um rótulo ao lado, use uma coluna: <<pasta>> | Documentos.

Wireframe gerado pelo PlantUML: à esquerda, um formulário de login com ícone de pessoa ao lado de Usuário, ícone de chave ao lado de Senha, e ícones nos botões Cancelar e OK; à direita, a definição do sprite pasta, desenhada uma vez, e a frase reutilizando o sprite, com duas linhas, pasta 1 e pasta 2, cada uma com o ícone da pasta.
Resultado real: ícones Open Iconic no formulário e um pseudo-sprite reutilizado.

De imagem para sprite

O original propõe um roteiro para transformar uma imagem em pseudo-sprite: [1]

  1. Converter a imagem para preto e branco e reduzir a largura à metade (os caracteres são mais altos que largos).
  2. Enviá-la a um conversor de ASCII art, como o Convert Images to ASCII Art, com largura de até 200 caracteres. O endereço no original tem um erro de digitação (“onvert”); o correto está nas referências. [16] [17]
  3. No texto baixado, trocar todo caractere que não seja espaço por X e todo espaço por ponto.
  4. Colar o resultado entre <<nome e >>.

Para diagramas UML, o PlantUML também tem sprites de verdade, em tons de cinza, definidos com sprite $nome e gerados a partir de imagens com java -jar plantuml.jar -encodesprite. [15]

Salt dentro de outros diagramas

Um wireframe pode aparecer dentro de outro diagrama, em uma nota, uma legenda ou o rótulo de um elemento. Basta colocá-lo entre {{salt e }}. [2]

@startuml
class Login
note right of Login
{{salt
{
  Usuário | "MeuNome   "
  Senha | "****      "
  [Cancelar] | [  OK  ]
}
}}
end note
@enduml
Diagrama de classes gerado pelo PlantUML com a classe Login e, à direita, uma nota amarela que contém o wireframe do formulário de login, com os campos Usuário e Senha e os botões Cancelar e OK.
Resultado real: o formulário dentro de uma nota de um diagrama de classes.

Exemplo completo

O exemplo final do original junta quase tudo numa só tela: menu, abas, campos, lista suspensa, caixa de grupo, botões de opção, lista com rolagem, tabela, árvore e botões com ícones. Os rótulos misturam inglês e português, como no original. [1]

Tela completa gerada pelo PlantUML: no topo, uma linha com os rótulos area1 a area7; abaixo, a barra de menus File, Edit, Source e ?, com o item About aberto; as abas General, Fullscreen, Behavior e Saving; os campos Login e Password; a lista Smart Mode e uma caixa Options com três caixas de seleção; os botões de opção Masculino e Feminino; uma lista com rolagem com Acre, Amapa e Amazonas; uma caixa Privacy com três opções; uma tabela de cinco colunas; uma árvore com World, Europe e Africa; e os botões OK e Cancel.
O exemplo do original renderizado no PlantUML 1.2026.8.
Ver o código completo
@startsalt
'skinparam BackgroundColor lightblue
{+
    |area1|area2|area3|area4|area5|area6|area7
    |.|{* File | Edit | Source | ?
    '  File | New | Open File | - | Close | Close All | - | Exit
      ? | About}|*|*|*|*
    |.
    |.|{/ <b>General | Fullscreen | Behavior | Saving }|*|*|*|*
    |.
    |.|Login    |"MyName          "|.
    |.|Password |"****            "|.
    |.
    |.|Open image in|{ ^Smart Mode^ }|{^Options
                                        [X] Smooth images when zoomed
                                        [X] Confirm image deletion
                                        [ ] Show hidden images
                                       }
    |.|Sexo|{(X) Masculino
             () Feminino}
    |.
    |.|Estado|{SI 
                Acre
                Amapa
                Amazonas
              }|{^"Privacy" | (X) public | () default | () private} |*|*
    |.
    |.|{#
        .     | Column 2  | Column 3 | Column 4 | Column 5
        Row 1 | value 1   | value 2  | value 3  | value 4
        Row 2 | long cell | *        | *        | *
       }|*|*|{+{T
              + World
              ++ Europe
              +++ Italy
              +++ Germany
              ++++ Berlin
              ++ Africa
             }}|*
    |.
    |.|.|.|.|[  OK<&account-login>   ]|[Cancel<&circle-x>]
    |.
}
@endsalt

O truque de layout está na primeira linha: |area1|area2|…|area7 cria sete colunas com rótulos, e as linhas seguintes começam com |. para deixar a primeira coluna vazia, como uma margem. Os asteriscos (|*|*) fazem o menu, as abas e a tabela ocuparem várias colunas. Numa tela real, a linha de rótulos seria apagada depois de ajustar o layout.

Referência rápida

SintaxeResultado
@startsalt … @endsaltInício e fim do wireframe.
[OK] · () · (X) · [] · [X]Botão, opção, opção marcada, caixa, caixa marcada.
"texto " · ^lista^Campo de texto · lista suspensa.
| · . · *Nova coluna · célula vazia · estende a célula da esquerda.
{ {# {! {- {+Grade sem linhas, com todas, verticais, horizontais, só a borda.
{^"título"Caixa de grupo.
{S · {SI · {S-Rolagem nas duas direções · vertical · horizontal.
.. == ~~ --Separadores pontilhado, duplo, grosso e simples.
{T com +, ++…Árvore; com |, árvore com colunas.
{/ a | b }Abas; uma por linha e } | para abas verticais.
{* a | b }Menu; a 2ª linha abre um item, e - é separador.
<&ícone>Ícone Open Iconic.
<<nome … >> · <<nome>>Define · reutiliza um pseudo-sprite.
{{salt … }}Salt dentro de outro diagrama.

Revisão rápida

Tente responder antes de abrir cada pergunta.

1. Qual a diferença entre um wireframe e um mockup?

O wireframe mostra só a estrutura e o conteúdo da tela, sem cores; o mockup já tem a aparência final, com cores, fontes e imagens.

2. Como desenhar uma caixa de seleção marcada e outra desmarcada?

[X] Marcada e [] Desmarcada.

3. O que define a largura de um campo de texto?

O texto entre aspas, incluindo os espaços: "Nome " gera um campo mais largo que "Nome".

4. Qual abertura desenha só a borda externa de uma grade?

{+.

5. Numa tabela {#, para que servem o ponto e o asterisco?

O ponto deixa a célula vazia; o asterisco faz a célula da esquerda se estender sobre a atual.

6. Como fazer abas verticais?

Com {/, uma aba por linha, fechando com } | para que o conteúdo fique ao lado.

7. Por que <<pasta>> Documentos não mostra o ícone?

Porque o pseudo-sprite precisa estar sozinho na célula. Use <<pasta>> | Documentos.

8. Como colocar um wireframe dentro de uma nota de um diagrama de classes?

Entre {{salt e }}, com {{salt na mesma linha.

↑ Voltar ao topo

Referências

  1. Giovani Perotto Mesquita, “Building Mockups with PlantUML”, GitHub, texto original deste tutorial, github.com/GiovaniPM/MyCourses/blob/master/PlantUML/Course Salt.md.
  2. PlantUML, “Salt (Wireframe)”, acesso em 25/09/2026, plantuml.com/salt.
  3. PlantUML, site oficial, acesso em 25/09/2026, plantuml.com.
  4. Wikipedia (em inglês), “Website wireframe”, acesso em 25/09/2026, en.wikipedia.org/wiki/Website_wireframe.
  5. Wikipedia (em inglês), “Mockup”, acesso em 25/09/2026, en.wikipedia.org/wiki/Mockup.
  6. Wikipedia (em inglês), “Software prototyping”, acesso em 25/09/2026, en.wikipedia.org/wiki/Software_prototyping.
  7. PlantUML, “Download”, acesso em 25/09/2026, plantuml.com/download.
  8. Visual Studio Marketplace, “PlantUML” (jebbs), acesso em 25/09/2026, marketplace.visualstudio.com/items?itemName=jebbs.plantuml.
  9. Graphviz, site oficial, acesso em 25/09/2026, graphviz.org.
  10. PlantUML, “Creole”, acesso em 25/09/2026, plantuml.com/creole.
  11. PlantUML, “Common commands”, acesso em 25/09/2026, plantuml.com/commons.
  12. Wikipedia (em inglês), “Graphical widget”, acesso em 25/09/2026, en.wikipedia.org/wiki/Graphical_widget.
  13. PlantUML, “Open Iconic”, acesso em 25/09/2026, plantuml.com/openiconic.
  14. Iconic, “Open Iconic”, repositório no GitHub, acesso em 25/09/2026, github.com/iconic/open-iconic.
  15. PlantUML, “Sprite”, acesso em 25/09/2026, plantuml.com/sprite.
  16. ManyTools, “Convert Images to ASCII Art”, acesso em 25/09/2026, manytools.org/hacker-tools/convert-images-to-ascii-art.
  17. Wikipedia (em inglês), “ASCII art”, acesso em 25/09/2026, en.wikipedia.org/wiki/ASCII_art.
↑ Voltar ao topo