Uma camada absoluta sobre a dobra, com bolhas de rótulo que carregam um ponteiro de mouse encostado num canto. Cada bolha desliza devagar entre duas ou três âncoras e para alguns segundos em cada uma. O olho lê como alguém apontando para a interface e dizendo o que ela faz.
Resolve um problema editorial específico: a dobra tem um argumento que não é a headline nem o subtítulo, e que perderia força numa lista de bullets. A legenda de cursor põe esse argumento no ar, ao lado do que ele descreve, sem consumir uma linha do bloco de texto. É um recurso de página de produto — em site institucional soa como aviso de software.
Quando usar
- Dobra de produto, com sobra visual: hero de duas colunas, faixa de prova, grade de cards com respiro
- Um a três argumentos curtos, de até ~60 caracteres cada, que não caberiam na headline
- Página de SaaS, app, plataforma — onde "cursor" é vocabulário nativo
Quando não usar
- Dobra densa. A bolha é opaca e vai cobrir alguma coisa — não há ajuste que resolva falta de espaço
- Mobile como alvo principal. Abaixo de 640px a camada não é exibida — não há posição em que a bolha não cubra texto numa tela de 375px; ver Gotchas
- Institucional sem interface para apontar — luxo, marca pessoal, dobra de texto e foto. Ponteiro de mouse é linguagem de software: numa assessoria ele só cabe sobre a encenação de um portal do cliente ou de um relatório na tela, que é o caso do markup atual. Sobre foto de família, não
- Quando o argumento é importante de verdade: então ele é conteúdo, e vai no
.sec-leadou numconteudo/imagem-lista-numerada
Padrão editorial
| Slot | Regra |
|---|---|
| Bolha | uma afirmação, sem ponto final, sem verbo no imperativo. Descreve a ferramenta, não manda usar |
| Extensão | 40 a 60 caracteres. Duas linhas na bolha é o alvo; três já é parágrafo |
| Quantidade | duas por dobra. Três é o teto absoluto, e só em dobra de tela cheia |
| Tom | as duas notas nunca no mesmo roxo — uma leva .cur-note-deep |
As notas de uma mesma dobra têm de ser paralelas em forma e diferentes em assunto: "Carteira desenhada para o seu horizonte" e "Relatório consolidado de todas as instituições" falam de coisas distintas no mesmo comprimento. Duas notas sobre o mesmo tema viram redundância exposta.
E o tempo de parada de cada nota é diferente de propósito (2600 e 3100 no markup). Em passo igual as duas viram um metrônomo, e o olho percebe o truque.
Especificação dos assets
Nenhum. O ponteiro é um <path> de 22×26 desenhado no próprio markup — não há imagem, ícone de biblioteca nem fonte a carregar.
Como usar
<link rel="stylesheet" href="componentes/efeitos/cursor-anotacao/estilo.css">
<script src="componentes/efeitos/cursor-anotacao/script.js"></script>
A camada é filha direta da seção. O core já dá position:relative a toda <section>, então não há nada a preparar:
<section class="sec-light sec-pad">
<div class="cur-layer">
<span class="cur-note cur-note-br cur-note-deep"
data-cur-note data-cur-pos="5% 4%; 17% 4%" data-cur-hold="2600">
<span class="cur-body" data-rv>
<span class="cur-tip" aria-hidden="true"><svg viewBox="0 0 22 26">...</svg></span>
<span class="cur-bubble">Relatório consolidado de todas as instituições</span>
</span>
</span>
</div>
<!-- a dobra -->
</section>
Ganchos
| Gancho | Papel |
|---|---|
.cur-layer |
a camada. Absoluta, cobre a seção, pointer-events:none |
[data-cur-note] |
a nota. O script escreve --cur-x/--cur-y aqui |
data-cur-pos |
âncoras, "x y; x y", em porcentagem da camada. Uma = parada, duas = vai-e-volta, três+ = ciclo |
data-cur-hold |
parada em ms. Padrão 2600 |
.cur-note-tl -tr -br -bl |
o canto onde o ponteiro encosta. O canto quadrado da bolha é a direção |
--cur-skin |
cor da bolha e do ponteiro, os dois de uma vez |
--cur-ink |
cor do texto |
--cur-bite |
quanto o ponteiro entra na bolha. Padrão 8px |
--cur-max |
largura máxima. Padrão 212px |
--cur-radius |
raio da bolha. Padrão 10px |
.cur-layer-desktop |
na camada: apaga tudo abaixo de 980px, e não de 640px |
Variações
.cur-note-deep— roxo escurecido contra o--dark. É a segunda nota da dobra. Nunca rodou em produção.cur-note-lg— 13px, raio 12px, ponteiro 26px. Para dobra de tela cheia. Nunca rodou em produção- nota parada — uma âncora só. O script pousa e sai sem ligar relógio
- três ou mais âncoras — vira ciclo, na ordem escrita
.cur-layer-desktop— apaga a camada abaixo de 980px, para dobra que colapsa para uma coluna antes dos 640px. É o que ohero/duas-colunas-produtousa. Nunca rodou em produção
Gotchas
-
O
data-rvvai na.cur-body, não na.cur-note. Não é preciosismo de estrutura.[data-rv]declaratransitionpara opacity, filter e transform, etransitioné shorthand: não se soma, substitui. Como o CSS do componente carrega depois do core, umatransition:left,topna mesma caixa apagaria a transição do reveal e a nota apareceria seca — contra o §5. Duas caixas resolvem sem!importante sem depender de ordem de carregamento. -
O deslize é em
left/top, e isso é deliberado. A âncora é porcentagem da camada, etranslateem % lê a caixa do próprio elemento, não a do pai — então transform não serve sem calcular pixels no script. São dois elementos pequenos andando uma vez a cada 2,6s: o custo de não estar no compositor é teórico, e a alternativa era escrever um FLIP à mão para ganhar nada. Se algum dia a nota precisar acompanhar scroll ou arraste, aí a conta muda e vale reescrever. -
--cur-skinpinta a bolha e o ponteiro juntos. Trocar só uma das duas produz um adesivo com a ponta de outra cor. Se precisar mesmo, sobrescrevacolorna.cur-tip— mas olhe antes se não é o--accentdo tema que está errado. -
Contraste é responsabilidade do tema. O texto nasce em
var(--light)sobrevar(--accent). Tema com accent claro (amarelo, sage, bege) produz branco sobre claro e a bolha fica ilegível. Nesse caso o tema põe--cur-ink:var(--dark)— o componente não adivinha, porque não tem como ler a luminância do accent em CSS puro. -
A nota nasce em
0% 0%se o script não rodar. É o fallback dovar(--cur-x,0%). Colada num Elementor sem oscript.js, a bolha aparece encostada no canto superior esquerdo da seção — visível e errada, o que é melhor que invisível: o erro se denuncia. -
Em tela estreita a camada desiste, e isso é a resposta certa. Há dois recuos: em 900px a nota encolhe, em 640px ela some. Numa tela de 375px não existe posição em que a bolha não cubra texto — nenhum
--cur-maxresolve, porque o problema é a dobra não ter mais espaço vazio. A nota é anotação, não conteúdo: sumir não custa informação. Dobra que colapsa para uma coluna antes de 640px precisa do.cur-layer-desktop, senão a bolha aparece sobre o texto na faixa entre os dois pontos. -
O relógio para fora da tela. Um
IntersectionObserverdesliga osetIntervalquando a nota sai de vista. A referência não faz isso e fica com dois timers correndo a página inteira, para sempre.
Histórico
| Projeto | Onde | Data | Diferenças |
|---|---|---|---|
| referência: Corvex | https://usecorvex.com.br/ — hero | 2026-08-31 | referência visual, não origem de código |
Normalizações aplicadas na tradução: a referência é Framer — classes hash, sem licença declarada, e nada foi copiado (§11). O que veio dela: a ideia da bolha com ponteiro encostado no canto quadrado, o porte (bolha ~187×48, ponteiro ~23×27), a cadência de ~2,5s de parada e o par de roxos. O que é nosso: o ponteiro desenhado do zero; a cor toda em --accent e color-mix em vez dos dois hex cravados; a entrada por data-rv do core (a referência usava opacidade em mola, sem blur — o §5 pede blur); as âncoras como contrato de dado (data-cur-pos) em vez de posições cravadas no CSS; os quatro cantos em vez dos dois que a referência tem; o desligamento fora da tela; e o aria-hidden só no ponteiro, deixando o texto da bolha legível para leitor de tela — na referência a bolha inteira é decoração.
Divergências conhecidas vs. a referência: o original desliza com mola do Motion, que passa ~1,5% do alvo e volta; aqui é o --ease único do projeto, sem overshoot. A diferença é imperceptível no percurso de ~150px, e um token de mola é decisão de arquitetura (§9.3) que não se justifica por isso. A referência também troca o texto das bolhas quando o carrossel da dobra vira de slide; aqui a nota é estática em conteúdo — quem quiser isso liga o hero/duas-colunas-produto às notas por conta própria.