Communitygithub.com

braxtonROSE4/clonar-cualquier-sitio-web

Realiza ingeniería inversa y clona píxel a píxel cualquier sitio web en vivo, ya sea una sola página de aterrizaje o un sitio completo. Captura el DOM, tokens de diseño CSS, activos, fuentes y datos de configuración JS compilados de la página en vivo, revierte animaciones de desplazamiento e interacciones con estado, reconstruye (espejo HTML sin procesar para sitios de exportación estática como Webflow/Framer, componentes Next.js para sitios con framework JS) y luego demuestra fidelidad con un benchmark puntuado (diferencia geométrica con la misma sonda, cobertura de activos/fuentes/animaciones, división de capturas de pantalla). Usa esta habilidad cuando el usuario quiera clonar, replicar, reconstruir o hacer ingeniería inversa del diseño o comportamiento de un sitio web.

¿Qué es clonar-cualquier-sitio-web?

Esta habilidad permite a un agente de IA (como Claude Code, Cursor o Codex) clonar sitios web completos píxel a píxel simplemente a partir de su URL, demostrando la fidelidad con un benchmark puntuado en lugar de afirmaciones subjetivas. Es útil para desarrolladores y diseñadores que necesitan replicar con precisión el diseño, la tipografía, las animaciones y las interacciones de un sitio existente, ya sea para análisis, reutilización de componentes o recreación de efectos complejos. La habilidad es compatible con plataformas como Claude Code, Cursor y Codex a través del runtime `ego-browser`, y ofrece dos rutas de reconstrucción: un espejo HTML sin procesar para sitios de exportación estática (Webflow, Framer) y reconstrucción basada en componentes para sitios con frameworks JS (Next.js, Remix). El flujo de trabajo implica la captura estática del DOM, CSS, fuentes y activos, la ingeniería inversa de animaciones e interacciones, y la reconstrucción con un riguroso proceso de validación mediante sondas de medición repetibles.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add braxtonROSE4/clone-any-website

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

clonar-sitio-web

Clona cualquier sitio web en vivo 1:1 (diseño, tipografía, activos, animaciones de desplazamiento, interacciones con estado) a partir únicamente de su URL, y demuestra la fidelidad con un benchmark puntuado en lugar de afirmarlo.

Dependencia de tiempo de ejecución y arranque

Cada operación en páginas en vivo se ejecuta como ego-browser nodejs <<'EOF' ... EOF en Bash, utilizando las fachadas precargadas page, browser y taskSpaces del runtime ego lite.

El runtime no es intercambiable, porque el método depende de él de tres maneras. El bucle a nivel de píxel necesita la misma sonda ejecutándose en el mismo runtime en el original y en el clon, o los números de diferencia no significan nada. El bucle de corrección necesita espacios de tarea: el agente prueba en sus espacios aislados mientras el usuario navega simultáneamente por el original y el clon en los suyos, toma el control de cualquier espacio para una verificación visual y lo devuelve, sin que ninguna parte compita por el navegador. Y cada script de sonda y advertencia en esta habilidad está calibrado contra el comportamiento medido de este runtime. Por eso, si falta el runtime, se debe instalar ego lite en lugar de usar un sustituto.

  1. Si la habilidad ego-browser está instalada en este entorno, cárgala antes de la Fase 0 y obedece todas sus reglas de corrección. Esta habilidad es un envoltorio alrededor de ella; en caso de conflicto, las reglas de la habilidad ego-browser prevalecen para la mecánica del navegador, mientras que las reglas de esta habilidad prevalecen para el flujo de trabajo de clonación.
  2. Si solo esta habilidad está presente, funciona de forma independiente. El contrato es la CLI ego-browser (proporcionada por la aplicación ego lite). En un entorno nuevo o desconocido, verifica una vez con command -v ego-browser antes de la Fase 0.
  3. Cuando la CLI no está presente, no improvises. Detente, lee references/install.md y guía al usuario a través de la instalación de ego lite (descarga mediante scripts/install-ego-browser.sh, luego el usuario finaliza la incorporación en la GUI de la aplicación, que registra la CLI; espera su confirmación, verifica con command -v ego-browser y luego reanuda). Nunca recurras a Playwright, otro navegador, WebFetch o cualquier otra ruta de automatización; los resultados de la sonda de un runtime diferente no son comparables y las advertencias de entorno de esta habilidad ya no se aplican.
  4. Después del primer comando exitoso, asume que el runtime está listo para el resto de la sesión; solo investiga cuando un comando real genere un error.

El método en una frase: trata el sitio en vivo como una verdad fundamental que se puede consultar, no una imagen que se observa a simple vista. Extrae el DOM real, los tokens CSS reales, los keyframes reales, las fuentes reales y los datos de configuración reales de la página en ejecución, reconstruye a partir de esos hechos, luego ejecuta la misma sonda de medición en el original y en el clon y compara los números hasta que converjan.

Mapa de archivos: scripts de sonda copiados y pegados en references/probes.md; protocolo de benchmark en references/eval.md; guía de instalación de ego lite en references/install.md (instalador incluido en scripts/install-ego-browser.sh); plantilla de diseño de herramientas/funciones en references/tool-design-template.md; implementaciones canónicas de herramientas en tools/ (registradas en tools/manifest.json); evaluador en scripts/eval_score.py; divisor de capturas de pantalla en scripts/slice.py.

Modelo de ejecución

  • Un espacio de tarea para todo el trabajo. taskSpaces.useOrCreate('revertir <sitio>') al inicio de cada heredoc; el mismo nombre en todas las invocaciones. No lo complete entre sondas; completa con { keep: false } solo después de la aceptación final. Si el usuario toma el control del espacio, eso es una parada forzosa: informa del estado y espera, nunca uses takeOver por tu cuenta.
  • Agrupa por fase, no por acción. Un heredoc debe completar una sonda completa (abrir, congelar videos, medir en cada profundidad, imprimir). Divide las invocaciones solo en límites reales: trabajo de shell entre trabajo de navegador (descargas curl, greps, Python), confirmación del usuario o inspección visual de una imagen guardada.
  • Artefactos a archivos, resúmenes a stdout. Cada sonda escribe su JSON/HTML completo en reference/ y registra en console.log solo conteos y rutas. Nunca vuelques un DOM completo, un archivo CSS o una tabla de geometría en la conversación.
  • Cada script de sonda es autónomo. La selección del espacio de tarea y browser.openOrReuseTab(url, { wait: true, timeout: 30000 }) al inicio, cada vez; el estado del runtime no persiste entre heredocs.
  • Solo rutas absolutas dentro de los heredocs. El proceso nodejs de ego no hereda el cwd del shell; las rutas relativas en fs.writeFileSync generan ENOENT. Define una constante ROOT al inicio de cada script.

Inicio rápido: arranque de reconocimiento

Una invocación captura la verdad fundamental desde la que comienza una reconstrucción. Adapta la URL y las rutas; la forma compuesta es el punto clave.

mkdir -p reference/{dom,css,js,screenshots} && ego-browser nodejs <<'EOF'
const fs = await import('node:fs')
const ROOT = '/abs/path/to/project'  // el nodejs de ego no hereda el cwd del shell
await taskSpaces.useOrCreate('revertir example.com')
await browser.openOrReuseTab('https://example.com', { wait: true, timeout: 30000 })

// CONGELA los videos de reproducción automática PRIMERO: saturan el hilo de renderizado y las evaluaciones posteriores se agotan.
await page.evaluate(() => {
  const freeze = () => document.querySelectorAll('video').forEach(v => v.pause())
  freeze(); setInterval(freeze, 400)
})

// Protege el viewport: w/h de 0 produce silenciosamente capturas de pantalla vacías y rectángulos basura.
const info = await page.info()
if (!info.w || !info.h) throw new Error('El viewport es 0, restaura la pestaña real antes del reconocimiento: ' + 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

Luego trabajo en shell: descarga cada URL de CSS/fuente/JS a reference/ y divide la captura de pantalla por sección con python3 scripts/slice.py reference/screenshots/original-full.png reference/dom/outline.json reference/screenshots/original/.

Flujo de trabajo

Fase 0, configuración

Directorio del proyecto con reference/{dom,css,js,screenshots}/ para artefactos de reconocimiento (nunca enviados, excluidos de cualquier push del repositorio); servidor de desarrollo en un puerto fijo en segundo plano para que el usuario pueda revisar continuamente. Crea manualmente la estructura de Next.js cuando public/ ya contenga activos descargados; create-next-app sobrescribe el directorio.

Antes de servir, lsof -iTCP:<puerto> -sTCP:LISTEN (un servidor sobrante de un trabajo de clonación anterior podría responder de manera convincente en tu puerto), y antes de cualquier sonda del clon, verifica que document.title coincida; una respuesta curl plausible no es prueba de que la pestaña del navegador muestre tu página.

Fase 1, captura estática

Ejecuta el arranque de reconocimiento, luego completa los vacíos (scripts completos en references/probes.md):

  • Tokens de diseño: busca en el CSS descargado --brand-*, --font-size-*, --color-*, escalas de espaciado. Lee tamaños y colores de los tokens, nunca los estimes a partir de capturas de pantalla. Un token que esperas pero no encuentras suele estar en un archivo CSS diferente; busca en todos ellos antes de concluir que no existe.
  • Fuentes: @font-face a menudo se inyecta mediante JS en tiempo de ejecución, por lo que buscar en el HTML guardado no prueba nada. En la página en vivo, combina tres fuentes: performance.getEntriesByType('resource') filtrado por extensiones de fuentes, document.fonts para familia/estado/peso, y un recorrido de document.styleSheets para CSSFontFaceRule para mapear familia a peso a src. Descarga con curl --globoff (los nombres de archivo entre corchetes rompen el globbing de curl). Autoalójate en public/fonts/.
  • Activos: enumera img[src], srcset, video src, URLs de background-image, SVGs en línea. Decodifica /_next/image?url=... de vuelta a las rutas originales. Refleja las rutas originales bajo public/. Extrae SVGs en línea textualmente, no los redibujes.
  • Contenido simulado/de UI de producto: los paneles de control, editores y paneles de tarjetas obtienen su contenido de objetos de configuración en chunks JS compilados. Busca en los chunks descargados una cadena visible; el objeto de configuración junto al acierto contiene el conjunto de datos completo (todas las variantes de carrusel, todas las filas), mucho más confiable que las capturas de pantalla que pierden el estado cargado de forma diferida.

Las capturas de pantalla de referencia siguen las reglas de Corrección a continuación: una captura fullPage en scroll 0 dividida por sección con scripts/slice.py, videos congelados primero, barras con estado reiniciadas primero.

Fase 2, movimiento e interacción inversa

Trabaja de lo más barato a lo más caro; detente tan pronto como el efecto esté explicado:

  1. Análisis CSS estático (gratuito, ya descargado): busca animation-timeline|view-timeline|scroll-timeline|@keyframes. Un acierto en animation-timeline: view() significa animaciones nativas CSS impulsadas por desplazamiento: copia keyframes y rangos textualmente, no se necesita JS.
  2. Inventario en tiempo de ejecución: document.getAnimations({ subtree: true }), la verdad fundamental. Por animación: effect.getKeyframes(), timeline.constructor.name (ViewTimeline es impulsado por desplazamiento, DocumentTimeline es impulsado por tiempo), rangeStart/rangeEnd, elemento objetivo. Parámetros por elemento como --parallax-from: 6% viven en estilos en línea.
  3. MutationObserver más desplazamiento real de rueda para efectos activados por JS: attributeFilter: ['class','style','src'], desplaza toda la página con page.mouse.wheel, registra mutaciones. Cero mutaciones de clase en un desplazamiento completo prueba que los efectos son CSS puro, lo que simplifica enormemente la reconstrucción.
  4. Muestreo de estado en múltiples profundidades para máquinas de estado fijas/pegajosas (barras de entrada flotantes, encabezados plegables): captura la subárbol completa del elemento (rectángulo de cada hijo, opacidad, radio, fondo, sombra) a varias profundidades de desplazamiento en ambas direcciones, luego compara las capturas entre estados. Las comprobaciones solo de posición pasan por alto los cambios de forma; la transición de estado es la interacción.

Fase 3, reconstrucción

Elige la ruta de reconstrucción primero según el tipo de sitio. Los sitios de exportación estática (Webflow, Framer: atributo data-wf-site, CDN website-files.com/framerusercontent.com) se clonan con la máxima fidelidad como un espejo HTML sin procesar, no una reconstrucción de componentes: descarga el HTML del servidor previo a la hidratación como esqueleto (el DOM capturado en vivo ya está hidratado — los clones del carrusel se insertaron, los caracteres de SplitText se dividieron — y se inicializa dos veces cuando los scripts se vuelven a ejecutar), reescribe cada URL de CDN a copias autoalojadas, elimina scripts de analítica/consentimiento, mantiene el runtime funcional (JS del sitio, GSAP, librerías de carrusel) autoalojado. Cuatro reglas para esa ruta:

  • Los activos pueden abarcar múltiples carpetas de CDN (bibliotecas de medios compartidas); reescribe cualquier cdn-host/<carpeta>/<archivo> por nombre base, no por el prefijo de la carpeta principal del sitio.
  • Elimina integrity/crossorigin de cada etiqueta de recurso reescrita: el hash SRI se calculó contra los bytes originales, y el navegador rechaza el archivo modificado silenciosamente — el síntoma es una página sin estilo (la altura del documento explota, document.fonts está vacío) sin error visible para la sonda.
  • La eliminación de scripts de rastreo mediante una lista de palabras clave mata scripts funcionales que simplemente mencionan una API de analítica con una degradación elegante (un script en el encabezado que controlaba el intercambio de texto de detección de SO de los botones de descarga hacía referencia a PostHog); audita la lista de scripts eliminados y añade los funcionales a la lista blanca.
  • Los scripts de experimentos no deterministas (Math.random() divisiones de tráfico, comprobaciones de redirección) permanecen eliminados aunque sean funcionales; hacen que las ejecuciones del benchmark no sean repetibles.

Para sitios con framework JS (Next.js, Remix — una discrepancia de hidratación hace que un espejo sea inviable), reconstruye por componentes:

  • Un componente por sección de nivel superior, nombrado según el contenido de negocio de la sección.
  • Los tokens de la Fase 1 van a globals.css tal cual; las fuentes se autoalojan con el mapeo de peso real.
  • Refleja la estrategia de montaje del DOM del original, no solo lo que es visible: los originales mantienen todos los marcos del carrusel, las variantes de rotación y las paredes de avatar montados (ocultos), mientras que un clon de representación condicional muestra los mismos píxeles con una fracción de los elementos, luego falla en los recuentos de medios por sección en el benchmark. Iguala los recuentos de elementos por sección contra el DOM del original, no contra su captura de pantalla.
  • Replica la jerarquía de contenedores del original, no solo sus imágenes. sticky se limita a su padre: una navegación que debe sobrevivir hasta el pie de página necesita un padre que abarque toda la página; un panel con efecto de cortina necesita un padre que comience donde comienza el efecto, o se fijará desde la primera pantalla. Cuando una sección se rompe después de la reestructuración, sospecha primero de un cambio en el ámbito de sticky o de contexto de apilamiento.
  • Los elementos fijos al viewport (barras de chat flotantes) son contenedores fijos a nivel de cuerpo en originales bien construidos: usa un portal de React, nunca absolute dentro de una sección.
  • Los encabezados plegables que cambian la altura del documento luchan contra el anclaje de desplazamiento de Chrome y producen vibraciones. Arquitectura robusta: un marcador de posición de altura constante en el flujo (la altura del documento nunca cambia) con el encabezado interno cambiando a fixed más una animación de deslizamiento una vez que se ha desplazado completamente fuera de la vista. Si la altura debe animarse, añade overflow-anchor: none e histéresis entre los umbrales de colapso y expansión.
  • Bordes dentados decorativos (bordes de festón/sello): SVG de lado sólido volteado hacia el espacio con 1px de superposición en el vecino.

Skills relacionados