BASTIDORES · CÓDIGO E EQUAÇÕES

O que tem nessa página.

Quase tudo que se move aqui é meteorologia rodando ao vivo no seu navegador. Nada é vídeo, nada é GIF: são equações resolvidas a cada quadro.

Duas peças fazem o trabalho pesado. O fundo desta página é um campo de pressão sintético do qual se extrai o vento geostrófico, isóbara por isóbara. E o box de 10 km na página inicial é um raymarch volumétrico de nuvens escrito em WebGL, sem nenhuma biblioteca 3D. Abaixo, o que cada um faz e com que conta.

Fundo: pressão e vento geostrófico simulados · Hemisfério Sul.Começar pela pressão

O fundo da página

Pressão, isóbaras e vento geostrófico.

As linhas finas atrás do texto são isóbaras de um campo de pressão inventado, mas tratado como campo real: as setas que passam entre elas são o vento geostrófico calculado a partir do próprio gradiente desse campo.

O campo de pressão

Não há dado observado aqui. O campo é procedural: três oitavas de ruído de valor com interpolação suave, somadas a uma bacia quadrática que garante um centro de baixa e a uma depressão gaussiana que segue o ponteiro do mouse. O conjunto deriva lentamente, com período de 30 s.

p(x,y,t)=ΔP·[0,65N(k)+0,24N(2k)+0,11N(4k)+0,12rbacia20,22s(t)ed22σ2]

O campo, uma vez resolvido: claro é alta pressão, escuro é baixa.

ΔP = 4000 Pa por unidade de campo · 1 unidade de campo = 1000 km · σ = 180 px (raio do ponteiro) · s(t) é a força do ponteiro, relaxada exponencialmente ao entrar e sair.

O ruído de valor usa uma grade fixa de 64 × 64 valores pseudoaleatórios e interpola com a mesma smoothstep de sempre, o que dá continuidade de primeira derivada — condição necessária para o gradiente, e portanto o vento, não sair picotado.

S(t)=t2(32t)

A interpolação suave contra a linear, que deixaria degrau na grade.

Interpolação bilinear entre os quatro vértices da célula, com S aplicado em cada eixo.

As isóbaras

As linhas saem de marching squares sobre a grade amostrada do campo: até 32 níveis igualmente espaçados, desenhados numa única passada de path do canvas. Cada célula testa quais dos quatro vértices estão acima do nível e emite os segmentos correspondentes.

n=0,10+0,035n,n=031

xcorte=xa+papbpa

As isolinhas do mesmo campo, extraídas célula por célula: 32 níveis, ℓ = 0,10 + 0,035 n.

Interpolação linear na aresta entre os vértices a e b. Os dois casos ambíguos de sela (5 e 10) são resolvidos pela média dos quatro vértices da célula, e não por escolha fixa: é o que impede as linhas de se cruzarem.

Só os níveis que efetivamente cruzam a célula são percorridos — o laço vai do menor ao maior valor dos seus quatro vértices —, o que corta a maior parte do trabalho em regiões planas do campo.

O vento geostrófico

O vento geostrófico é o equilíbrio exato entre a força do gradiente de pressão e a força de Coriolis. É a aproximação de primeira ordem do escoamento em larga escala fora da camada limite, e é por isso que, num mapa sinótico, o vento sopra praticamente paralelo às isóbaras em vez de atravessá-las da alta para a baixa.

f×Vg=1ρhp

ug=1ρfpyvg=+1ρfpx

O gradiente virado em vento: cada seta é a solução da equação naquele ponto, paralela à isóbara e horária em torno da baixa.

ρ = 1,225 kg·m⁻³ (densidade do ar ao nível do mar, atmosfera padrão). ug é a componente zonal, para leste; vg a meridional, para norte.

O parâmetro de Coriolis depende só da latitude escolhida para a cena — 30° S, o paralelo que corta o Sul do Brasil:

f=2Ωsenφ

f contra a latitude: nulo no equador, negativo em todo o Hemisfério Sul.

Ω = 7,292115 × 10⁻⁵ rad·s⁻¹ (velocidade angular da Terra) · φ = −30° · f ≈ −7,29 × 10⁻⁵ s⁻¹.

Como f < 0 no Hemisfério Sul, a circulação em torno de uma baixa sai no sentido horário — o contrário do que se vê na maior parte das animações prontas na internet, quase todas feitas para o Hemisfério Norte. Perto do equador o equilíbrio geostrófico simplesmente não vale: f → 0 e a velocidade diverge. O código verifica isso e devolve “sem vetor” em vez de inventar uma direção.

pxΔP·[p̂(x+h)p̂(xh)]2hΔs

Um corte do campo e a secante entre x−h e x+h, que é a derivada estimada.

Diferenças centradas, precisão de segunda ordem, com h = 2 px e Δs = 10⁶ / escala do campo, em metros por pixel. O mesmo campo escalar alimenta as isóbaras e o gradiente, então linha e seta nunca discordam.

As setas que andam

As setas não são um campo estático: são parcelas lagrangianas, advectadas pelo vento amostrado na posição de cada uma, com integração de Euler explícita a cada quadro. Cada parcela vive 7 s, nasce em fase aleatória — para que os renascimentos não pulsem juntos — e reaparece se sair da tela.

xn+1=xn+Vg(xn,t)·G·Δt

Onde cada parcela passou: 34 passos de Euler de rastro, e a seta é o estado atual.

G = 1,2 px·s⁻¹ por m·s⁻¹, ganho só de exibição: a 5000 m por pixel, o deslocamento real seria invisível. O comprimento desenhado da seta é proporcional a |Vg| e limitado por um teto visual, mas o vetor físico mantém a magnitude que a equação deu.

Como o canvas tem o eixo y apontando para baixo e o norte aponta para cima, o vetor de tela é (ug, −vg). O campo procedural está isolado numa única função: trocá-la por pressão ao nível do mar de um modelo numérico é o passo que transforma essa animação em um mapa de verdade.

O box de nuvens

Um cubo de 10 km, renderizado de dentro para fora.

Na página inicial há um cubo de 10 × 10 × 10 km com nuvens que nascem, crescem e se desfazem sobre um recorte de imagem de satélite. É WebGL2 puro, um triângulo de tela cheia e cinco shaders: sem three.js, sem modelo, sem textura de nuvem pronta.

1. O volume de ruído, assado uma vez

Antes do primeiro quadro, o programa gera uma textura 3D de 96³ pixels, camada por camada, e nunca mais volta a calculá-la. Ela guarda a forma-base das nuvens no canal vermelho e três frequências de detalhe nos demais.

W(p,f)=0,625w(f)+0,250w(2f)+0,125w(4f)

P(p,f)=0,55n(f)+0,28n(2f)+0,17n(4f)

R=remap(P,W1,1,0,1)

As três imagens da conta: Perlin, Worley e a combinação que vira nuvem.

w é ruído de Worley (distância ao ponto de célula mais próximo, invertida) e n é ruído de Perlin em grade periódica. A combinação Perlin–Worley é o que dá o aspecto de bolha coalescente em vez de mancha. remap(v,a,b,c,d) = c + (va)(dc)/(ba).

2. Onde há nuvem, e de que tipo

Duas amostras de baixa frequência formam um “mapa de tempo” em duas dimensões: cobertura e tipo. A cobertura corta o campo por limiar; o tipo interpola entre um gradiente vertical achatado, de estrato, e um alto e cheio, de cúmulo. A nuvem só existe entre 1200 m e 4600 m.

h=y120046001200,0h1

G(h,tipo)=mix(estrato(h),cúmulo(h),tipo)

σ(p)=remap(R·G,1cobertura,1,0,1)·perfil(h)·D

O perfil vertical: estrato fica embaixo, cúmulo sobe e afina no topo.

σ é o coeficiente de extinção, em unidades por metro. Uma segunda amostra de alta frequência erode as bordas, com o sinal invertido perto da base e mantido no topo — é o que dá pé chapado e topo encaracolado.

3. Transporte radiativo

Cada pixel lança um raio e integra a equação de transporte radiativo ao longo dele, com 88 passos. A transmitância segue Beer–Lambert; a integral de luz é resolvida analiticamente dentro de cada passo, e não por retângulo, o que mantém a energia conservada mesmo com passo grande.

T(t)=exp(0tσ(s)ds)

L=T(t)σ(t)S(t)dt

Tpasso=eσΔtLL+T(SSTpasso)TT·Tpasso

A transmitância caindo, e a luz que se acumula no que ela deixou passar.

Sem emissão: a nuvem não brilha, só espalha. O laço para quando T < 0,006 — abaixo disso, nada do que está atrás muda o pixel.

A direção do espalhamento vem de uma mistura de duas funções de fase de Henyey–Greenstein: um lóbulo dianteiro forte, responsável pelo brilho quando se olha a nuvem contra o sol, e um lóbulo traseiro fraco, responsável pelo cinza do lado sombreado.

HG(θ,g)=1g24π(1+g22gcosθ)3/2

p(θ)=0,72·HG(θ,0,82)+0,28·HG(θ,0,22)

A fase em coordenada polar: o lóbulo grande aponta para longe do sol.

θ é o ângulo entre o raio de visada e a direção do sol.

4. Múltiplo espalhamento, de mentirinha

Resolver o espalhamento múltiplo de verdade custaria ordens de grandeza mais. No lugar dele entra a aproximação por oitavas: a mesma luz direta é somada três vezes, cada uma com extinção, peso e anisotropia reduzidos. É o truque que faz o interior da nuvem ficar leitoso em vez de preto.

E=o=02bo·e0,72aoτsol·p(cocosθ)·2π·

Cada oitava e a soma: é a soma que impede o interior de ir a preto.

a = 0,52 (extinção), b = 0,48 (peso), c = 0,66 (anisotropia). O termo de “pó”, 1 − e−2,4 a σΔt, escurece as bordas iluminadas: é a correção empírica que devolve o contorno escuro que o modelo de espalhamento simples apaga.

A profundidade óptica até o sol, τsol, é medida com uma marcha curta de seis passos partindo do ponto atual, com passo crescendo 55 % a cada iteração e deslocamentos laterais em cone para amostrar volume em vez de linha, mais uma amostra distante que representa o resto da atmosfera.

5. Câmera, passos e ruído proposital

A câmera é em perspectiva: a origem do raio é a mesma em todo pixel e o que muda é a direção, aberta num cone a partir de um olho a 2,5 lados de distância do centro do box. É isso que faz a aresta próxima do terreno chegar mais larga que a distante — com a projeção ortográfica que havia antes as duas saíam iguais, e a leitura da profundidade se invertia. O enquadramento continua projetando os oito vértices do cubo e usando a maior extensão, agora com o fator de profundidade de cada um, senão os cantos do lado próximo — justamente os que a perspectiva alarga — sairiam do quadro. O tamanho aparente da cena é regulado pela distância do olho: aproximá-la abre mais o cone, afastá-la volta em direção ao ortográfico.

o=cd·2,5L+(2Hu)+(2Hv)

Δti=Δt0(1+0,02i)

O raio amostrado: passo inicial deslocado e espaçamento crescendo.

L = 10 000 m, H = meia-altura do quadro em metros, (u,v) as coordenadas normalizadas de tela. O passo cresce 2 % por iteração: o detalhe importa perto da câmera, não no fundo.

Duas decisões contra artefato: o início do raio recebe um deslocamento pseudoaleatório por pixel, o que troca as faixas concêntricas do passo fixo por um granulado que o desfoque some; e o percurso pula ao dobro do passo enquanto encontra vazio, recuando um passo assim que reencontra densidade.

6. A marca dentro da nuvem

A logo e os rótulos da rede não ficam por cima da cena: ficam dentro dela. Ao cruzar o plano da marca — perpendicular à visada e passando pelo hub —, a marcha fecha a camada da frente e recomeça uma nova. Sobram duas imagens, antes e depois do plano, e a composição encaixa a marca entre elas.

tplano=(hubo)·d

Onde a marcha se parte em duas, e onde a marca é encaixada.

O mesmo critério de profundidade decide quais nós da rede são desenhados atrás da nuvem e quais na frente.

A nuvem é marchada em 480p, mas a marca, as arestas do cubo e a textura do solo são compostas na resolução do dispositivo. É o que permite texto nítido e nuvem barata no mesmo quadro. O desfoque é uma passada gaussiana separável aplicada só à nuvem.

7. Cor

A cena é calculada em luz linear e só no fim passa por um tone mapping de curva ACES aproximada. As imagens que entram na cena — o recorte de satélite, a marca — já vêm tonemapeadas e em sRGB, então o código aplica nelas a inversa analítica da curva antes de usá-las, para que não sejam iluminadas duas vezes.

T(x)=x(2,51x+0,03)x(2,43x+0,59)+0,14

A curva que leva a luz linear da cena até o branco da tela.

A inversa sai da raiz da quadrática correspondente. A sombra que a nuvem projeta no solo vem de duas amostras de densidade na direção do sol, atenuadas por Beer–Lambert, e−45σ, calculada à parte do albedo para que a textura de satélite não passe pelo desfoque.

8. O que a rolagem controla

A elevação da câmera está presa à rolagem da página, com o meio da tela como linha de referência e o card como régua: enquanto sobrar mais de 80% do card abaixo dessa linha, a câmera fica a pino, em 90° — é o tempo de ver a cena parada antes de qualquer movimento. O tombo até 25° corre entre 80% e 50%, e depois fica preso no fim — a metade final do curso do card serve só para ler a cena já deitada. O azimute segue girando sozinho, e o arrasto do ponteiro continua livre para girar a cena. O ciclo de evolução da nuvem — cobertura, tipo e densidade se movendo juntos — vai e volta em triângulo suavizado a cada 30 s, porque em dente de serra o retorno ao mínimo apareceria como um salto.

O resto

E o que mais está rodando.

Fora as duas peças acima, a página é HTML, CSS e um arquivo de JavaScript. Sem framework, sem build, sem dependência remota além das fontes.

A abertura. O vídeo do hero começa ocupando a tela inteira, com a logo branca ao centro, e encolhe até virar o fundo do card. A transição espera o carregamento do render 3D — com teto de tempo, para que uma conexão ruim não prenda ninguém na tela cheia.

As entradas de seção. GSAP com ScrollTrigger, hospedado localmente, uma única vez por elemento e sempre com estado final visível caso o script falhe. Foco de teclado e a preferência por menos movimento cancelam a animação em curso em vez de competir com ela.

Acessibilidade. Tudo o que se move respeita prefers-reduced-motion: o campo de pressão desenha um quadro estático, o vídeo pausa e as entradas somem. As animações também param quando a aba sai de foco.

Desempenho. O campo de pressão roda a 30 quadros por segundo e só sobre a área visível, independentemente do comprimento do documento. O render 3D vive num iframe e carrega atrás da abertura, porque é a peça mais cara da página.

Referência para quem quiser ir atrás: o modelo de nuvem segue a linha do trabalho apresentado por Andrew Schneider e Nathan Vos para o Horizon Zero Dawn (SIGGRAPH 2015) e da aproximação de múltiplo espalhamento por oitavas de Magnus Wrenninge. O equilíbrio geostrófico está em qualquer livro de meteorologia dinâmica — o Holton é o de sempre.

Receber amostra em PDF