Communitygithub.com

kyjongSNSoft/landing-page-skill

Use quando o usuário fornece um link/arquivo do Figma e deseja uma landing page promocional/marketing gerada a partir dele (SNSoft 活动落地页) — produz HTML + CSS + JS estáticos prontos para deploy com layout em rem, imagens exportadas recortadas e runtime fixo de analytics/postMessage. Acionadores - /figma-landing-page, "figma 落地页", "把这个 Figma 做成落地页", link do Figma + solicitação de landing page.

O que é landing-page-skill?

Esta skill, `kyjongSNSoft/landing-page-skill`, é uma ferramenta especializada para desenvolvedores que precisam converter designs do Figma em landing pages promocionais estáticas e prontas para deploy. Ela automatiza todo o fluxo de trabalho: desde a extração de informações do design (através de MCP ou API REST) até a geração de código HTML, CSS e JavaScript, exportação de imagens e comparação visual para garantir fidelidade. A skill impõe um contrato rígido sobre a estrutura do código gerado, incluindo placeholders específicos (como `__PAGE_TITLE__`) e uma arquitetura de três arquivos JavaScript (tool.js, pm_main.js, main.js) para adaptação rem, ponte postMessage e lógica de negócios, respectivamente. Ela suporta layouts de tela única (H5) e dupla (H5 + PC), com pontos de interrupção em 576px. O processo inclui uma única interrupção de confirmação para que o usuário valide nomes, diretório de saída, lista de recortes e interações inferidas. Caso a chamada MCP do Figma não esteja disponível ou o orçamento de chamadas se esgote, a skill recai automaticamente para a API REST e, em última instância, para exportação manual pelo usuário. Ela é ideal para fluxos de trabalho de alto volume onde consistência, velocidade e aderência a um modelo de projeto fixo são críticos.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/kyjongSNSoft/landing-page-skill/tree/main/skill

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Prévia

Do README da skill

landing-page-skill preview

Documentação

Figma → Landing Page

Gere uma landing page promocional estática e pronta para deploy a partir de um design do Figma: index.html + css/main.css + js/{tool,pm_main,main}.js + images/*.webp.

Chamada: /figma-landing-page <link-figma> [nome-da-campanha] [diretório-de-saída]

Contrato fixo (não desviar em nenhuma circunstância):

  • Exatamente 3 placeholders de modelo: __PAGE_TITLE__, __FUNCTION_NAME__ (ambos em main.js; title também aparece em index.html), __PC_BASE__ (em tool.js; 375 = apenas frame H5; 1920 = frames H5+PC).
  • Os elementos CTA devem obrigatoriamente ter a classe .join-btn (contrato do seletor fixo do JS), coexistindo com as classes BEM.
  • Breakpoint de 576px unificado em três lugares: branch rem do JS, @media (min-width: 576px) no CSS, detecção de plataforma.
  • Normalização de px: H5 px × 375 ÷ largura-frame-H5 ÷ 100 = rem; PC px × 1920 ÷ largura-frame-PC ÷ 100 = rem.
  • Os três arquivos JS do modelo (tool.js adaptação rem / pm_main.js ponte postMessage / main.js camada de negócios da campanha, ordem de carregamento é esta) são fixos e não devem ser alterados em nenhum caractere; a interação da página é inserida apenas sob o marcador // === Page-specific interactions === em main.js (dentro da IIFE, pode usar diretamente $p/pm/track/Date.prototype.format).
  • Regras detalhadas (limites de recorte, nomes de classes, tabela de inferência de interação) em references/patterns.md, padrão de entrega em references/checklist.md — leia ambos os arquivos antes de gerar.

Etapa 1 — Analisar entrada e verificar ambiente

  1. Extrair file key e node-id do link. Converter hífen em node-id para dois pontos (123-456 → 123:456) antes de chamar qualquer API do Figma; se a API retornar 404/resultado vazio, verifique esta etapa primeiro.
  2. Três verificações de ambiente (se não passarem, corrija antes de continuar):
    • Figma MCP conectado (se não, guie o usuário na autenticação; interações de autenticação não contam como a "única interrupção" da porta de confirmação). Primeiro chame whoami (isento de cota) para confirmar o tipo de assinatura: assinaturas Viewer/Collab ou Starter têm apenas 6 chamadas MCP/mês — quando o orçamento estiver apertado, pule o MCP e vá diretamente para a rota REST das Etapas 2/4 (PAT armazenado em ~/.figma_token; se ausente, peça ao usuário para gerar um em Figma Settings → Security e escrevê-lo em seu terminal para evitar o histórico de chat).
    • which cwebp — se ausente, informe o usuário: brew install webp; se o usuário se recusar a instalar, toda a página retorna para produtos PNG e anota no relatório de entrega.
    • node -e "require('playwright-core')" — se ausente, execute npm i playwright-core no diretório scratchpad; reutilize o Chrome do sistema (channel: 'chrome'), não baixe binários do navegador.
  3. Diretório de saída padrão: ./output/<slug-do-nome-da-campanha>/ (todos os produtos da skill ficam em output/; se o nome da campanha não for fornecido, inferir do nome da página/frame do Figma e confirmar na porta de confirmação). Se o diretório já existir e não estiver vazio, não interrompa agora — a confirmação de substituição faz parte do conteúdo da porta de confirmação.

Etapa 2 — Inventariar o design

  • Use ferramenta de metadados esparsos (tipo get_metadata) para ler a árvore de nós; não puxe o contexto de design completo do frame raiz de uma vez.
  • Quando MCP não estiver disponível/orçamento esgotado: REST GET /v1/files/<key>/nodes?ids=<node> (sem depth = JSON de subárvore completa, contém texto completo, fontes, valores originais de gradiente de fills, bbox exato — informações mais completas que get_metadata). Armazene localmente e analise repetidamente; uma única chamada cobre todo o percurso; valores de cor/gradiente/texto do CSS vêm diretamente deste JSON, sem necessidade de get_code.
  • Identificação de frames: largura ≤ 480 → frame H5; ≥ 1200 → frame PC; frames que não podem ser determinados entram na porta de confirmação. Apenas frame H5 → __PC_BASE__ = 375; frames H5+PC → __PC_BASE__ = 1920.
  • Produzir lista de ativos: lista de seções (hero, banner, steps, tnc…); cada nó marcado como recorte / texto real / componente interativo (regras de determinação em references/patterns.md).
  • Marcar todos os CTAs (Join Now / Registrar / botões do tipo Sign Up) — eles devem receber a classe .join-btn.

Etapa 3 — Porta de confirmação (única interrupção antes da geração no fluxo normal)

Uma única mensagem lista tudo abaixo, obtém a confirmação do usuário de uma vez; depois disso, não interrompe até a entrega:

  • Nome da campanha, valor de __PAGE_TITLE__, valor de __FUNCTION_NAME__ (ex.: WinsdayBillionDropLandingPage)
  • Diretório de saída (se não estiver vazio, confirme aqui a substituição)
  • Lista de recortes (nó → images/<nome>.webp)
  • Lista de nós CTA
  • Lista de interações: cada item com justificativa de inferência e parâmetros necessários (contagem regressiva → tempo limite/comportamento ao expirar; carrossel → reprodução automática/intervalo; pop-up → momento de disparo; veja tabela em references/patterns.md). Parâmetros que o design não consegue inferir devem ser preenchidos pelo usuário aqui; nós que não podem ser categorizados marcar como "estático".
  • Itens de frame com identificação duvidosa

Etapa 4 — Exportar recortes (cadeia de fallback de quatro níveis, degradar conforme disponibilidade)

  1. MCP download_assets (quando o orçamento da assinatura for suficiente): máximo de 20 nós por lote, scale 2x, formato png; baixar URLs temporárias com curl.
  2. Renderização REST GET /v1/images/<key>?ids=…&format=png&scale=2: ids em lote separados por vírgula, mas máximo de 4 nós grandes por lote (se exceder, reportar "Render timeout"); 429 = orçamento de renderização da assinatura esgotado (assinatura Viewer dispara após cerca de 12 imagens, janela de hora); mudar para o próximo nível, não esperar.
  3. Endpoint de imagens originais REST GET /v1/files/<key>/images: retorna o mapeamento imageRef → URL de imagem original do arquivo inteiro, usa o orçamento do arquivo, quase sem limitação de renderização. Adequado para todos os nós de preenchimento de imagem (fotos/adesivos/ícones — o fills[].imageRef no JSON do nó corresponde para obter resolução original, muitas vezes muito maior que 2x, recortar/diminuir alpha conforme o scaleMode do fill e redimensionar). Não adequado para nós de composição vetorial (painéis/fitas).
  4. Exportação manual pelo usuário (cota zero): peça ao usuário para selecionar o nó no Figma e exportar. Preferir formato SVG — parte vetorial infinitamente nítida, bitmap incorporado em base64 na resolução original (pode extrair com regex <image> e decodificar, é a melhor fonte para elementos transparentes). Pipeline de rasterização SVG→bitmap 2x: copiar SVG para diretório temporário (nome de arquivo seguro em kebab-case, nomes originais geralmente contêm &/espaços); escrever um HTML wrapper no mesmo diretório <img src="./x.svg"> (abrir SVG diretamente com file:// ou referência de arquivo entre diretórios será recusado pelo Chrome); tirar screenshot com playwright deviceScaleFactor:2 + omitBackground:true para obter PNG transparente.
  • Geral: converter para webp cwebp -q 80; nomear semanticamente em kebab-case, sem hash; nós puramente gradiente/cor sólida ler diretamente do JSON e escrever CSS, sem gerar imagem.
  • Atenção: o viewBox do SVG exportado do Figma pode conter sombra/sangria (maior que o bounding box do nó); ao posicionar o contêiner pelo bounding box do nó, deixe a imagem transbordar proporcionalmente, não achatar.
  • Falha na exportação de imagem única: tentar 2 vezes → degradar para próximo nível de fallback; pular apenas se toda a cadeia falhar e registrar no relatório de entrega.

Etapa 5 — Gerar código

  • Partir de assets/template/: o conteúdo de base.css serve como esqueleto inicial de css/main.css (o produto final tem apenas um main.css, não emite base.css separadamente).
  • index.html: substituir <title>; link de fonte trocar pela fonte do design (se não encontrar no Google Fonts, escolher a mais próxima e registrar no relatório); dentro de #app, gerar estrutura semântica por seção, nomes de classe BEM (.hero__bg, .banner__headline), elementos CTA com classe extra join-btn.
  • css/main.css: valores retirados das dimensões/cores/gradientes exatos do Figma (a saída HTML+CSS simples do get_code pode ajudar a obter valores), normalizar px primeiro e depois escrever em rem; fundo background-image, imagens de conteúdo <img>. Em páginas de dois frames: regras H5 primeiro, todas as sobreposições PC dentro de @media (min-width: 576px).
  • js/: copiar os três arquivos do modelo (tool.js / pm_main.js / main.js), substituir 3 placeholders (__PC_BASE__ em tool.js, os outros dois em main.js); código de interação confirmado inserido abaixo do marcador em main.js.
  • Elementos no design que sangram até a borda do frame e são cortados (bbox ultrapassa a largura do frame), o contêiner deve ter overflow: hidden para reproduzir o corte do frame, caso contrário a página transborda horizontalmente.
  • Autoverificação: node --check js/*.js nos três arquivos deve passar.

Etapa 6 — Comparação de screenshot iterativa (por seção, máximo 3 rodadas)

  • Iniciar servidor local no diretório de saída: python3 -m http.server <porta>.
  • Escrever o seguinte script de screenshot no scratchpad e usá-lo para capturar screenshots por seção (coordenadas de clip obtidas do DOM: dentro de page.evaluate, para cada elemento de seção, obter getBoundingClientRect):
// shot.mjs <url> <out.png> <width> <dsf> [clipY clipH]
import { chromium } from 'playwright-core';
const [url, out, width, dsf, clipY, clipH] = process.argv.slice(2);
const browser = await chromium.launch({ channel: 'chrome' });
const page = await browser.newPage({
  viewport: { width: +width, height: 800 },
  deviceScaleFactor: +dsf,
});
await page.goto(url, { waitUntil: 'networkidle' });
await page.screenshot(clipY === undefined
  ? { path: out, fullPage: true }
  : { path: out, clip: { x: 0, y: +clipY, width: +width, height: +clipH } });
await browser.close();
  • Comparação H5: local width 375, dsf 2; lado do Figma usar download_assets para exportar 2x png por nó de seção como imagem de comparação (imagens de comparação vão para scratchpad, não entram em images/).
  • Comparar lado a lado por seção, corrigir cada diferença; no máximo 3 rodadas, se ainda houver diferenças, registrar no relatório de entrega.
  • Após a convergência da comparação, fazer uma regressão rápida de página inteira com width 414 (dsf 2) para confirmar que não há desalinhamento/transbordamento (checklist exige duas faixas: 375/414).
  • Screenshot de frame inteiro apenas para impressão no relatório de entrega, nunca como base para julgamento de diferenças (frame inteiro longo será subamostrado a ponto de não dar para ver tamanho da fonte/diferenças de cor).
  • Páginas de dois frames: adicionalmente, com width 1920, dsf 1, repetir a comparação por seção acima para o layout PC (exportar imagem 1x do frame PC); e fazer regressão rápida de página inteira com width 1280 (checklist de dois frames exige 1280/1920).
  • Verificação adicional: console do navegador sem erros (page.on('console') ou DevTools).

Etapa 7 — Entrega

O relatório de entrega contém:

  1. Árvore do diretório de saída
  2. Resultados item a item do references/checklist.md
  3. Diferenças conhecidas restantes (não eliminadas em 3 rodadas)
  4. Caminhos das imagens de comparação por seção
  5. Fallbacks utilizados (png em vez de webp, fontes aproximadas, recortes pulados)

Referência rápida de tratamento de erros

CenárioTratamento
Figma MCP não conectado/autenticação expiradaGuiar autenticação e continuar a partir do passo interrompido (não conta como interrupção da porta de confirmação)
API retorna 404/vazio com node-idVerificar conversão de hífen para dois pontos
Falha ao exportar recorte/429 de limiteTentar 2 vezes → degradar para próximo nível de fallback (ver Etapa 4) → se ainda falhar, pular + registrar no relatório
cwebp ausente e usuário recusa instalaçãoProduto regride para images/*.png + registrar no relatório
Estrutura do frame não reconhecidaIncluir na porta de confirmação e perguntar ao usuário (precisa do node-id específico)
Diretório de saída não vazioConfirmar substituição junto dentro da porta de confirmação

Habilidades Relacionadas