O que Esboço a tinta faz?
Desenha uma imagem como um SVG animado autocontido: linhas de tinta irregulares de espessura variável, manchas de marcador ligeiramente desviadas das linhas, sobre papel creme. Plano 2D, vista frontal ou lateral. As linhas "fervilham" (a irregularidade é redesenhada a cada 2 quadros), então até um assunto parado parece vivo, e a cena pode adicionar um pequeno movimento com t. Para uma versão 3D isométrica, use a habilidade handdrawn-3d. Etiquetas e títulos usam uma fonte de traço desenhada à mão incorporada que cobre latim e vietnamita.
Kit: assets/kit.js · renderizador: assets/render.mjs · todas as funções: references/kit.md (leia antes de escrever uma cena) · exemplos práticos: examples/ (copo, maçã, gato, planta, casa, refeição).
Configuração (única vez)
A exportação de PNG/GIF precisa de @resvg/resvg-js. Se render.mjs disser que está faltando, execute npm install na pasta desta habilidade. A saída SVG não precisa de nada.
Antes de desenhar
- É desenhável? Se o assunto for abstrato ("esperança", "produtividade", "economia"), não desenhe algo vago. Diga isso e sugira uma ou duas cenas concretas que o mostrem ("uma muda rompendo uma rachadura no asfalto"), depois desenhe a que o usuário escolher.
- Diagramas, gráficos, UI, botões, coisas interativas: não é para esta habilidade.
- Animação: o SVG sempre loopa (fervilhamento de linha). Adicione um pequeno movimento que pertença ao assunto (vapor, um balanço de cauda, uma piscada, folhas balançando) quando couber ou quando o usuário pedir; caso contrário, apenas o fervilhamento já é suficiente.
Um SVG de quadro único apenas quando o usuário pedir uma imagem estática (
--still).
Fluxo de trabalho
- Partes e vista. Liste as partes reais do assunto e escolha a vista: frontal ou lateral. Um bule: corpo, tampa, botão, bico, alça, base; vista lateral. Desenhe a partir das partes reais (bordas, alças, tampas, caules, tábuas, azulejos), não uma bolha genérica com um nome.
- Esboce. Escreva uma pequena tabela num comentário no topo da cena: parte, chamada de forma, caixa (x, y, w, h), cor. O assunto ocupa ~65–80% da folha, centralizado, com espaço para respirar. A linha do chão/mesa fica cerca de 80–88% abaixo.
- Desenhe de trás para frente no
scene.jscom o kit: sombra → coisas atrás → corpo principal → detalhes por cima → etiquetas. Prefira as peças prontas (k.cat,k.person,k.tree,k.house,k.window,k.leaf…) e mude as opções em vez de redesenhá-las. Usek.turnedpara qualquer coisa redonda que você pudesse tornear (copos, potes, vasos, garrafas, tigelas, lampiões). Usek.tubepara alças, caules, caudas, braços e galhos. - Renderize e olhe:
Abranode <skill>/assets/render.mjs scene.js -o out/scene.svg --png out/scene.png --thumb --gridout/scene.pngcom a ferramenta Read e olhe para ela. A sobreposição--gridimprime coordenadas para que você possa ler onde as coisas estão realmente. Olhe também paraout/scene-128.png: ela ainda precisa ser legível como o assunto a 128 px. - Corrija e renderize novamente. Verifique:
- É legível como o assunto à primeira vista, e a 128 px? Silhueta primeiro: se o contorno não diz "bule", nenhum detalhe vai salvá-lo.
- Proporções e sobreposições: alças se prendem aos corpos, as coisas repousam no chão, nada flutua ou corta.
- A luz vem do topo-esquerdo em toda parte (sombra/hatching no canto inferior direito).
- As etiquetas não ficam em cima do desenho nem cruzam outras linhas.
Repita 4–5 até ficar certo (geralmente 2–4 rodadas). Depois renderize o final sem
--grid.
Nunca entregue sem ter olhado o PNG. Entregue o SVG (a imagem animada) e os caminhos do PNG, e mostre o PNG. Se a cena se move, verifique também alguns quadros (veja Animação).
Regras de estilo
- Visual único: tinta + mancha de marcador plana. Sem textura ou grão. Sem gradientes, brilhos, sombras projetadas, desfoque, truques de opacidade ou
<text>SVG (usek.text/k.label/k.title). Não adicione SVG cru. - Cor: nomes de paleta (
red, coral, orange, ochre, yellow, sage, green, leaf, teal, sky, blue, navy, lilac, plum, pink, wood, brown, chocolate, grey, stone, charcoal, white, cream, sand, skin, tan). 3–5 cores por imagem mais tinta. Qualquer hex é suavizado automaticamente, mas nomes de paleta ficam melhores. - Sombreamento:
shade: true(ou 0.15–0.35) nos volumes principais;hatch: trueem um ou dois objetos grandes no máximo. A luz sempre vem do topo-esquerdo. - Espessuras de linha: contornos
'outline'(padrão), detalhes internos'detail', marcas pequenas e linhas guia'fine'. - Fofo e redondo: animais e plantas são macios e redondos, com cabeças grandes, olhos de ponto e pequenas elipses de blush. Sem anatomia nítida e realista.
- Composição: um assunto claro, centralizado, preenchendo a maior parte da folha. Uma sombra de chão (
k.shadow) abaixo de tudo que fica em pé sobre algo. - Texto:
k.title(...)opcional no topo-esquerdo, mais pequenas etiquetas de margem em minúsculas (k.label) com linhas guia, colocadas em espaço de margem vazio. Nunca caixas ou balões de fala flutuando sobre o desenho. Escreva etiquetas no idioma do usuário. Vietnamita é totalmente suportado. - Folha: 1000×1000 por padrão. Para cenas largas use
export const sheet = { width: 1200, height: 900 }.--transparentremove o papel.
Modelo de cena
// bule, vista lateral. partes: corpo (torneado), tampa, botão, bico (tubo), alça (tubo), sombra
export const sheet = { seed: 1 };
export function draw(k, t = 0) {
k.shadow(500, 820, 300, 34);
k.tube([[690, 540], [810, 520], [810, 650], [700, 710]], 34, { fill: 'teal' }); // alça (extremidades escondidas pelo corpo)
k.tube([[330, 640], [250, 560], [200, 470]], [60, 26], { fill: 'teal', shade: 0.3 }); // bico
const pot = k.turned([[150, 0], [230, 70], [250, 180], [210, 300], [170, 330]],
{ cx: 500, y: 480, fill: 'teal', hatch: true }); // corpo
k.ellipse(500, 480, 150, 22, { fill: 'teal', weight: 'detail' }); // tampa
k.blob(500, 445, 30, { squash: 0.8, fill: 'ochre' }); // botão
k.label('o bom bule', { x: 640, y: 300, to: [560, 440] });
}
Animação (sempre ativa)
out.svg é um SVG animado em loop por padrão: quadros alternados por CSS, sem script, funciona em navegadores e tags <img> (renderizadores sem animação CSS mostram o quadro 0). As cenas recebem t ∈ [0, 1), um loop. Mantenha simples: no máximo uma ou duas coisas se movendo (vapor, um balanço de cauda, uma piscada, folhas balançando, fumaça) além do fervilhamento de linha automático: a irregularidade é redesenhada a cada 2 quadros, então até um assunto parado parece vivo. Faça o movimento se repetir perfeitamente com Math.sin(2 * Math.PI * t). As peças prontas aceitam t:
k.steam(x, y, { t }), k.cat(..., { animate: true, t }), k.person(..., { wave: true, t }).
node <skill>/assets/render.mjs scene.js -o out/scene.svg --png out/scene.png # SVG animado + PNG estático
node <skill>/assets/render.mjs scene.js -o out/scene.svg --gif out/scene.gif # + GIF, funciona em toda parte
node <skill>/assets/render.mjs scene.js -o out/scene.svg --still # SVG de quadro único
--frames 8 --fps 10 --boil 2 --gif-size 560
Verifique um GIF olhando alguns quadros: ffmpeg -i out/scene.gif -vf "select='not(mod(n\,3))',scale=300:-1,tile=4x1" -frames:v 1 out/frames.png (ou verifique o PNG estático, que é o quadro 0). GIFs são de 256 cores: mantenha-os com largura ≤ 600 px.