Como animar fontes variáveis com Python e Drawbot

Um dos usos mais comuns das fontes variáveis (ou variable fonts, em inglês) é para fazer animações. Você já deve ter visto esse tipo de animação por aí: fontes ganham e perdem peso, ficam mais largas ou mais estreitas, ou até mesmo variam entre uma fonte normal e uma versão stencil, sempre de forma extremamente suave.

Animação demonstrando o eixo wght de uma fonte variável.
Uma fonte variável possui um ou mais eixos de variação que podem ser acessados pelo usuário. Neste exemplo, o eixo wght da Malva Variable.

Você não precisa comprar softwares caros para fazer isso. Na realidade, boa parte dessas animações podem ser produzidas utilizando o Drawbot, um software grátis para o MacOS. Embora o Drawbot tenha sido desenvolvido como uma ferramenta para aprender a programar em Python, sua capacidade de gerar arquivos PDF, SVG, PNG, MP4, GIF e outros formatos acabou o tornando uma excelente ferramenta para automatizar tarefas de design gráfico em geral. É possível até mesmo diagramar um livro inteiro nele com saída para PDF em CMYK!

Neste post eu compartilho o código que usei para criar a animação da Malva Variable. Embora meu objetivo aqui não seja dar uma aula de Python, tomei o cuidado de anotar o que cada uma das linhas faz. Desta forma você poderá ler o código e ter uma boa noção do que está acontecendo em cada momento.

Para recriar a animação, copie e cole (ou melhor ainda, digite) o código a seguir no Drawbot e salve o arquivo com a extensão .py. Caso queira, você pode personalizar as variáveis do início.

# -------------------------------
# EDITE ESTAS VARIÁVEIS
# -------------------------------
# Tamanho da página
w, h = 980, 490
# Texto a ser desenhado
text_string = 'Animating in Drawbot!'
# Número de linhas
lines = 5
# Nome da fonte
font_name = 'MalvaVariable-Italic'
# As cores do fundo e do texto
bg_r, bg_g, bg_b = 25, 29, 59
fg_r, fg_g, fg_b = 235, 0, 89
# Número de frames e a duração total da animação
total_frames = 30
total_duration = 2 # em segundos
# -------------------------------

# Conta o número de caracteres
chars = len(text_string)
# Calcula o tamanho da fonte
font_size = w / 12
# Obtém e armazena os valores mínimo e máximo do eixo wght (peso)
min_var = listFontVariations(font_name)['wght']['minValue']
max_var = listFontVariations(font_name)['wght']['maxValue']
# Calcula a duração de cada frame
frame_duration = total_duration / total_frames

# Para cada frame...
for frame in range(total_frames):

    # Cria uma nova página e define sua duração
    newPage(w, h)
    frameDuration(frame_duration)

    # Desenha o retângulo com a cor de fundo
    fill(bg_r/255, bg_g/255, bg_b/255)
    rect(0,0,w,h)
    
    # Calcula a posição vertical da primeira linha
    y = (h - (lines * font_size)) / 2
    y = y + w/50

    # Inicia cada frame com um valor wght diferente
    frame_start = (2 * pi) * frame / total_frames

    # Para cada linha...
    for line in range(lines):
        
        # Inicia cada LINHA com um valor wght diferente
        step_start = frame_start - (pi * (line / (lines - 1)))
        
        # Cria um objeto de texto vazio e define suas propriedades
        txt = FormattedString()
        txt.fill(fg_r/255, fg_g/255, fg_b/255)
        txt.font(font_name)
        txt.fontSize(font_size)
        txt.openTypeFeatures(ss01=True)

        # Para cada caractere...
        for char_index in range(chars):
            
            # Calcula o valor wght
            inst_step = pi * (char_index / (chars -1))
            curr_step = (cos(step_start - inst_step) + 1) / 2
            wght_value = min_var + curr_step * (max_var - min_var)
            
            # Adiciona o caractere ao objeto de texto
            txt.append(
                text_string[char_index], 
                fontVariations=dict(wght=wght_value)
                )
        
        # Depois que todos os caracteres foram adicionados 
        # ao objeto de texto, obtém suas dimensões
        text_width, text_height = textSize(txt)

        # Calcula a coordenada horizontal necessária
        # para centralizar esta linha na página
        x = (w - text_width) / 2
        
        # Desenha a linha na página
        text(txt, (x, y))

        # Move a coordenada y para a próxima linha
        y = y + font_size
    
# Salva a animação como gif
saveImage("Animating in Drawbot.gif")

Depois de copiar o código para o Drawbot, execute o script clicando em Run ou através do atalho ⌘R. Após alguns segundos, você verá uma série de páginas no lado esquerdo da janela e um arquivo GIF na mesma pasta que você salvou o script.

O resultado da animação utilizando fontes variáveis.
O resultado da animação utilizando fontes variáveis.

Utilizando outras fontes variáveis

Caso você não possua a Malva Variable em seu sistema, você pode utilizar outra fonte variável em seu lugar. Para descobrir quais fontes variáveis estão instaladas em seu sistema, digite o código abaixo em um novo arquivo do Drawbot e execute. Este pequeno script percorre todas as fontes instaladas verificando cada uma delas pela presença de propriedades variáveis, ou seja, os eixos de variação.

# Para cada fonte instalada no sistema...
for f in installedFonts():
    # Se a fonte atual possui eixos de variação...
    if listFontVariations(f):
        # Escreve o nome da fonte atual no painel de saída.
        print(f)

Ao executar o código acima, você verá uma lista de todas as fontes variáveis instaladas em seu sistema no painel de saída. Use esta informação para escolher uma fonte para usar no script principal.