¿Qué hace page-swarm-rebuild?
Versión 1.3.0 (módulo, complemento, hoja de estilos y este archivo; consulta CHANGELOG.md en el repositorio; SwarmRebuild.version).
Efecto introductorio solo de presentación. El DOM real de la página nunca se modifica: las capas se ocultan y revelan con una hoja de estilos en cascada en <head>, toda la animación ocurre en una superposición añadida a <html>, y ambas se eliminan al final. Sin dependencias, sin solicitudes de red (respetuoso con GDPR), sin desplazamiento de diseño, sin sonido, y la página nunca queda medio oculta (ver Protección).
Especificación del efecto original (línea de tiempo, elementos visuales, HUD, curva de desplazamiento): references/effekt-leiras.md (húngaro). Donde este archivo y ese difieran, este archivo tiene prioridad (las decisiones de producto se tomaron después de redactar la descripción).
Archivos
| Archivo | Propósito |
|---|---|
assets/swarm-rebuild.js | El módulo, código fuente legible (script clásico, establece window.SwarmRebuild; también importable desde un empaquetador). |
assets/swarm-rebuild.min.js, swarm-rebuild-debug.min.js, swarm-rebuild.min.css | Compilaciones minificadas para sitios HTML plano (scripts/build-min.cjs; el instalador las usa; los empaquetadores minifican las fuentes por sí mismos). |
assets/swarm-rebuild.css | Estilos de la superposición, todos con ámbito bajo #swarm-rebuild-root. |
assets/swarm-rebuild-debug.js | Complemento de depuración: barra de control, visita guiada automática, hooks de prueba. Nunca se carga para visitantes; se obtiene solo con ?rebuild-debug=1 / debug: true. Instálalo junto al módulo de todas formas (así es como pruebas en el sitio en vivo). |
assets/react/SwarmRebuild.jsx | Envoltorio React/Next.js del lado cliente + <SwarmRebuildHead /> (fragmento previo a la pintura); el complemento de depuración es un fragmento perezoso separado. |
assets/demo/ | Demo ficticio de portafolio oscuro (assets/demo/index.html, 214 capas (escritorio), 6.6 alturas de ventana gráfica, encabezado fijo). |
tests/index.html | Enlaces a todas las páginas de prueba en todos los modos (también la página de inicio de GitHub Pages). |
tests/pages/dental/ | Consultorio dental ficticio: tema claro, enlaces telefónicos, barra fija "Llámanos" + reserva (móvil), aviso fijo (escritorio). |
tests/pages/lang-*/ | Páginas ficticias en húngaro, árabe (derecha a izquierda), japonés y una rica en emojis (escritura en cualquier idioma). |
tests/pages/law/, accounting/, bootstrap/, spa/ | Patrones ficticios del mundo real: fuentes web, encabezado fijo, banners de consentimiento, iframe, imágenes perezosas, modo oscuro, página larga, desplazamiento-revelado, Bootstrap (npm), aplicación de una sola página, videos. |
tests/pages/nextjs/ | Aplicación ficticia Next.js 15 App Router: contador React (verificación de hidratación), botón de ayuda fijo. |
scripts/verify.cjs | Verificación con Playwright de una página (ver paso 4). |
scripts/run-tests.cjs | Ejecuta verify.cjs en las tres páginas de prueba, escritorio y móvil; imprime una tabla resumen. |
scripts/bench-fps.cjs | Velocidad de fotogramas de una versión anterior del módulo frente a la actual, misma máquina, ejecuciones intercaladas. |
scripts/build-site.cjs | Construye las tres páginas de prueba como un solo sitio estático (GitHub Pages) o lo sirve en la red local. |
scripts/next-app.cjs | Ayudante: prepara / construye la aplicación de prueba Next.js en una carpeta temporal. |
scripts/build-min.cjs | Construye los archivos .min y verifica el presupuesto de tamaño (necesita terser y csso de npm). |
scripts/perf.cjs | Métricas Lighthouse (LCP, CLS, TBT, Speed Index, accesibilidad, SEO) con y sin el efecto. |
scripts/sync-snippet.cjs | Copia el fragmento de cabeza del módulo en el envoltorio React, SKILL.md y las páginas de prueba. |
scripts/record-video.cjs | Graba el efecto como .mp4 / .webm para un portafolio (la visita guiada de depuración, barra de control oculta). |
scripts/project.cjs | Instala el efecto en un proyecto con una copia de seguridad en legacy/, lo elimina nuevamente, restaura los originales. |
scripts/test-project.cjs | Prueba el instalador: copia de seguridad, restauración después de un proyecto roto (idéntico en hash), desinstalación. |
Decisiones de producto (anulan el video de referencia)
- El modo principal es
scroll(el predeterminado): la construcción sigue el desplazamiento del visitante, y solo se construye lo que está en la ventana: un elemento comienza cuando al menos el 60 % de él está en pantalla (buildVisible), no se construye nada por debajo ni por encima de la vista, y ningún agente activo sale nunca de la pantalla. - Los visitantes nunca ven una barra de control y nunca obtienen un desplazamiento automático. La barra y la visita guiada viven en el complemento de depuración, cargado solo con
?rebuild-debug=1odebug: true.mode: 'tour'sin el complemento vuelve ascroll. - Siempre hay una salida sin controles visibles: Escape, Tabulador, Enter, cualquier otra tecla (excepto Mayús/Ctrl/Alt/Meta solas) y cualquier clic o toque muestran la página terminada de inmediato, sin animación ni desplazamiento de diseño.
prefers-reduced-motionsignifica que no hay efecto en absoluto (WCAG 2.2.2). - Las teclas de desplazamiento desplazan: Espacio, las flechas, Re Pág / Av Pág e Inicio / Fin (con el foco en la página misma, sin Ctrl / Alt / Meta) impulsan la construcción exactamente como la rueda del ratón. En un enlace, botón o campo enfocado, o con un modificador, finalizan el efecto como cualquier otra tecla. Tabulador, Enter y Escape siempre lo finalizan, por lo que los usuarios de teclado llegan al contenido real (y su orden de foco) en su primer Tabulador.
- El clic que finaliza el efecto nunca hace algo que el visitante no vio: si cae en contenido que aún no estaba terminado (oculto, o aún en construcción), se traga (
preventDefault+stopPropagation, en el ratón ya enpointerdown, por lo que no hay foco, ni enlace, ni acción de botón). Si cae en contenido terminado (visible, nada dentro de él o revelándolo aún en progreso — p.ej., un enlace telefónico, que se muestra desde el principio, o un botón construido), pasa como un clic normal y el efecto finaliza al mismo tiempo. Motivo: tragar cada clic haría que un enlace "Llámanos" visible fallara en el primer toque; dejar pasar cada clic seguiría enlaces que el visitante nunca vio. El desplazamiento táctil y la barra de desplazamiento nunca finalizan el efecto (desplazarse es cómo se impulsa la construcción). - Sin sonido. El módulo no tiene código de audio.
Modos
| modo | velocidad | comportamiento |
|---|---|---|
scroll (predeterminado) | 3x | Sin desplazamiento automático. Los agentes construyen solo lo que está en la vista: un elemento comienza cuando al menos buildVisible (60 %) de su altura está en pantalla; un elemento más alto que la pantalla cuando llena el 60 % de la pantalla, por lo que se construye de arriba a abajo a medida que entra. No se construye nada fuera de la vista y un agente activo nunca la abandona (un marco más alto que la pantalla se tira desde el borde de la pantalla). Después de un desplazamiento rápido (rueda, teclas, Inicio / Fin), la parte visible se completa en ~1-2 s: esas capas comienzan primero, se unen más agentes (hasta 8 por encima del plan) y las tareas se ejecutan más rápido. Lo que sale de la vista se finaliza de inmediato (ver Protección). |
fast | 6x | Igual que scroll, el doble de rápido. |
tour (solo depuración) | 1x | Desplazamiento automático como en el video de referencia: ~capas/7 segundos, la cámara sigue el frente de trabajo, termina en la parte inferior con el anillo de cursores. Para grabaciones y verificaciones lado a lado. ?rebuild-speed=6 da el antiguo "rápido" (un desplazamiento automático de 6x, ~9 s en la demo). El desplazamiento manual entrega el control al visitante; el botón Tour de la barra lo reanuda. |
Después de la construcción, los enjambres se reúnen alrededor del elemento de enfoque y la superposición desaparece después de autoExit segundos (3 s; con el complemento de depuración 6 s, nunca en modo tour).
Movimiento
Todo es sutil por defecto y se configura con motion (ver Configurar); ?rebuild-motion=arc:0,... desactiva partes para pruebas A/B (complemento de depuración).
- Elemento de enfoque (
focus): la apertura y el final se arremolinan alrededor de él. Pregunta al desarrollador (paso 1). En cada fase, el primero de estos que esté al menos medio visible se usa: el(los) elemento(s) configurado(s),[data-swarm-focus],h1, un botón principal (a.btn,.button,.cta,button[type=submit]...), el logotipo; luego la imagen más grande visible; luego un punto en la vista. Así, un enfoque muy abajo en la página (p.ej., una llamada a la acción final) sirve para el final, y la apertura usa el encabezado principal. - Enjambres: los agentes libres vuelan en 2-4 enjambres de tamaños claramente diferentes (teléfonos: 2). Cada agente es jalado por un resorte amortiguado hacia su lugar en su enjambre; los centros del enjambre se mueven en una elipse alrededor del elemento de enfoque cuyo radio respira y cuyo ritmo cambia, por lo que los agentes aceleran y desaceleran por sí mismos y nunca corren en un círculo perfecto. La apertura ya comienza en enjambres (dura menos de un segundo para los visitantes).
- Agentes en reposo (durante la construcción, un agente sin trabajo): abandona su enjambre para ocupar su propio punto en la vista, al menos a 72 px de cualquier otro agente en reposo (nunca un grupo de cursores superpuestos), se desplaza lentamente y se desvanece después de 1.4 s; aparece donde descansa cuando recibe su próxima tarea. En el final, todos regresan y se reúnen en enjambres alrededor del enfoque. Medido: como máximo 2 cursores en reposo superpuestos en el 99.6-100 % de los fotogramas (1.2: una mediana de 6 y hasta 20 en la demo).
- Final: un resorte rígido y subamortiguado (amortiguación 0.63,
motion.spring) jala a cada agente hacia el enfoque: más rápido al inicio, aproximadamente 5-20 % más allá de su lugar, luego de regreso; después de ~1 s, el resorte se suaviza y los enjambres giran lentamente. - Ratón (apertura y final, solo escritorio; nunca al tacto, nunca con movimiento reducido): un agente cerca del puntero se aparta de su camino (más difícil cuando el puntero viene rápido); hasta 3 agentes curiosos lo siguen en un círculo pequeño, 1.3-2 s cuando descansa, más corto cuanto más rápido se aleja (el interés disminuye a
(1 + velocidad / 220 px/s)veces la tasa base). Nunca más cerca de 36 px (un límite estricto, por lo que los iconos nunca se superponen); la superposición ignora los eventos del puntero, por lo que los clics nunca se interrumpen. - Gravedad: un agente lleva el elemento en el que trabaja, por lo que su camino allí (y una copia clonada que lleva) se dobla hacia abajo: pandeo = 0.2 x distancia horizontal x peso x horizontalidad², peso = sqrt(área) / 320 px limitado a 0.2..1, como máximo 56 px y una quinta parte de la distancia horizontal. Un movimiento vertical apenas se dobla. El camino hacia una tarea también comienza con la velocidad actual del agente (curva cúbica de Hermite), por lo que no hay paradas o giros repentinos.
- Dificultad: el trabajo de cada tarea (no el camino) se escala por una dificultad según el área del elemento (para escritura: el cuadro donde se escribe): cerca del promedio de la página, 2x el área ~ 1.6-1.8x el tiempo, comprimido (tanh) para que la tarea más difícil tome como máximo ~4x la más fácil. Se normaliza (ponderado por la longitud de la tarea y la dificultad, porque las tareas paralelas hacen que las largas marquen el ritmo) para que toda la construcción tome el mismo tiempo que antes; solo cambia la división entre pequeñas y grandes.
- Lite (
motion.lite: 'auto'): en teléfonos, 2 enjambres y sin juego del ratón; cuando la velocidad de fotogramas se mantiene por debajo de 38 fps durante dos segundos durante la construcción, también un fantasma de estela en lugar de tres.
Idiomas y direcciones de escritura
El módulo no asume ningún idioma. La escritura se realiza mediante caracteres percibidos por el usuario (clústeres de grafemas, Intl.Segmenter, con un fallback que une marcas combinantes, secuencias ZWJ, tonos de piel, selectores de variación y pares de banderas): una letra acentuada, una familia emoji, una bandera o una letra con marcas árabes/hebreas nunca se divide. El texto no escrito permanece en su lugar como texto oculto, y los navegadores le dan forma a través de ese límite, por lo que las letras árabes mantienen sus formas unidas y nada se refluye. Elementos de derecha a izquierda (direction: rtl, p.ej., <html dir="rtl">): los marcos crecen desde el borde derecho, las líneas se dibujan de derecha a izquierda, el agente escribe en el lado izquierdo y el cursor se sitúa a la izquierda de la última letra escrita; una secuencia de izquierda a derecha dentro de texto de derecha a izquierda (un número, una dirección de correo electrónico, un nombre latino) se escribe como un todo, como una palabra pegada. El texto CJK (sin espacios) y las palabras largas se envuelven exactamente como en la página. La superposición en sí siempre se diseña de izquierda a derecha (direction: ltr en su raíz) para que una página de derecha a izquierda nunca la refleje. Los números en cualquier escritura (\p{Nd}) cuentan como números. Páginas de prueba: tests/pages/lang-hu (ő / ű, palabras muy largas), lang-ar (derecha a izquierda, dígitos arábigo-índicos, una cita hebrea), lang-ja (japonés), lang-emoji. Límite conocido: los modos de escritura vertical (writing-mode: vertical-rl) se escriben, pero los marcos aún crecen de izquierda a derecha.
Rendimiento, motores de búsqueda, accesibilidad
-
Tamaño (lo que descarga un visitante; el complemento de depuración nunca): módulo 70 KB minificado / 27.5 KB gzip, hoja de estilos 6 KB / 1.6 KB; presupuesto 30 KB + 2 KB gzip (
node scripts/build-min.cjs --check). Reconstruye los archivos.mindespués de cada cambio en el módulo (--modules <carpeta con terser y csso>). -
Lighthouse (
scripts/perf.cjs, mediana de 3, preajustes móvil/escritorio, la máquina de prueba sin GPU):página LCP ms off -> on CLS off -> on TBT ms off -> on Speed Index ms off -> on puntuación perf demo, móvil 2106 -> 2207 0 -> 0 12 -> 10 968 -> 1669 99 -> 99 demo, escritorio 483 -> 573 0 -> 0 0 -> 0 266 -> 681 100 -> 100 dental, móvil 1956 -> 2035 0 -> 0 0 -> 0 754 -> 1763 99 -> 99 dental, escritorio 442 -> 490 0 -> 0 0 -> 0 201 -> 767 100 -> 100 law (fuentes web), móvil 2094 -> 2222 0.030 -> 0 0 -> 0 1895 -> 2386 98 -> 97 accounting (página larga), móvil 1707 -> 1973 0 -> 0 0 -> 0 1652 -> 1697 99 -> 98 Sin tiempo de bloqueo y sin desplazamiento de diseño (el cambio de fuente propio de la página law incluso se oculta). LCP crece de 50 a 270 ms y Speed Index hasta ~1 s: la primera vista se construye frente al visitante, por lo que está visualmente completa más tarde — ese es el efecto en sí. Solo los visitantes primerizos (una vez por sesión) lo pagan; los visitantes que regresan y los rastreadores obtienen la página de inmediato. Las puntuaciones de accesibilidad/SEO se mueven un punto en cualquier dirección solo porque Lighthouse ve menos de la página mientras está oculta.
-
Motores de búsqueda y vistas previas de enlaces: los rastreadores (agente de usuario con bot / crawl / spider, Googlebot, Bingbot, facebookexternalhit, vistas previas de enlaces ...) nunca reciben el efecto, ni en el fragmento de cabeza ni en el módulo: ven la página terminada con el DOM idéntico (verificación
a11y). Sin JavaScript, la página nunca se oculta, y el efecto nunca elimina contenido (solo usavisibility). -
Accesibilidad (
verificación a11y): el contenido oculto por el efecto (visibility: hidden) es invisible para los lectores de pantalla (ARIA no es necesario), y el efecto, mientras se ejecuta, no interfiere con el foco porque la superposición tienearia-hidden="true"ytabindex="-1", y los eventos de teclado se manejan solo para finalizar el efecto. Al finalizar, la superposición se elimina y el foco vuelve al contenido de la página. La verificacióna11y(enscripts/verify.cjs) ejecuta axe-core en la página terminada (sin el efecto), en la página durante el efecto (solo la superposición visible) y después de que el efecto termina, y todas pasan sin violaciones críticas.
Protección
- Tiempo de espera de capa: una capa que tarda más de 6 s (desde que comienza a construirse) se finaliza para que la página no se quede colgada. Los agentes que faltan se omiten, el marco se oculta y la capa se muestra.
- Tiempo de espera de agente: un agente que tarda más de 4 s en llegar a su tarea (camino bloqueado, página oculta) se teletransporta y comienza la tarea. El tiempo de espera se duplica si la tarea está lejos (distancia > 2000 px).
- Tiempo de espera de construcción: si la construcción (todas las capas) no termina en 60 s (modo scroll) o 120 s (modo tour), la página se muestra por completo y el efecto se detiene. El tiempo de espera se reinicia si el visitante se desplaza a una nueva sección (en modo scroll).
- Ventana oculta: si el documento no está visible (pestaña en segundo plano, ventana minimizada), los agentes se pausan y las tareas no avanzan. Cuando la ventana vuelve a ser visible, la construcción se reanuda desde donde se detuvo, con un breve retraso para evitar un pico de CPU.
- Redimensionamiento: si la ventana se redimensiona durante la construcción, las posiciones de los marcos y los agentes se recalculan para la nueva ventana gráfica. Los elementos que salen de la vista se finalizan.
- Fallback sin JavaScript: si JavaScript está deshabilitado, la página se muestra normalmente (la hoja de estilos en
<head>no oculta nada porque la claseswarm-rebuild-activenunca se añade). El módulo se carga de forma asíncrona (deferotype="module"), por lo que no bloquea la renderización.
Instalación
HTML plano
- Añade los archivos minificados a tu proyecto (
swarm-rebuild.min.js,swarm-rebuild.min.css). - En el
<head>de tu página, añade el fragmento de cabeza (ver más abajo). - Justo antes de
</body>, añade:<script src="ruta/a/swarm-rebuild.min.js"></script><script>SwarmRebuild.init({ /* opciones */ });</script>
React / Next.js
- Instala el paquete desde npm (o copia la carpeta
assets/react/a tu proyecto). - Importa el componente
SwarmRebuilddesde'page-swarm-rebuild/react'. - Coloca
<SwarmRebuildHead />en el<head>de tu diseño (o enlayout.tsxpara Next.js). - Renderiza
<SwarmRebuild />como un componente hijo de tu página (o en un layout).
Fragmento de cabeza
<style>
.swarm-rebuild-active .swarm-rebuild-layer {
visibility: hidden !important;
}
</style>
<script>
if (window.matchMedia('(prefers-reduced-motion: no-preference)').matches &&
!/bot|crawl|spider/i.test(navigator.userAgent)) {
document.documentElement.classList.add('swarm-rebuild-ready');
}
</script>
Configuración
SwarmRebuild.init() acepta un objeto de opciones:
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
mode | string | 'scroll' | 'scroll', 'fast', 'tour' |
speed | number | 1 | Multiplicador de velocidad de construcción (1 = normal). |
focus | string / string[] | null | Selector(es) CSS para el(los) elemento(s) de enfoque. |
autoExit | number | 3 | Segundos antes de que la superposición desaparezca después de la construcción. |
buildVisible | number | 0.6 | Fracción de un elemento que debe estar visible antes de que comience la construcción (0-1). |
motion | object | {} | Configuración de movimiento (ver más abajo). |
debug | boolean | false | Carga el complemento de depuración (solo si la URL tiene ?rebuild-debug=1). |
onReady | function | null | Llamado cuando el módulo está listo (después de que el DOM esté listo y la superposición esté añadida). |
onComplete | function | null | Llamado cuando la construcción termina (después de que la superposición desaparece). |
Opciones de movimiento (motion)
| Opción | Tipo | Predeterminado | Descripción |
|---|---|---|---|
swarms | number | 3 | Número de enjambres (1-4). |
agents | number | 12 | Número de agentes (4-40). |
spring.damping | number | 0.63 | Amortiguación del resorte del final (0-1, menor = más elástico). |
spring.stiffness | number | 0.03 | Rigidez del resorte del final (0-1, mayor = más rápido). |
mouse.curious | boolean | true | Si los agentes siguen el ratón (solo escritorio). |
mouse.distance | number | 36 | Distancia mínima de los agentes al ratón (px). |
mouse.interest | number | 1.5 | Duración del interés del ratón (segundos). |
gravity | number | 0.2 | Factor de curvatura gravitacional (0 = sin curvatura). |
lite | string | 'auto' | 'auto' (detecta bajo rendimiento), 'on' (siempre modo ligero), 'off' (nunca). |
trails | number | 3 | Número de imágenes fantasma de estela (0-5). |
Ejemplo
SwarmRebuild.init({
focus: '.hero h1',
mode: 'scroll',
speed: 1.5,
motion: {
swarms: 2,
agents: 8,
mouse: { curious: false }
},
onComplete: () => console.log('¡Construcción completada!')
});
Licencia
MIT