Communitygithub.com

braxtonROSE4/clone-any-website

Faça engenharia reversa e clone pixel-perfect qualquer site ao vivo, uma única landing page ou um site inteiro.

O que é clone-any-website?

Este skill permite que um agente de IA clone qualquer site ao vivo com fidelidade pixel-perfect a partir de sua URL, capturando DOM, tokens de design CSS, assets, fontes e dados de configuração de JS compilado. Ele realiza engenharia reversa de animações de scroll e interações com estado, reconstrói o site (como um espelho HTML bruto para sites de exportação estática como Webflow/Framer, ou componentes Next.js para sites baseados em frameworks JS) e prova a fidelidade com um benchmark pontuado que compara geometria, cobertura de assets/fontes/animações e slicing de screenshots. O skill depende do runtime `ego-browser` para todas as operações de página ao vivo, garantindo que as medições sejam consistentes e comparáveis. Ele é ativado por comandos como "clone este website", "reverse esta landing page", "reconstrua esta página pixel-perfect", ou termos em chinês como "复刻网站", substituindo métodos ad-hoc de screenshot e estimativa visual.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add braxtonROSE4/clone-any-website

Perguntar na sua IA favorita

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

Documentação

clone-website

Clone qualquer site ao vivo 1:1 (layout, tipografia, assets, animações de scroll, interações com estado) a partir apenas de sua URL, e prove a fidelidade com um benchmark pontuado em vez de apenas afirmar.

Dependência de runtime e inicialização

Toda operação de página ao vivo é executada como ego-browser nodejs <<'EOF' ... EOF em Bash, usando as fachadas pré-carregadas page, browser e taskSpaces do runtime ego lite.

O runtime não é intercambiável, porque o método depende dele de três maneiras. O loop de nível de pixel precisa da mesma sonda executando no mesmo runtime no original e no clone, ou os números de diferença não significam nada. O loop de correção precisa de espaços de tarefa: o agente sonda em seus próprios espaços isolados enquanto o usuário navega simultaneamente pelo original e pelo clone nos deles, assume qualquer espaço para uma verificação visual e o devolve, sem que nenhum dos lados compita pelo navegador. E cada script de sonda e ressalva neste skill é calibrado contra o comportamento medido deste runtime. É por isso que um runtime ausente leva à instalação do ego lite em vez de um substituto.

  1. Se o skill ego-browser estiver instalado neste ambiente, carregue-o antes da Fase 0 e obedeça a todas as suas regras de correção. Este skill é um wrapper em torno dele; em qualquer conflito, as regras do skill ego-browser vencem para mecânica do navegador, as regras deste skill vencem para o fluxo de trabalho de clonagem.
  2. Se apenas este skill estiver presente, ele funciona de forma independente. O contrato é a CLI ego-browser (fornecida pelo aplicativo ego lite). Em um ambiente novo ou desconhecido, verifique uma vez com command -v ego-browser antes da Fase 0.
  3. Quando a CLI estiver faltando, não improvise. Pare, leia references/install.md e oriente o usuário na instalação do ego lite (baixe via scripts/install-ego-browser.sh, então o usuário finaliza a integração na GUI do aplicativo, que registra a CLI; aguarde a confirmação deles, verifique com command -v ego-browser, então retome). Nunca recorra a Playwright, outro navegador, WebFetch ou qualquer outro caminho de automação; os resultados da sonda de um runtime diferente não são comparáveis e as ressalvas de ambiente do skill não são mais válidas.
  4. Após o primeiro comando bem-sucedido, assuma que o runtime está pronto para o resto da sessão; investigue apenas quando um comando real gerar erro.

O método em uma frase: trate o site ao vivo como a verdade fundamental que você pode consultar, não uma imagem que você avalia visualmente. Extraia o DOM real, os tokens CSS reais, os keyframes reais, as fontes reais e os dados de configuração reais da página em execução, reconstrua a partir desses fatos, então execute a mesma sonda de medição no original e no clone e diferencie os números até convergirem.

Mapa de arquivos: scripts de sonda copiáveis em references/probes.md; protocolo de benchmark em references/eval.md; guia de instalação do ego lite em references/install.md (instalador anexado em scripts/install-ego-browser.sh); modelo de design de ferramenta/função em references/tool-design-template.md; implementações de ferramentas canônicas em tools/ (registradas em tools/manifest.json); score em scripts/eval_score.py; slicer de screenshots em scripts/slice.py.

Modelo de execução

  • Um espaço de tarefa para todo o trabalho. taskSpaces.useOrCreate('reverse <site>') no topo de cada heredoc; o mesmo nome em todas as invocações. Não complete entre sondas; complete com { keep: false } apenas após a aceitação final. Se o usuário assumir o espaço, isso é uma parada forçada: relate o estado e espere, nunca takeOver por conta própria.
  • Agrupe por fase, não por ação. Um heredoc deve terminar uma sonda inteira (abrir, congelar vídeos, medir em todas as profundidades, imprimir). Divida invocações apenas em limites reais: trabalho de shell entre trabalho de navegador (curl downloads, greps, Python), confirmação do usuário ou inspeção visual de uma imagem salva.
  • Artefatos para arquivos, resumos para stdout. Cada sonda escreve seu JSON/HTML completo em reference/, e console.log apenas contagens e caminhos. Nunca despeje um DOM completo, arquivo CSS ou tabela de geometria na conversa.
  • Cada script de sonda é autocontido. Seleção de espaço de tarefa e browser.openOrReuseTab(url, { wait: true, timeout: 30000 }) no topo, toda vez; o estado do runtime não sobrevive entre heredocs.
  • Apenas caminhos absolutos dentro de heredocs. O processo nodejs do ego não herda o cwd do shell; caminhos relativos fs.writeFileSync geram ENOENT. Defina uma constante ROOT no topo de cada script.

Início rápido: bootstrap de reconhecimento

Uma invocação captura a verdade fundamental a partir da qual uma reconstrução começa. Adapte URL e caminhos; a forma composta é o ponto.

mkdir -p reference/{dom,css,js,screenshots} && ego-browser nodejs <<'EOF'
const fs = await import('node:fs')
const ROOT = '/abs/path/to/project'  // nodejs do ego não herda o cwd do shell
await taskSpaces.useOrCreate('reverse example.com')
await browser.openOrReuseTab('https://example.com', { wait: true, timeout: 30000 })

// CONGELE vídeos em reprodução automática PRIMEIRO: eles saturam a thread de renderização e avaliações posteriores expiram.
await page.evaluate(() => {
  const freeze = () => document.querySelectorAll('video').forEach(v => v.pause())
  freeze(); setInterval(freeze, 400)
})

// Proteja o viewport: w/h 0 produz silenciosamente screenshots vazios e rects lixo.
const info = await page.info()
if (!info.w || !info.h) throw new Error('Viewport é 0, restaure a aba real antes do recon: ' + JSON.stringify(info))

const facts = await page.evaluate(() => ({
  html: document.documentElement.outerHTML,
  outline: Array.from(document.querySelectorAll('body section, body header, body footer, body main > div'))
    .map(el => { const r = el.getBoundingClientRect(); return {
      tag: el.tagName, cls: (el.className?.toString() || '').slice(0, 120),
      y: Math.round(r.top + scrollY), h: Math.round(r.height), w: Math.round(r.width) } })
    .filter(s => s.h > 40).sort((a, b) => a.y - b.y),
  cssUrls: performance.getEntriesByType('resource').map(e => e.name).filter(u => /\.css(\?|$)/.test(u)),
  fontFiles: performance.getEntriesByType('resource').map(e => e.name).filter(u => /\.(woff2?|ttf|otf)(\?|$)/.test(u)),
  jsChunks: performance.getEntriesByType('resource').map(e => e.name).filter(u => /\.js(\?|$)/.test(u)),
}))
fs.writeFileSync(ROOT + '/reference/dom/full-page.html', facts.html)
fs.writeFileSync(ROOT + '/reference/dom/outline.json', JSON.stringify(facts.outline, null, 2))
fs.writeFileSync(ROOT + '/reference/urls.json', JSON.stringify({ css: facts.cssUrls, fonts: facts.fontFiles, js: facts.jsChunks }, null, 2))

await page.evaluate(() => scrollTo(0, 0))
await page.waitForTimeout(800)
await page.screenshot({ path: ROOT + '/reference/screenshots/original-full.png', fullPage: true })

console.log(JSON.stringify({ sections: facts.outline.length, cssFiles: facts.cssUrls.length,
  fontFiles: facts.fontFiles.length, jsChunks: facts.jsChunks.length, htmlKB: Math.round(facts.html.length / 1024) }))
EOF

Então trabalho de shell: faça curl de cada URL CSS/fonte/JS para reference/, e fatie o screenshot por seção com python3 scripts/slice.py reference/screenshots/original-full.png reference/dom/outline.json reference/screenshots/original/.

Fluxo de trabalho

Fase 0, configuração

Diretório do projeto com reference/{dom,css,js,screenshots}/ para artefatos de recon (nunca enviados, excluídos de qualquer push de repositório); servidor de desenvolvimento em uma porta fixa em segundo plano para que o usuário possa revisar continuamente. Faça scaffold do Next.js manualmente quando public/ já contiver assets baixados; create-next-app sobrescreve o diretório.

Antes de servir, lsof -iTCP:<port> -sTCP:LISTEN (um servidor residual de um trabalho de clonagem anterior responde de forma convincente na sua porta), e antes de qualquer sonda do clone, afirme que document.title corresponde; uma resposta curl plausível não é prova de que a aba do navegador mostra sua página.

Fase 1, captura estática

Execute o bootstrap de reconhecimento, então preencha as lacunas (scripts completos em references/probes.md):

  • Tokens de design: grep no CSS baixado por --brand-*, --font-size-*, --color-*, escalas de espaçamento. Leia tamanhos e cores dos tokens, nunca os estime a partir de screenshots. Um token que você espera mas não encontra geralmente está em um arquivo CSS diferente; grep todos eles antes de concluir que não existe.
  • Fontes: @font-face muitas vezes é injetado por JS em tempo de execução, então fazer grep no HTML salvo não prova nada. Na página ao vivo, combine três fontes: performance.getEntriesByType('resource') filtrado para extensões de fonte, document.fonts para família/peso/status, e uma varredura document.styleSheets para CSSFontFaceRule para mapear família para peso para src. Baixe com curl --globoff (nomes de arquivo com colchetes quebram o globbing do curl). Auto-hospede em public/fonts/.
  • Assets: enumere img[src], srcset, video src, URLs de background-image, SVGs inline. Decodifique /_next/image?url=... de volta para caminhos originais. Espelhe caminhos originais sob public/. Extraia SVGs inline textualmente, não os redesenhe.
  • Conteúdo mock/UI de produto: dashboards, editores e painéis de cartão obtêm seu conteúdo de objetos de configuração em chunks JS compilados. Grep nos chunks baixados por uma string visível; o objeto de configuração ao lado do hit contém o conjunto de dados completo (todas as variantes de carrossel, todas as linhas), muito mais confiável do que screenshots que perdem estados carregados preguiçosamente.

Screenshots de referência seguem as regras de Correção abaixo: uma captura fullPage no scroll 0 fatiada por seção com scripts/slice.py, vídeos congelados primeiro, barras com estado resetadas primeiro.

Fase 2, engenharia reversa de movimento e interação

Trabalhe do mais barato primeiro; pare assim que o efeito for explicado:

  1. Análise estática CSS (gratuita, já baixada): grep por animation-timeline|view-timeline|scroll-timeline|@keyframes. Um hit em animation-timeline: view() significa animações nativas orientadas por scroll em CSS: copie keyframes e ranges textualmente, nenhum JS necessário.
  2. Inventário em tempo de execução: document.getAnimations({ subtree: true }), a verdade fundamental. Por animação: effect.getKeyframes(), timeline.constructor.name (ViewTimeline é orientado por scroll, DocumentTimeline é orientado por tempo), rangeStart/rangeEnd, elemento alvo. Parâmetros por elemento como --parallax-from: 6% residem em estilos inline.
  3. MutationObserver mais scroll real com roda para efeitos acionados por JS: attributeFilter: ['class','style','src'], role a página inteira com page.mouse.wheel, registre mutações. Zero mutações de classe em um scroll completo prova que os efeitos são CSS puro, o que simplifica massivamente a reconstrução.
  4. Amostragem de estado em múltiplas profundidades para máquinas de estado fixas/sticky (barras de entrada flutuantes, cabeçalhos que colapsam): tire um snapshot da subárvore inteira do elemento (rect de cada filho, opacidade, raio, fundo, sombra) em várias profundidades de scroll em ambas as direções, então diferencie os snapshots entre estados. Verificações apenas de posição perdem mudanças de forma; a transição de estado é a interação.

Fase 3, reconstrução

Escolha a rota de reconstrução primeiro pelo tipo de site. Sites de exportação estática (Webflow, Framer: atributo data-wf-site, CDN website-files.com/framerusercontent.com) clonam com maior fidelidade como um espelho HTML bruto, não uma reconstrução de componente: faça curl do HTML do servidor pré-hidratação como o esqueleto (o DOM ao vivo capturado já está hidratado — clones de carrossel inseridos, caracteres SplitText divididos — e duplica inicialização quando scripts são reexecutados), reescreva cada URL de CDN para cópias auto-hospedadas, remova scripts de analytics/consentimento, mantenha runtime funcional (JS do site, GSAP, bibliotecas de carrossel) auto-hospedado. Quatro regras para essa rota:

  • Assets podem abranger múltiplas pastas de CDN (bibliotecas de mídia compartilhadas); reescreva qualquer cdn-host/<folder>/<file> pelo nome base, não pelo prefixo da pasta principal do site.
  • Remova integrity/crossorigin de cada tag de recurso reescrita: o hash SRI foi computado contra os bytes originais, e o navegador rejeita o arquivo modificado silenciosamente — o sintoma é uma página sem estilo (altura do documento explode, document.fonts vazio) sem erro visível pela sonda.
  • A remoção de scripts de rastreamento por lista de bloqueio de palavras-chave mata scripts funcionais que apenas mencionam uma API de analytics com fallback gracioso (um script head que gerenciava a troca de texto de detecção de SO dos botões de download referenciou PostHog); audite a lista de scripts removidos e coloque os funcionais na lista de permissões.
  • Scripts de experimento não determinísticos (Math.random() divisão de tráfego, redirecionamentos canários) permanecem removidos mesmo sendo funcionais; eles tornam as execuções de benchmark não reproduzíveis.

Para sites baseados em frameworks JS (Next.js, Remix — a incompatibilidade de hidratação torna um espelho inviável), reconstrua por componente:

  • Um componente por seção de nível superior, nomeado após o conteúdo de negócio da seção.
  • Tokens da Fase 1 vão para globals.css como estão; fontes auto-hospedadas com o mapeamento de peso real.
  • Espelhe a estratégia de montagem do DOM do original, não apenas o que é visível: originais mantêm todos os quadros de carrossel, variantes de rotação e paredes de avatar montados (ocultos), enquanto um clone de renderização condicional mostra os mesmos pixels com uma fração dos elementos, então falha nas contagens de mídia por seção no benchmark. Corresponda as contagens de elementos por seção contra o DOM do original, não contra seu screenshot.
  • Replique a hierarquia de contêineres do original, não apenas seus visuais. sticky tem escopo para seu pai: um nav que deve sobreviver até o rodapé precisa de um pai que atravesse a página; um painel de revelação de cortina precisa de um pai que comece onde o efeito começa, ou ele fixa desde a primeira tela. Quando uma seção quebra após reestruturação, suspeite primeiro de uma mudança de escopo sticky ou contexto de empilhamento.
  • Elementos fixos no viewport (barras de chat flutuantes) são contêineres fixos de nível body em originais bem construídos: use um portal React, nunca absolute dentro de uma seção.
  • Cabeçalhos que colapsam que mudam a altura do documento lutam contra a ancoragem de scroll do Chrome e tremem. Arquitetura robusta: um placeholder de altura constante no fluxo (altura do documento nunca muda) com o cabeçalho interno mudando para fixed mais uma animação de deslizamento uma vez que esteja completamente scrollado para fora. Se a altura deve animar, adicione overflow-anchor: none e histerese entre os limites de colapso e expansão.
  • Bordas decorativas denteado (bordas scallop/stamp): SVG de lado sólido virado para o espaço com 1px de sobreposição no vizinho

Habilidades Relacionadas