Mono Editorial Landing
Uma página de destino com estilo de revista: tinta no papel, um cabeçalho com uma linha fina de "edição", um título em Instrument Serif grande o suficiente para ser lido do outro lado da sala, uma introdução com capitular, depois colunas numeradas divididas por linhas finas, spreads de funcionalidades que alternam lados com figuras emolduradas e legendas ("Fig. 1"), uma citação em itálico centralizada, uma lista de perguntas, uma linha de fechamento e um colofão no estilo máquina de escrever. Preto sobre branco quente por padrão; claro sobre quase preto, ou com uma cor de destaque para as palavras em itálico, alterando três cores.
Você descreve a página em page.json, ou deixa um script rascunhá-la a partir do README do projeto. O build verifica e escreve out/index.html, um arquivo com seu CSS (e out/assets/ para imagens). Para um produto que ainda não foi lançado, o hero contém um formulário de lista de espera real que envia para Formspree, Netlify Forms, Buttondown ou qualquer endpoint; para um que já está no ar, dois botões.
O que você precisa
- Node.js 18 ou mais recente. Nada para instalar.
- Chrome, Chromium ou Edge para as verificações (os scripts o encontram; defina
CHROME_PATHse não encontrarem). - Para uma lista de espera: uma conta em um serviço de formulários, ou um endpoint que aceite um POST de formulário.
- Acesso à internet quando a página for aberta, para as Google Fonts (Instrument Serif, Newsreader, Inter e IBM Plex Mono). Sem internet, a página usa fontes do sistema.
A pasta desta skill é <skill> abaixo: a pasta onde este SKILL.md está.
Passos
1. Rascunhar a partir do README
node <skill>/scripts/from-readme.mjs README.md page.json
Ele lê o README (e o package.json ao lado, se houver) e escreve um page.json que já funciona: o nome, o slogan como primeiro título, a introdução como lead, uma lista de "Funcionalidades" cujos itens começam com um nome em negrito como colunas, comandos de instalação e início rápido como uma figura de terminal, outras seções como spreads de funcionalidades (com sua captura de tela ou código), uma seção de FAQ como perguntas, e o repositório como um botão. Ele ignora badges, logos, linhas de links, sumários, seções de licença e contribuição.
Ele nunca escreve conteúdo próprio além de rótulos como "Começar", e termina com três listas. Trabalhe nelas com a pessoa:
- Escrever com a pessoa: sempre o título, e todo título de funcionalidade que ainda é um heading do README ("Instalar", "Como funciona").
- Cortar para caber: texto que ele encurtou em uma quebra de frase ou palavra. Leia cada um novamente.
- No README mas não na página: seções e funcionalidades para as quais não houve espaço. Troque-as se forem mais importantes.
Sem README, ou com um enxuto, escreva page.json a partir das anotações da pessoa, do site atual ou da documentação, começando por um dos exemplos.
2. Decidir o que o hero pede
-
Ainda não lançado: uma lista de espera. Pergunte qual serviço coleta os emails e defina
hero.form:providerConfiguração O que colocar em formformspreeCrie um formulário em formspree.io; sua URL termina com o ID do formulário. Mais simples em qualquer host. "id": "xayzbqwe"netlifyApenas quando a página for implantada no Netlify; as inscrições aparecem na aba Forms do site. "name": "waitlist"buttondownUma newsletter do Buttondown. As pessoas veem a página de confirmação do próprio Buttondown. "username": "yourname"endpointQualquer outra coisa que aceite um POST de formulário: sua API, ou a URL actionde um formulário de lista de e-mails (Mailchimp, Kit, Loops e similares)."url": "https://…","field"se não foremail(Mailchimp usaEMAIL),"ajax": falsepara serviços de listaCom
ajax(o padrão, exceto para Buttondown), a página envia o formulário com JavaScript e mostrasuccessouerrorno lugar; sem JavaScript, ou com"ajax": false, é um POST de formulário normal. Um endpoint usado comajaxdeve responder com 2xx e, em outro domínio, permitir a origem da página (CORS). Todo provedor, exceto Buttondown, recebe um campo oculto de spam trap; descarte inscrições onde ele estiver preenchido. Todo botão "Entrar" na página (a barra, o fechamento) rola para o formulário e coloca o cursor nele. -
Já no ar:
hero.actionscom um botãoprimary(download, cadastro, instalação) e umsecondaryopcional (docs, código-fonte). Aponte para URLs reais ou para#get-startedna página.
3. Escrever a página
Copie o exemplo mais próximo e substitua tudo: examples/quietly/page.json (uma lista de espera, claro) ou examples/galley/page.json (uma ferramenta open-source, escuro, rascunhado a partir de examples/galley/README.md).
| Campo | O que é | Limite |
|---|---|---|
brand.name, brand.href | O nome no canto superior esquerdo, definido na serifa de display | 24 |
nav[] | Até 5 { "label", "href" }. Links #id devem apontar para algo na página (abaixo) | 16 |
action | O botão no canto superior direito; padrão: a ação principal do hero. false para nenhum. | 22 |
issue[] | Até 3 linhas curtas abaixo da barra, em versaletes: uma edição, as partes do produto, uma data de lançamento ou versão. Em telefones, apenas a primeira e a última aparecem. | 40 cada |
hero.title | O título. *palavra* coloca em itálico (em theme.accent se definido), \n quebra a linha (até 3 linhas). | 64 |
hero.lede | O que é, para quem e por quê, em uma ou duas frases. A primeira letra vira uma capitular ("dropcap": false para desligar). | 300 |
hero.form ou hero.actions | Passo 2. Textos do formulário: placeholder (32), button (22), success, error (120). Botões: { "label", "href" } (26). | – |
hero.note | Uma linha pequena abaixo do formulário ou botões: quando os convites saem, o que você enviará, a licença. | 100 |
columns[] | 2 a 4 { "kicker", "title", "text" }, numerados 01, 02… Seção id highlights | 24, 44, 220 |
features[] | Até 4 spreads: kicker (28), title (72, *itálico* funciona), text (420; uma linha em branco inicia um parágrafo), points (até 4, 90 cada), id (para links de navegação), figure (abaixo). | – |
quote | { "text", "cite" }, uma citação real de uma pessoa real que concordou com ela. Caso contrário, omita. | 220, 60 |
faq | title (40, padrão "Antes de perguntar") e 1 a 8 items de { "q", "a" }. Seção id faq. | 100, 500 |
closing | kicker (28), title (64), text (220), action (padrão: a ação principal do hero). Seção id closing. | – |
footer.items[], links[] | Até 3 linhas no colofão (padrão "Nome © ano") e até 6 links. | 48, 20 |
theme | paper e ink (hex; ink deve atingir 7:1 sobre paper), accent opcional; fontes display, serif, sans, mono (famílias Google Fonts); fonts ("" para nenhuma, ou sua URL). | – |
meta | title (70) e description (170) para pesquisa e previews de links; url, image (uma imagem https para preview de link), icon, lang. | – |
Campos de texto aceitam Markdown inline: code, links, negrito e itálico.
Figuras. Cada funcionalidade pode ter uma, desenhada em um quadro com sombra deslocada dura e uma caption opcional (90), numerada "Fig. 1", "Fig. 2" ao longo da página. Spreads com figura alternam lados; spreads sem figura colocam o título ao lado do texto.
type | Campos | Use para |
|---|---|---|
image | src (um arquivo ao lado de page.json: png, jpg, webp, avif, gif ou svg; ou uma URL https) e alt (160): o que a imagem mostra. | Uma captura de tela real, uma foto, uma ilustração. |
window | title (40), subtitle (60), sidebar (até 6 itens, 20 cada; active escolhe o destacado, padrão 0), rows (1 a 6 de meta (8), label (48), tag (14), fill true/false). | A tela principal de um app, desenhada no estilo da página. |
stats | items: 2 a 4 de value (10) e label (60). | Números que são verdadeiros e com fonte. |
code | code (até 14 linhas de 64 caracteres; linhas com $ têm um prompt, # e // são esmaecidas) e title (24) para a barra do quadro, ex. "Terminal". | Comandos de instalação e primeiro uso, um arquivo de configuração. |
Dicas de escrita: o título diz o que o leitor ganha, nas palavras dele, com o mínimo de palavras possível; deixe uma palavra carregar o itálico. Títulos de colunas são afirmações curtas ("Silêncio por padrão."), não nomes de funcionalidades. Todo número, citação, cliente e afirmação deve vir da pessoa, do README ou de uma fonte para a qual ela aponte. Uma figura window deve mostrar o que o produto realmente faz; suas linhas podem ser exemplos inventados, como uma tela de amostra, então diga isso na legenda se nomes aparecerem.
4. Construir
node <skill>/scripts/build.mjs page.json out
Ele lista todo problema no page.json de uma vez (campos ausentes, texto acima do limite, um link de navegação para um id que não está na página, cores que não contrastam) e não escreve nada até que sejam corrigidos. Então ele diz onde o formulário envia, e lista o que apenas a pessoa pode confirmar: a citação, os números, as figuras de janela.
5. Verificar e olhar
node <skill>/scripts/check.mjs out/index.html
node <skill>/scripts/try-form.mjs out/index.html # com um formulário de lista de espera
node <skill>/scripts/screenshot.mjs out/index.html
check.mjscarrega a página em 390, 768, 1024 e 1440 px e deve dizerokem cada: nada mais largo que a tela ou cortado, contraste legível em todo lugar, texto alternativo, um campo de formulário rotulado, um h1, nenhum nível de heading pulado. Linhas marcadas com·merecem uma olhada, mas não falham.try-form.mjsinscreve[email protected]em Chrome headless contra um substituto para o serviço de formulário nesta máquina (nada atinge o serviço real), e mostra o que foi enviado, o que o visitante vê depois, e o que ele vê quando o serviço falha. Deve terminar comThe form works.screenshot.mjssalvaout/screens/desktop.pngemobile.png. Olhe para ambos: a primeira tela diz o que é, algum título quebra feio, um spread está desequilibrado (encurte o texto ou a figura)?
6. Colocar no ar
Envie out/index.html e out/assets/ para qualquer host estático: Netlify, Vercel, Cloudflare Pages, GitHub Pages, S3. Para manter a página no repositório do projeto, adicione o build aos seus scripts, ex. "landing": "node tools/landing/build.mjs landing/page.json public" após copiar build.mjs, inline.mjs, markup.mjs e color.mjs para tools/landing/.
Com uma lista de espera, inscreva-se uma vez na página ao vivo com o próprio endereço da pessoa e confirme que chega ao serviço. Vincule uma política de privacidade a partir de footer.links quando a página coletar e-mails; peça a URL à pessoa.
Solução de problemas
build: fix page.json first: cada linha nomeia o campo e o que mudar.points at nothing on the page: um link de navegação ou botão para#algoque não é umidaqui. Spreads de funcionalidades recebem um com"id"; os próprios da página são#join(o formulário),#highlights,#faqe#closing.can't read page.json: O JSON tem um erro de sintaxe. Valide-o em jsonlint.com ou em um editor.Chrome not found: Instale Chrome, ou definaCHROME_PATHcom o caminho completo para o executável.form test failed: O formulário não envia ou a resposta não é a esperada. Verifique os logs e teste manualmente.