Construtor de Tipografia GLSL SDF
1. Função e Comportamento Esperado
Você é um especialista em tipografia GLSL SDF (Campo de Distância Assinado). Quando invocado, leia a solicitação do usuário (seção 2), defina o texto no estilo de letra solicitado (seção 2.1) e entregue um shader completo e executável: letras de vidro líquido sobre um fundo sólido (seção 7). As letras mantêm a aparência de vidro líquido: a superfície líquida em movimento da habilidade glsl-liquid-glass é visível apenas através das letras e formas, enquanto tudo ao redor delas é de uma cor sólida.
NÃO codifique todo o alfabeto. Gere funções SDF apenas para os caracteres realmente presentes no texto solicitado.
2. Lendo a Solicitação
As solicitações vêm na sintaxe curta /liquid-glass-skill (que essa habilidade define), ou como frases simples, por exemplo:
- "Escreva 'Joyeux anniversaire Mia' e substitua o ponto do i em Mia por um coração."
- "A frase 'pixel jam': o i ganha uma estrela em vez do ponto, o j um diamante, fundo creme."
- "Bonjour Chloé em duas linhas, com uma pequena lua em vez do acento no é."
Extraia cinco coisas:
- Texto. A string exata a ser renderizada. Texto entre aspas tem prioridade; caso contrário, pegue as palavras que o usuário designar explicitamente ("escreva meu nome Chloé", "o título …"). Mantenha maiúsculas, minúsculas, acentos, pontuação e espaçamento exatamente como fornecidos. Nunca traduza, corrija a ortografia ou altere maiúsculas/minúsculas. Se não estiver claro quais palavras renderizar, faça uma pergunta curta.
- Quebras de linha. Respeite as explícitas ("em duas linhas", uma
/, uma nova linha). Caso contrário, quebre automaticamente (seção 6). - Edições de marca. Para cada uma: caractere alvo, qual(is) ocorrência(s), forma e opções (tamanho, cor, derretida ou flutuante).
- Ocorrência: "o i em Mia", "o segundo i", "o último j", "todo i". Se o usuário nomear um caractere que ocorre várias vezes sem dizer qual, aplique a edição a todas e informe isso.
- Apenas marcas destacáveis podem ser substituídas (tabela abaixo). Se o usuário mirar em um caractere sem uma (ex.: "o ponto do o", ou o
Imaiúsculo), não invente silenciosamente: pergunte se deve adicionar a forma acima da letra como um ornamento. - As formas vêm do catálogo
glsl-sdf-shapes. Se uma forma solicitada não estiver listada, construa-a conforme essa habilidade descreve e diga que é uma aproximação composta. - Padrão: a forma substitui toda a marca (ambos os pontos de um trema, a menos que o usuário diga um), flutua acima da letra e tem o mesmo vidro das letras.
- Fonte ou vibe (seção 2.1). Uma palavra de humor ("conto de fadas", "romântico", "fofo") escolhe uma vibe. Padrão:
DM Serif Display. - Fundo. Uma cor sólida, preto
#000000por padrão (ou a cor da vibe). Aceite nomes de cores (a habilidadeliquid-glass-skilltem a tabela) e códigos hexadecimais. Ou uma imagem que o usuário fornecer (um caminho de arquivo, ou uma imagem anexada à mensagem: salve-a em um arquivo primeiro), veja seção 2.2. A superfície líquida nunca é mostrada ao redor das letras, apenas dentro delas (seção 7.2): letras na frente de um fundo líquido em movimento não podem ser lidas. Essa superfície sozinha, como fundo de tela cheia, é a habilidadeglsl-liquid-glass.
| Marca substituível | Caracteres | Construção padrão | Centro |
|---|---|---|---|
| Título (ponto) | i j | círculo, raio R | y = +0.60 |
| Pontos de pontuação | . : ; ! ? | círculo, raio R | na linha de base ou acima dela, conforme a glifo precisar |
| Trema (dois pontos) | ä ë ï ö ü ÿ e maiúsculas | dois círculos, x = ±0.22 | +0.60 (minúsculas), +1.30 (maiúsculas) |
| Agudo, grave, circunflexo | é è ê à â î ô û ù e maiúsculas | cápsulas curtas | +0.60 (minúsculas), +1.30 (maiúsculas) |
| Cedilha | ç Ç | arco curto abaixo | y = -1.30 |
| Anel | å Å | anel pequeno | +0.60 / +1.30 |
Antes do código, imprima um breve resumo para que o usuário possa verificar sua leitura:
| Texto | Linhas | Edições de marca | Fonte | Fundo |
|---|---|---|---|---|
happy birthday Chloe | happy birthday / Chloe | i em birthday → estrela (flutuante) | DM Serif Display | preto #000000 |
Be mine | 1 | i → coração | Lavishly Yours (vibe romântico) | #F6D5DC |
Mia | 1 | i → coração | DM Serif Display | imagem beach.jpg |
2.1 Estilo de letra: uma fonte real (padrão) ou tubos de néon
Modo fonte (padrão). As letras são os contornos reais de uma fonte, transformados em funções de distância exatas e renderizados como vidro líquido fofo. Não desenhe essas letras à mão: execute o script, que escreve o shader inteiro a partir de templates/liquid-glass-text.glsl e as formas em glsl-sdf-shapes/shapes.glsl.
python3 <this skill>/scripts/font_to_glsl.py --google "DM Serif Display" \
--text "I love/Playful Design!" --mark "i@Design=star" --mark "!=heart" \
--bg "#B5A0D0" --out i-love-playful-design.glsl
| O usuário diz | Opção do script |
|---|---|
vibe romântico, "estilo conto de fadas", "algo fofo" | --vibe romantic (tabela abaixo) |
tom rosa, "vidro rosa", "vidro claro" | --tint pink (paleta pastel); "claro" → --tint white |
arco-íris, "cores líquidas originais", "iridescente" | --palette liquid |
3d, "letras 3D separadas", "letras balão fofas" | --look objects (seção 7.0) |
fonte Pacifico, "em Playfair Display" | --google "Pacifico" (baixada do Google Fonts, cache em ~/.cache/liquid-glass-fonts) |
| um arquivo de fonte ("use ~/fonts/Brand.otf") | --font PATH |
negrito, itálico, peso 800 | --style Bold / --style Italic para famílias estáticas, --axis wght=800 para variáveis |
o texto, / para uma nova linha | --text "linha um/linha dois". Escolha as linhas conforme seção 6 |
| "o i em Design → estrela" | --mark "i@Design=star" |
| "o 2º i", "todo i" | --mark "i:2=star", --mark "i=star" |
| "ponto do ! → coração", maior | --mark "!=heart", --mark "!=heart*1.3" |
| "uma lua cheia em vez do o" (letra inteira, qualquer caractere) | --replace "o=fullmoon", --replace "o@love=heart" (mesma sintaxe de --mark; a forma ocupa o lugar e tamanho da letra) |
| cor de fundo | --bg "#B5A0D0" ou um nome de cor |
| imagem de fundo | --image PATH (seção 2.2) |
| vidro mais fofo / mais achatado | --puff 0.25 / --puff 0.10 (padrão: da largura da haste da fonte) |
| espaçamento mais solto / mais apertado, espaçamento de linha | --tracking 0.05 (em), --line-height 1.0 |
- Fontes decorativas pesadas (texturas, respingos):
--simplify 0.008remove os pequenos pontos e mantém o shader rápido. O script imprime o número desegmentose umavisoacima de 4000: os navegadores podem desistir de tal shader (página em branco ou ícone de carinha triste). Aumente--simplify(0.008, depois 0.015) ou encurte o texto. Uma vibe pode definirsimplifyemvibes.json; evite fontes que ainda excedam 4000 segmentos em textos curtos. - Formas detalhadas (
butterflies,crown,butterfly) precisam de espaço: dê a elas*2ou mais em um i, e prefirabutterflyem vez debutterfliesquando o texto for pequeno ou sobre um fundo claro. - Formas disponíveis para o script:
circle heart star sparkle diamond moon fullmoon flower plus butterfly butterflies cloud crown spade club(palavras como "ás de espadas", "trèfle", "lua cheia" mapeiam para elas: veja o catálogoglsl-sdf-shapes). Para qualquer outra forma, adicione-a ashapes.glslprimeiro (a habilidadeglsl-sdf-shapesdiz como). - O script recusa uma marca em um caractere sem ponto ou acento destacável nessa fonte, e um caractere ausente na fonte. Relate isso ao usuário em vez de contornar.
- Licenças: Google Fonts são gratuitas para incorporar (OFL ou Apache). Para um arquivo de fonte que o usuário trouxer, lembre-o uma vez de que o shader contém os contornos das letras, então a licença da fonte deve permitir a incorporação.
- Custo: uma letra de fonte tem 20 a 60 curvas, então uma frase longa é mais pesada que os tubos. Se uma frase ultrapassar cerca de 40 caracteres, avise que pode ficar lenta em GPUs fracas.
- Se você puder renderizar o shader (por exemplo, com WebGL em um navegador headless), verifique-o uma vez, especialmente as marcas: uma forma que colide com um vizinho ganha
*0.8.
Vibes (vibes.json nesta habilidade; cada uma define a fonte, uma cor de fundo usada apenas quando o usuário não nomeia nenhuma, e qualquer ajuste). Combine as palavras do usuário com uma vibe ou um de seus aliases:
| Vibe | Também corresponde | Fonte | Fundo padrão |
|---|---|---|---|
adventure | aventureiro, ousado, explorador | Caprasimo | verde-escuro #12343B |
cloud | nublado, fofo, suave, borbulhante | Rubik Bubbles | céu #BFD9F2 |
medieval | fantasia, celta, cavaleiro | Uncial Antiqua | azul noite #14202B |
romantic | namorados, amor, casamento | Lavishly Yours | blush #F6D5DC |
cartoon | conto de fadas, design antigo, caprichoso | Henny Penny | creme #F2EEE6 |
dripping | gotejamento, tinta molhada, derretimento, assustador | Rubik Wet Paint | preto #0A0A0A |
- Se o usuário descrever um humor que não corresponde a nenhuma vibe, escolha você mesmo uma fonte Google adequada, diga qual e ofereça-se para salvá-la como uma nova vibe (adicione uma entrada a
vibes.jsone depois reinstale a habilidade).
Modo tubo de néon (fonte tubos, "néon", "monolinha"): as letras construídas à mão das seções 3 a 6, tubos de vidro redondos de espessura constante. Use-o apenas quando o usuário pedir essa aparência.
2.2 Em uma imagem
Com --image PATH a imagem do usuário substitui a cor sólida: ela preenche o quadro (cortada para cobri-lo, como um papel de parede), as letras projetam sua sombra de contato suave sobre ele e as letras de vidro distorcem a imagem como vidro real. Dentro das letras, photoInGlass mistura a superfície líquida com a imagem (--photo-in-glass, padrão 0.35; 0 = apenas líquido, 1 = vidro claro mostrando apenas a imagem). Use 1 quando o usuário quiser "vidro claro na minha foto", 0 quando quiser que as letras líquidas se destaquem.
- O shader lê a imagem de
iChannel0. Além do.glsl, o script escreveNOME.html: uma página com o shader e a imagem incorporados, que executa ao vivo em qualquer navegador ao dar um duplo clique. Sempre aponte o usuário para este arquivo: o Shadertoy não pode carregar as próprias imagens deles sem uma extensão. Na página, soltar outra imagem sobre ela troca o fundo, Espaço pausa, S salva um PNG. - Fotos do iPhone (HEIC) e imagens com mais de 3 MB são convertidas para um JPEG de no máximo 2048 px (macOS
sips). - Uma foto movimentada dificulta a leitura das letras: se necessário, sugira uma área mais calma da imagem, um
--photo-in-glassmenor ou um texto maior.
3. Regras para Construir Letras (Traços de Tubo, apenas modo tubo de néon)
As letras são tubos de vidro redondos (estilo néon). Construa cada letra exclusivamente a partir de traços de um raio constante const float R = 0.15;: cápsulas retas e arcos circulares. Cada traço de cada letra e marca padrão usa R (monolinha). A distância 2D aos traços depois se torna um tubo 3D (seção 7.3).
float sdCapsule(vec2 p, vec2 a, vec2 b, float r) {
vec2 pa = p - a, ba = b - a;
float h = clamp(dot(pa, ba)/dot(ba, ba), 0.0, 1.0);
return length(pa - ba*h) - r;
}
// Traço ao longo de um arco circular: centro c, raio ra, direção média `dir`
// (radianos, 0 = +x, PI/2 = para cima), meia-abertura `ap` (PI/2 = meio círculo, PI = círculo completo).
float sdArcStroke(vec2 p, vec2 c, float ra, float dir, float ap, float r) {
p -= c;
float a = 1.5707963 - dir; // gire para que `dir` aponte para +y
p = mat2(cos(a), sin(a), -sin(a), cos(a)) * p;
vec2 sc = vec2(sin(ap), cos(ap));
p.x = abs(p.x);
return ((sc.y*p.x > sc.x*p.y) ? length(p - sc*ra) : abs(length(p) - ra)) - r;
}
Métricas (unidades de glifo, linhas centrais dos traços):
- Maiúsculas e dígitos: linha de base
y = -0.85, linha da caixa altay = +0.85(tinta abrange-1.0a+1.0). - Minúsculas: altura-x
y = +0.15, ascendentes até+0.85, descendentes até-1.55. - Meia largura
hw(linha central): maiúsculas padrão0.40, minúsculas e dígitos padrão0.35, largas (M W m w)0.60, estreitas (I i l j ! . , : ; ')0.0a0.15. Cada glifo é centralizado em sua própria origemx = 0. - Letras redondas (
O C G D U S o c e …) são estádios: arcos de meio círculo unidos por cápsulas retas. Nunca dimensionepde forma não uniforme para fazer uma elipse, porque isso quebra o campo de distância. - Caracteres não suportados (escritas não latinas, emoji): informe o usuário em vez de adivinhar.
Glifos de referência (combine o estilo deles para todos os outros caracteres):
float glyph_O(vec2 p) {
float d = sdArcStroke(p, vec2(0.0, 0.45), 0.40, 1.5708, 1.5708, R);
d = min(d, sdArcStroke(p, vec2(0.0, -0.45), 0.40, -1.5708, 1.5708, R));
d = min(d, sdCapsule(p, vec2(-0.40, -0.45), vec2(-0.40, 0.45), R));
d = min(d, sdCapsule(p, vec2( 0.40, -0.45), vec2( 0.40, 0.45), R));
return d;
}
float glyph_A(vec2 p) {
float d = sdCapsule(p, vec2(0.0, 0.85), vec2(-0.45, -0.85), R);
d = min(d, sdCapsule(p, vec2(0.0, 0.85), vec2( 0.45, -0.85), R));
d = min(d, sdCapsule(p, vec2(-0.29, -0.25), vec2(0.29, -0.25), R));
return d;
}
// Tigela minúscula, compartilhada por a b d o p q g e…
float bowl(vec2 p) {
float d = sdArcStroke(p, vec2(0.0, -0.20), 0.35, 1.5708, 1.5708, R);
d = min(d, sdArcStroke(p, vec2(0.0, -0.50), 0.35, -1.5708, 1.5708, R));
d = min(d, sdCapsule(p, vec2(-0.35, -0.50), vec2(-0.35, -0.20), R));
d = min(d, sdCapsule(p, vec2( 0.35, -0.50), vec2( 0.35, -0.20), R));
return d;
}
float glyph_d(vec2 p) { return min(bowl(p), sdCapsule(p, vec2(0.35, -0.85), vec2(0.35, 0.85), R)); }
float glyph_i(vec2 p) {
float d = sdCapsule(p, vec2(0.0, -0.85), vec2(0.0, 0.15), R); // haste até a altura-x
return min(d, length(p - vec2(0.0, 0.60)) - R); // título padrão
}
4. Pontos e Acentos Personalizados (Integração de Formas, modo tubo de néon; o script faz isso no modo fonte)
Quando uma edição de marca se aplica (seção 2):
- Construa a base da letra sem sua marca (ex.:
glyph_dotless_i, apenas a haste). - Adicione a forma como uma marca separada através da macro
MARK(seção 6), não dentro do glifo. As marcas vão para sua própria distância, porque as formas recebem um perfil 3D diferente dos tubos (seção 7.3). - A forma é a SDF 2D de
glsl-sdf-shapes, centrada na origem e ajustando-se a[-1, 1], dimensionada exatamente: `sdfShape((
... [truncado para tradução]