Saltar al contenido
motionframe

Buscar piezas

Categorías

La pieza

Qué hace y dónde encaja

Un haz de luz con cola, de 1,5 px de trazo y un único color vivo, circula en bucle lento por el borde de un elemento con esquinas redondeadas. Está hecho solo con CSS: offset-path, una máscara que deja visible únicamente el anillo y una propiedad registrada que encadena siete segmentos para que la cola doble las esquinas sin cortarse. En la demo marca la tarjeta negra destacada de tres planes de pago único, aparece en las blancas al pasar el puntero, rodea el campo activo de un formulario con etiqueta flotante, acompaña a los botones píldora y sigue a la ficha de plan marcada. Un botón pausa todos los cometas y con movimiento reducido el cometa queda aparcado. Encaja en tablas de precios, formularios de reserva, tarjetas de producto y CTAs de webs de estudio, tecnología o comercio. Cambia el color, la velocidad y la longitud de la cola con tres variables.

Prompt
≈9.675 tokens · con Lite
Librerías
ninguna
Demo
26,3 KB · ligero
Prueba en frío
pendiente

Antes de copiar

Tu marca, dentro del prompt

Cambia lo que quieras y copia: el prompt sale ya con el nombre, los colores y los textos de tu cliente. Lo que dejes en blanco se queda como en la demo.

Ver 1 campos más
Colores

Sin cambios: se copia con los valores de la demo.

Gratis y entero

El prompt, entero y a la vista

Qué trae el prompt, por apartados

  1. 01Qué es
  2. 02Librerías y esqueleto
  3. 03Tokens de diseño
  4. 04Estructura y contenido
  5. 05Movimiento
  6. 06Código clave
  7. 07Interacción
  8. 08Adaptación a móvil y tablet
  9. 09Accesibilidad y movimiento reducido
  10. 10Rendimiento
  11. 11Personalización
  12. 12Comprobación final
Completo
3.737 palabras · ≈9.675 tokens
Lite
1.306 palabras · ≈2.789 tokens
Librerías
ninguna
Peso de la demo
26,3 KB (ligero)
Resolución máxima (DPR)
2
Se pausa fuera de pantalla
sí
Respeta «menos movimiento»
sí

Tokens estimados para español (≈3,6 caracteres por token): sirven para orientarte, no son exactos.

prompt.md
# Recrea en un único archivo HTML: Borde con cometa

Un haz de luz con cola de un solo color vivo que recorre en bucle lento el borde fino de una tarjeta, un botón o un campo de formulario para marcar la opción destacada o el campo activo, hecho solo con CSS (`offset-path` y máscara).

Eres un desarrollador front-end creativo senior. Genera un único `index.html` autocontenido que
reproduzca exactamente la pieza descrita: mismo layout, textos, colores, movimiento e interacción.
HTML, CSS y JS en un solo archivo, sin build ni frameworks. Librerías solo por CDN y en las versiones
indicadas. Todos los valores numéricos de este documento son definitivos: úsalos tal cual.
Responde solo con el archivo completo.

## Qué es

Una página larga para un estudio ficticio de webs de pago único, **Faro** (Portomar), que sirve de escaparate del efecto «borde con cometa». Estilo: blanco y negro puros con **un único color vivo** (`#ff4b14`), sin pasteles, sin cursivas ni letra manuscrita, sin degradados multicolor.

El efecto es una microinteracción reutilizable: un cometa (cabeza brillante y cola que se desvanece, 1,5 px de grosor) circula por el borde de un elemento con esquinas redondeadas. Va dentro del elemento como un anillo decorativo y se activa en tres situaciones: el elemento está marcado como destacado, el puntero pasa por encima, o el foco del teclado está dentro. Cuando no está activo no se ve y su animación está en pausa (no gasta nada).

La demo lo aplica a cuatro tipos de elemento para que se vea que sirve para todo:

1. **Tres tarjetas de plan** (dos blancas y una negra). La negra es la opción destacada: el cometa corre siempre. Las blancas lo muestran al pasar el puntero o al enfocar su botón.
2. **Botón píldora** «Pedir presupuesto» en la cabecera (negro) y «Enviar proyecto» (blanco sobre negro): el cometa aparece al pasar el puntero o enfocar.
3. **Tres campos de formulario** (nombre, email, descripción) con etiqueta flotante: el cometa recorre el borde del campo mientras tiene el foco.
4. **Tres fichas de opción** (radio): el cometa corre alrededor de la ficha marcada.

Composición, de arriba abajo:

1. Cabecera blanca (76 px): marca `Faro` en minúsculas con un punto de color que late; a la derecha tres enlaces (Planes, Proceso, Contacto) con subrayado que se dibuja y el botón negro con cometa.
2. Portada en dos columnas (1,5fr / 1fr): etiqueta mono con punto que emite un «ping», titular grande con «Sin cuotas.» subrayado con una raya del color vivo, y a la derecha un párrafo y el botón «Pausar cometas».
3. Rejilla de tres planes (blanca, negra destacada, blanca).
4. Sección negra a ancho completo con el formulario de contacto, pasos numerados y pie.

## Librerías y esqueleto

Ninguna librería. Solo Google Fonts (con `display=swap`; las tres fuentes tienen ñ, tildes, ¿ y ¡):

```html
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Faro — Borde con cometa</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,500;12..96,700&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>/* ver «Código clave» */</style>
</head>
<body>
  <header class="envoltorio cabecera">…</header>
  <main id="inicio">
    <section class="envoltorio portada">…</section>
    <section class="envoltorio planes" id="planes">…</section>
    <section class="noche" id="contacto">…<footer class="envoltorio pie">…</footer></section>
  </main>
  <script>/* ver «Código clave» */</script>
</body>
</html>
```

Tipografía: **Bricolage Grotesque** (700) para titulares, precios, marca y nombres de plan; **Geist** (400/500/600) para texto y botones; **Geist Mono** (500) para etiquetas técnicas en mayúsculas con `letter-spacing:.08em`.

## Tokens de diseño

```css
@property --t{syntax:"<number>";inherits:true;initial-value:0}
:root{
  --papel:#ffffff;
  --tinta:#0a0a0a;
  --gris:#5c5c5c;
  --gris-noche:#a3a3a3;
  --linea:rgba(10,10,10,.14);
  --linea-noche:rgba(255,255,255,.18);
  --cometa:#ff4b14;
  --f-display:"Bricolage Grotesque","Helvetica Neue",Arial,sans-serif;
  --f-texto:"Geist",system-ui,-apple-system,"Segoe UI",sans-serif;
  --f-mono:"Geist Mono",ui-monospace,"SFMono-Regular",Consolas,monospace;
  --ease:cubic-bezier(.16,1,.3,1);
  --gutter:clamp(16px,4vw,48px);
}
```

`html` y `body` con fondo `var(--papel)`. Texto base 16 px / 1,55. `max-width` del contenedor `.envoltorio`: 1240 px con `padding:0 var(--gutter)`. Los únicos grises son `--gris` (sobre blanco) y `--gris-noche` (sobre negro); ambos cumplen contraste AA.

## Estructura y contenido

Todos los textos son literales (castellano de España). Precios con «IVA incl.».

**Cabecera.** Enlace `.marca` (`aria-label="Faro, inicio"`) con `<span class="marca-punto" aria-hidden="true">` y el texto «Faro» en minúsculas. `<nav class="nav" aria-label="Principal">` con `.nav-enlaces` (Planes → `#planes`, Proceso → `#proceso`, Contacto → `#contacto`) y el botón `<a class="btn btn-negro con-cometa" href="#contacto">` con el anillo de cometa, el texto «Pedir presupuesto» y una flecha SVG de 16 px (`M3 8h10M9 4l4 4-4 4`, trazo 1,6, extremos redondos).

**Portada.** Etiqueta `.etiqueta.mono` con `<span class="punto-vivo">` y «Planes de web · Pago único». `h1.titular`: «Tu web en catorce días. » + `<span class="rayado">Sin cuotas.</span>`. A la derecha `.portada-lado`: párrafo «Estudio Faro diseña y programa webs a mano para negocios de Portomar, Altamar y Valmar. Eliges un plan, lo pagas una vez y la web es tuya.» y `<button class="pausa" id="pausa" aria-pressed="false">` con dos barritas (`.barras`) y el texto «Pausar cometas» (pasa a «Reanudar cometas»).

**Planes** (`<article class="tarjeta con-cometa">`; el primer hijo es el anillo de cometa doble, luego `.plan-cab`, `.precio`, `.precio-nota`, `.plan-desc`, `ul.lista` con cuatro `li` que llevan un check SVG de 18 px (`M3.5 9.5l3.5 3.5 7.5-8`, `pathLength="1"`) y el botón `.btn.btn-plan`):

| Plan | Variante | Precio | Descripción | Puntos | Botón |
|---|---|---|---|---|---|
| Esencial | blanca | 490 € | Una página bien hecha para que te encuentren y te escriban. | Una página con hasta 5 secciones · Tu dominio .com el primer año · Formulario de contacto y mapa · Entrega en 10 días | «Elegir Esencial», `btn-linea` |
| Estudio | negra + `destacada`, insignia «Más elegido» | 1.290 € | La web completa de un negocio que quiere reservas y presencia. | Hasta 6 secciones a medida · Reservas y calendario conectado · Animaciones y microinteracciones · Tres meses de soporte incluido | «Elegir Estudio», `btn-llena` |
| Taller | blanca | 2.400 € | Web a fondo, con panel para que la edites tú sin tocar código. | Páginas ilimitadas y blog · Panel de edición sencillo · Fotos y textos de ayuda · Doce meses de soporte | «Elegir Taller», `btn-linea` |

Bajo cada precio: «IVA incl. · pago único». El símbolo € va en `<small>` a 28 px. En el DOM el orden es Esencial, Estudio, Taller. Cada botón de plan lleva `data-plan="Esencial|Estudio|Taller"` y una flecha SVG.

**Contacto** (`section.noche#contacto`, fondo `#000`). Dos columnas (1fr / 1,05fr). Izquierda: etiqueta mono «Primer paso» (id `proceso`), `h2` «Cuéntanos qué necesitas.», párrafo «Te respondemos en menos de 24 horas con un presupuesto cerrado y una fecha de entrega.» y una lista ordenada sin viñetas con tres pasos numerados «01», «02», «03» (en mono, color vivo): «Nos cuentas tu negocio y lo que quieres lograr.» · «Te enviamos un diseño en tres días.» · «Lo ajustamos juntos y publicamos en catorce.»

Derecha: `<form class="formulario" novalidate>` con:

- `label.campo.con-cometa` (anillo doble) > `input type="text" name="nombre" autocomplete="name" required placeholder=" "` + `span.rotulo` «Tu nombre».
- Ídem `type="email" name="email" autocomplete="email"` con «Tu email».
- `label.campo.alto.con-cometa` con `textarea name="proyecto" required placeholder=" "` y «Qué hace tu negocio».
- `fieldset.fieldset` con `legend` «Plan que te interesa» y tres `label.ficha.con-cometa` (anillo simple) con `input type="radio" name="plan"` de valores Esencial, **Estudio (marcado por defecto)** y Taller.
- `.envio`: botón `btn btn-blanco con-cometa` (anillo doble) «Enviar proyecto» con flecha, y `p.aviso#aviso[role=status][aria-live=polite]` con un check SVG de 20 px (`M4 10.5l4 4 8-9`) y un `span` de texto.

**Pie**: «© 2026 Estudio Faro · Portomar» a la izquierda; a la derecha `hola@faro.com` (mailto) y `+00 000 000 000` (`tel:`).

**El anillo de cometa** es siempre el primer hijo del elemento anfitrión (`.con-cometa`). Hay dos versiones; las dos son `aria-hidden="true"`:

```html
<!-- Trazo (siempre): 7 segmentos -->
<span class="cometa" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></span>
<!-- Brillo difuso (opcional, solo sobre fondos oscuros): 1 elemento -->
<span class="cometa luz" aria-hidden="true"><i></i></span>
```

Llevan trazo + brillo: las tarjetas, los dos botones, los tres campos. Solo trazo: las tres fichas. En las tarjetas blancas el brillo se oculta con CSS (sobre blanco se vería pastel). Cada anfitrión declara sus variables: `--radio` (igual que su `border-radius`), `--dur` (segundos de vuelta) y `--seg` (largo de cada segmento de la cola).

## Movimiento

| Elemento | Propiedad | De → a | Duración | Easing | Retardo | Disparador |
|---|---|---|---|---|---|---|
| Cometa (`.cometa`) | `--t` (número registrado) → `offset-distance` | 0 → 100 (%) en bucle | tarjetas 9 s · campos 5,5 s · botones 4,2 s (planes 4 s) · fichas 3,4 s | `linear` | 0 | anfitrión destacado, `:hover`, `:focus-within` o ficha marcada |
| Cometa (`.cometa`) | `opacity` | 0 → 1 | .45 s | `ease` | 0 | igual |
| Segmentos de la cola | `offset-distance` | `--t`·1 % − k·(`--seg` − 0,4 px) | — | — | — | k = 0…6 |
| Entrada de portada y planes | `opacity`, `translateY` | 0 / 22 px → 1 / 0 | .9 s | `--ease` | `--i`·90 ms + 80 ms | carga |
| Sección de contacto (`.rev`) | `opacity`, `translateY` | 0 / 24 px → 1 / 0 | .8 s / 1 s | `ease` / `--ease` | `--i`·80 ms | `IntersectionObserver` (umbral 0,12) |
| Checks de las listas | `stroke-dashoffset` | 1 → 0 | .6 s | `--ease` | `--i`·90 ms + .5 s | entrada |
| Tarjeta | `transform` | 0 → −4 px | .6 s | `--ease` | 0 | hover |
| Punto de la marca | `box-shadow` (onda) | 0 → 12 px, se desvanece | 3,2 s infinito | `ease-out` | 0 | siempre |
| `.punto-vivo::after` | `scale`, `opacity` | 1 / .7 → 3,2 / 0 | 2,4 s infinito | `cubic-bezier(0,0,.2,1)` | 0 | siempre |
| Etiqueta flotante | `transform` | arriba izq. → `translateY(-12px) scale(.76)` | .35 s | `--ease` | 0 | foco o campo con texto |
| Botones | `transform` | `scale(.97)` | .5 s | `--ease` | 0 | `:active` |
| Flechas | `translateX` | 0 → 4 px | .5 s | `--ease` | 0 | hover del botón |
| Subrayado de enlaces | `scaleX` | 0 → 1 (origen derecha → izquierda) | .45 s | `--ease` | 0 | hover o foco |
| Aviso del formulario | `opacity`, `translateY`, trazo del check | 0 / 6 px → 1 / 0; trazo .7 s | .5 s / .6 s | `ease` / `--ease` | check .15 s | envío |

## Código clave

### Cómo funciona el cometa (léelo antes del CSS)

1. `.cometa` es un anillo: ocupa todo el anfitrión (`inset:0`), hereda su `border-radius` y tiene `padding:var(--w)` (1,5 px). Una **máscara con dos capas** (`content-box` y borde completo, `mask-composite:exclude`) deja visible solo ese anillo de 1,5 px.
2. Dentro hay siete `<i>`. Cada uno es un rectángulo de `--seg` × 8 px que recorre un `offset-path:inset(...)` con las mismas esquinas que el anfitrión (`offset-rotate:auto`, `offset-anchor:100% 50%`, de modo que la cabeza va delante y la cola detrás).
3. El movimiento no lo hace `offset-distance` directamente, sino una **propiedad personalizada registrada** `--t` (número 0→100) animada en `.cometa`. Cada segmento calcula `offset-distance: calc(var(--t) * 1% - k * (--seg - 0.4px))`: así los siete segmentos van encadenados por una distancia fija en píxeles, la cola **dobla las esquinas** (un solo rectángulo recto se cortaría en cada esquina) y el valor negativo da la vuelta al ser el camino cerrado.
4. Cada segmento tiene un degradado horizontal del mismo color con alfas decrecientes (1 → 0): las constantes `--a0` y `--a1` de cada `nth-child` forman una cola continua. La cabeza (primer segmento) acaba en una punta más clara (`color-mix` con un 40 % de blanco). Un solo color, sin degradado multicolor.
5. El brillo `.luz` es otro anillo, de 32 px de ancho y con el camino pegado al borde (`--p:0px`), con una elipse radial desvaneciéndose: da la sensación de que el cometa ilumina la tarjeta por dentro.
6. El anillo solo se anima cuando el anfitrión está activo (`animation-play-state:running`) y nunca fuera de pantalla ni en pausa global.

### Hoja de estilos completa

Copia esta hoja tal cual dentro de `<style>`:

```css
@property --t{syntax:"<number>";inherits:true;initial-value:0}
:root{
  --papel:#ffffff;
  --tinta:#0a0a0a;
  --gris:#5c5c5c;
  --gris-noche:#a3a3a3;
  --linea:rgba(10,10,10,.14);
  --linea-noche:rgba(255,255,255,.18);
  --cometa:#ff4b14;
  --f-display:"Bricolage Grotesque","Helvetica Neue",Arial,sans-serif;
  --f-texto:"Geist",system-ui,-apple-system,"Segoe UI",sans-serif;
  --f-mono:"Geist Mono",ui-monospace,"SFMono-Regular",Consolas,monospace;
  --ease:cubic-bezier(.16,1,.3,1);
  --gutter:clamp(16px,4vw,48px);
}
*,*::before,*::after{box-sizing:border-box}
html{background:var(--papel);-webkit-text-size-adjust:100%}
@media (prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}
body{margin:0;background:var(--papel);color:var(--tinta);font:400 16px/1.55 var(--f-texto);-webkit-font-smoothing:antialiased;overflow-x:hidden}
h1,h2,h3,p,ul{margin:0}
ul{padding:0;list-style:none}
a{color:inherit;text-decoration:none}
button,input,textarea{font:inherit;color:inherit}
button{background:none;border:0;padding:0;cursor:pointer}
:focus-visible{outline:2px solid var(--cometa);outline-offset:3px}
.envoltorio{max-width:1240px;margin:0 auto;padding:0 var(--gutter)}
.mono{font:500 12px/1 var(--f-mono);letter-spacing:.08em;text-transform:uppercase}

/* ——— Borde con cometa: el núcleo ——— */
.cometa{
  --w:1.5px;--p:calc(var(--w) / 2);
  position:absolute;inset:0;z-index:2;padding:var(--w);border-radius:inherit;pointer-events:none;
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask-composite:exclude;
  opacity:0;transition:opacity .45s ease;
  animation:giro var(--dur,9s) linear infinite paused;
}
.cometa.luz{--w:32px;--p:0px}
.cometa i{
  position:absolute;left:0;top:0;width:var(--seg,32px);height:8px;
  offset-path:inset(var(--p) round calc(var(--radio,20px) - var(--p)));
  offset-rotate:auto;offset-anchor:100% 50%;
  offset-distance:calc(var(--t) * 1% - var(--k) * (var(--seg,32px) - .4px));
  background:linear-gradient(90deg,
    color-mix(in srgb,var(--cometa) calc(var(--a1) * 100%),transparent),
    color-mix(in srgb,var(--cometa) calc(var(--a0) * 100%),transparent));
}
.cometa i:nth-child(1){--k:0;--a0:1;--a1:.86;background:linear-gradient(90deg,color-mix(in srgb,var(--cometa) 86%,transparent),var(--cometa) 70%,color-mix(in srgb,var(--cometa) 40%,#fff))}
.cometa i:nth-child(2){--k:1;--a0:.86;--a1:.73}
.cometa i:nth-child(3){--k:2;--a0:.73;--a1:.6}
.cometa i:nth-child(4){--k:3;--a0:.6;--a1:.47}
.cometa i:nth-child(5){--k:4;--a0:.47;--a1:.33}
.cometa i:nth-child(6){--k:5;--a0:.33;--a1:.18}
.cometa i:nth-child(7){--k:6;--a0:.18;--a1:0}
.cometa.luz i{width:170px;height:68px;border-radius:50%;offset-anchor:60% 50%;offset-distance:calc(var(--t) * 1%);background:radial-gradient(closest-side,color-mix(in srgb,var(--cometa) 78%,transparent),color-mix(in srgb,var(--cometa) 22%,transparent) 52%,transparent)}
@keyframes giro{from{--t:0}to{--t:100}}
/* En fondo blanco el brillo difuso se vería pastel: ahí solo va el trazo */
.tarjeta:not(.negra) > .cometa.luz{display:none}
/* El cometa corre (y se ve) solo en la opción destacada, al pasar el puntero o con el foco dentro */
.con-cometa{position:relative;isolation:isolate}
.con-cometa:is(:hover,:focus-within,.destacada,.activa,:has(input:checked)) > .cometa{opacity:1;animation-play-state:running}
.con-cometa[data-fuera] > .cometa,html[data-pausa] .cometa{animation-play-state:paused!important}
/* Sin soporte de offset-path: un anillo cónico que gira */
@supports not (offset-path:inset(0)){
  .cometa i{display:none}
  .cometa:not(.luz){background:conic-gradient(from calc(var(--t) * 3.6deg),transparent 0 58%,var(--cometa))}
  .cometa.luz{display:none}
}
@media (prefers-reduced-motion:reduce){
  .cometa{animation:none;--t:9}
  .punto-vivo::after,.marca-punto{animation:none}
}

/* ——— Cabecera ——— */
.cabecera{display:flex;align-items:center;justify-content:space-between;gap:24px;height:76px}
.marca{display:inline-flex;align-items:center;gap:10px;font:700 26px/1 var(--f-display);letter-spacing:-.03em}
.marca-punto{width:12px;height:12px;border-radius:50%;background:var(--cometa);box-shadow:0 0 0 0 var(--cometa);animation:latido 3.2s ease-out infinite}
@keyframes latido{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--cometa) 55%,transparent)}70%,100%{box-shadow:0 0 0 12px transparent}}
.nav{display:flex;align-items:center;gap:6px}
.nav-enlaces{display:flex;gap:2px;margin-right:14px}
.nav-enlaces a{position:relative;padding:10px 14px;font-size:15px;font-weight:500}
.nav-enlaces a::after{content:"";position:absolute;left:14px;right:14px;bottom:6px;height:1.5px;background:var(--tinta);transform:scaleX(0);transform-origin:right;transition:transform .45s var(--ease)}
.nav-enlaces a:hover::after,.nav-enlaces a:focus-visible::after{transform:scaleX(1);transform-origin:left}

/* ——— Botones ——— */
.btn{--radio:26px;--seg:16px;--dur:4.2s;display:inline-flex;align-items:center;justify-content:center;gap:10px;height:52px;padding:0 26px;border-radius:26px;font:600 15px/1 var(--f-texto);white-space:nowrap;transition:background-color .3s ease,color .3s ease,transform .5s var(--ease)}
.btn:active{transform:scale(.97)}
.btn svg{width:16px;height:16px;flex:none;transition:transform .5s var(--ease)}
.btn:hover svg{transform:translateX(4px)}
.btn-negro{--radio:22px;height:44px;padding:0 20px;border-radius:22px;background:var(--tinta);color:#fff}
.btn-blanco{background:#fff;color:var(--tinta)}
.btn-linea{box-shadow:inset 0 0 0 1px var(--tinta);color:var(--tinta);--seg:0px}
.btn-linea:hover{background:var(--tinta);color:#fff}
.btn-plan{width:100%;--dur:4s}
.btn-plan.btn-llena{background:#fff;color:var(--tinta)}
.btn-plan.btn-llena:hover{background:var(--cometa);color:var(--tinta)}

/* ——— Portada ——— */
.portada{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);gap:clamp(24px,5vw,80px);align-items:end;padding-block:clamp(20px,4.5svh,52px) clamp(24px,4svh,44px)}
.etiqueta{display:inline-flex;align-items:center;gap:10px;margin-bottom:clamp(14px,2.2svh,24px);color:var(--gris)}
.punto-vivo{position:relative;width:8px;height:8px;border-radius:50%;background:var(--cometa)}
.punto-vivo::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--cometa);animation:ping 2.4s cubic-bezier(0,0,.2,1) infinite}
@keyframes ping{0%{transform:scale(1);opacity:.7}80%,100%{transform:scale(3.2);opacity:0}}
.titular{font:700 clamp(2.4rem,4.9vw,4.5rem)/.98 var(--f-display);letter-spacing:-.045em;text-wrap:balance}
.titular .rayado{background:linear-gradient(var(--cometa),var(--cometa)) 0 92%/100% .09em no-repeat}
.portada-lado{display:flex;flex-direction:column;gap:20px;align-items:flex-start;padding-bottom:6px}
.portada-lado p{color:var(--gris);font-size:17px;max-width:38ch}
.pausa{display:inline-flex;align-items:center;gap:10px;height:44px;padding:0 18px 0 16px;border-radius:22px;box-shadow:inset 0 0 0 1px var(--linea);font:500 13px/1 var(--f-mono);letter-spacing:.04em;transition:box-shadow .3s ease,background-color .3s ease}
.pausa:hover{box-shadow:inset 0 0 0 1px var(--tinta)}
.pausa .barras{display:flex;gap:3px}
.pausa .barras i{display:block;width:3px;height:12px;background:currentColor;border-radius:1px;transition:transform .35s var(--ease)}
html[data-pausa] .pausa .barras i:first-child{transform:translateX(2px) scaleY(.7)}
html[data-pausa] .pausa .barras i:last-child{transform:translateX(-2px) scaleY(.7)}

/* ——— Planes ——— */
.planes{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;padding-bottom:clamp(56px,9vw,120px)}
.tarjeta{--radio:20px;--dur:9s;--seg:30px;display:flex;flex-direction:column;padding:28px;border-radius:20px;background:#fff;color:var(--tinta);box-shadow:inset 0 0 0 1px var(--linea);transition:transform .6s var(--ease),box-shadow .4s ease}
.tarjeta:hover{transform:translateY(-4px)}
.tarjeta.negra{background:#000;color:#fff;box-shadow:inset 0 0 0 1px var(--linea-noche)}
.plan-cab{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:30px}
.plan-cab h3{font:700 22px/1 var(--f-display);letter-spacing:-.02em}
.insignia{display:inline-flex;align-items:center;gap:8px;height:26px;padding:0 11px 0 10px;border-radius:13px;background:var(--cometa);color:#0a0a0a}
.insignia .punto-vivo{width:6px;height:6px;background:#0a0a0a}
.insignia .punto-vivo::after{background:#0a0a0a}
.precio{display:flex;align-items:baseline;gap:6px;margin-top:26px;font:700 clamp(3.2rem,5vw,4.4rem)/.9 var(--f-display);letter-spacing:-.05em;font-variant-numeric:tabular-nums}
.precio small{font:500 28px/1 var(--f-display);letter-spacing:0}
.precio-nota{margin-top:10px;color:var(--gris)}
.negra .precio-nota{color:var(--gris-noche)}
.plan-desc{margin-top:22px;max-width:34ch;color:var(--gris)}
.negra .plan-desc{color:var(--gris-noche)}
.lista{display:grid;gap:11px;margin:22px 0 28px;padding-top:22px;border-top:1px solid var(--linea)}
.negra .lista{border-color:var(--linea-noche)}
.lista li{display:flex;gap:12px;align-items:flex-start;font-size:15px;line-height:1.4}
.lista svg{flex:none;width:18px;height:18px;margin-top:1px}
.lista path{fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:1;stroke-dashoffset:0}
.tarjeta .btn{margin-top:auto}

/* ——— Contacto ——— */
.noche{background:#000;color:#fff;padding:clamp(64px,9vw,128px) 0 0}
.contacto{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);gap:clamp(32px,6vw,96px);padding-bottom:clamp(56px,8vw,104px)}
.noche h2{font:700 clamp(2.3rem,4.6vw,4.2rem)/.98 var(--f-display);letter-spacing:-.04em;text-wrap:balance}
.noche .intro{margin-top:22px;color:var(--gris-noche);font-size:17px;max-width:40ch}
.pasos{display:grid;gap:0;margin-top:40px;counter-reset:paso;border-top:1px solid var(--linea-noche)}
.pasos li{display:grid;grid-template-columns:44px 1fr;align-items:baseline;padding:16px 0;border-bottom:1px solid var(--linea-noche);font-size:15px;color:#d4d4d4}
.pasos li::before{counter-increment:paso;content:"0" counter(paso);font:500 12px/1 var(--f-mono);color:var(--cometa);letter-spacing:.06em}
.formulario{display:grid;gap:14px;align-content:start}
.campo{--radio:12px;--seg:22px;--dur:5.5s;position:relative;display:block;height:60px;border-radius:12px;background:#0b0b0b;box-shadow:inset 0 0 0 1px var(--linea-noche);transition:box-shadow .3s ease,background-color .3s ease}
.campo:hover{box-shadow:inset 0 0 0 1px rgba(255,255,255,.36)}
.campo:focus-within{box-shadow:inset 0 0 0 1px rgba(255,255,255,.55);background:#101010}
.campo.alto{height:132px}
.campo input,.campo textarea{position:absolute;inset:0;width:100%;height:100%;padding:25px 16px 8px;border:0;border-radius:inherit;background:transparent;color:#fff;font-size:16px;line-height:1.4;caret-color:var(--cometa);outline:none;resize:none}
.campo textarea{padding-top:28px}
.campo .rotulo{position:absolute;left:16px;top:20px;font-size:15px;line-height:1;color:var(--gris-noche);transform-origin:left top;pointer-events:none;transition:transform .35s var(--ease),color .3s ease}
.campo :is(input,textarea):focus + .rotulo,.campo :is(input,textarea):not(:placeholder-shown) + .rotulo{transform:translateY(-12px) scale(.76);color:#fff}
.campo :is(input,textarea):focus + .rotulo{color:var(--cometa)}
.campo.alto .rotulo{top:20px}
.fieldset{display:grid;gap:12px;margin:6px 0 4px;padding:0;border:0;min-inline-size:0}
.fieldset legend{padding:0 0 12px;color:var(--gris-noche);font-size:14px}
.fichas{display:flex;flex-wrap:wrap;gap:10px}
.ficha{--radio:22px;--seg:14px;--dur:3.4s;position:relative;display:inline-flex;align-items:center;height:44px;padding:0 20px;border-radius:22px;box-shadow:inset 0 0 0 1px var(--linea-noche);font-size:15px;font-weight:500;cursor:pointer;transition:box-shadow .3s ease,background-color .3s ease,transform .5s var(--ease)}
.ficha:hover{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}
.ficha:active{transform:scale(.96)}
.ficha input{position:absolute;inset:0;margin:0;opacity:0;cursor:pointer}
.ficha:has(input:checked){background:#0d0d0d;box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}
.ficha:has(input:focus-visible){outline:2px solid var(--cometa);outline-offset:3px}
.envio{display:flex;align-items:center;gap:20px;flex-wrap:wrap;margin-top:10px}
.envio .btn{--dur:4s}
.aviso{display:inline-flex;align-items:center;gap:10px;font-size:15px;color:#fff;opacity:0;transform:translateY(6px);transition:opacity .5s ease,transform .6s var(--ease)}
.aviso.ok{opacity:1;transform:none}
.aviso svg{width:20px;height:20px;flex:none}
.aviso path{fill:none;stroke:var(--cometa);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:1;stroke-dashoffset:1}
.aviso.ok path{stroke-dashoffset:0;transition:stroke-dashoffset .7s .15s var(--ease)}
.pie{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px 32px;padding-block:26px 34px;border-top:1px solid var(--linea-noche);color:var(--gris-noche)}
.pie a{transition:color .3s ease}
.pie a:hover{color:#fff}
.pie-enlaces{display:flex;gap:24px;flex-wrap:wrap}

/* ——— Entradas ——— */
@media (prefers-reduced-motion:no-preference){
  .entra{animation:sube .9s var(--ease) both;animation-delay:calc(var(--i,0) * 90ms + 80ms)}
  @keyframes sube{from{opacity:0;transform:translateY(22px)}}
  .js .rev{opacity:0;transform:translateY(24px);transition:opacity .8s ease,transform 1s var(--ease);transition-delay:calc(var(--i,0) * 80ms)}
  .js .rev.visto{opacity:1;transform:none}
  .rev.visto .lista path,.entra .lista path{animation:trazo .6s calc(var(--i,0) * 90ms + .5s) var(--ease) backwards}
  @keyframes trazo{from{stroke-dashoffset:1}}
}

/* ——— Adaptación ——— */
@media (max-width:1020px){
  .planes{grid-template-columns:1fr;max-width:560px}
  .tarjeta.negra{order:-1}
  .portada{grid-template-columns:1fr;align-items:start}
  .contacto{grid-template-columns:1fr}
}
@media (max-width:640px){
  .nav-enlaces{display:none}
  .cabecera{height:68px}
  .portada-lado p{font-size:16px}
  .tarjeta{padding:24px}
  .campo,.campo.alto{--dur:6s}
  .ficha{flex:1 1 auto;justify-content:center}
  .pie-enlaces{gap:16px}
}
```

### Script completo

```js
(() => {
  const raiz = document.documentElement;
  raiz.classList.add("js");

  // Pausa global de los cometas (control para quien no quiere movimiento continuo)
  const pausa = document.getElementById("pausa"), pausaTxt = document.getElementById("pausa-texto");
  pausa.addEventListener("click", () => {
    const on = raiz.toggleAttribute("data-pausa");
    pausa.setAttribute("aria-pressed", String(on));
    pausaTxt.textContent = on ? "Reanudar cometas" : "Pausar cometas";
  });

  // Los anillos fuera de pantalla no animan
  const hosts = document.querySelectorAll(".con-cometa");
  if ("IntersectionObserver" in window) {
    const vigila = new IntersectionObserver((es) => es.forEach((e) => e.target.toggleAttribute("data-fuera", !e.isIntersecting)), { rootMargin: "80px" });
    hosts.forEach((h) => vigila.observe(h));
  }

  // Elegir un plan precarga la ficha del formulario
  document.querySelectorAll("[data-plan]").forEach((a) => a.addEventListener("click", () => {
    const r = document.querySelector('input[name="plan"][value="' + a.dataset.plan + '"]');
    if (r) r.checked = true;
  }));

  // Aparición al hacer scroll
  const revs = document.querySelectorAll(".rev");
  if ("IntersectionObserver" in window) {
    const io = new IntersectionObserver((es) => es.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("visto"); io.unobserve(e.target); } }), { threshold: 0.12 });
    revs.forEach((r) => io.observe(r));
  } else revs.forEach((r) => r.classList.add("visto"));

  // Envío de ejemplo (no sale de la página)
  const form = document.getElementById("formulario"), aviso = document.getElementById("aviso"), avisoTxt = document.getElementById("aviso-texto");
  form.addEventListener("submit", (ev) => {
    ev.preventDefault();
    const n = form.nombre, m = form.email;
    const malo = [n, m, form.proyecto].find((c) => !c.value.trim() || (c === m && !/^\S+@\S+\.\S+$/.test(c.value)));
    aviso.classList.remove("ok");
    if (malo) { avisoTxt.textContent = "Revisa el campo «" + malo.parentElement.querySelector(".rotulo").textContent + "»."; void aviso.offsetWidth; aviso.classList.add("ok"); malo.focus(); return; }
    avisoTxt.textContent = "Recibido, " + n.value.trim().split(" ")[0] + ". Te escribimos en menos de 24 horas.";
    void aviso.offsetWidth; aviso.classList.add("ok");
  });
})();
```

## Interacción

- **Puntero**: pasar por una tarjeta, botón o campo activa su cometa y levanta la tarjeta 4 px. Al salir, el cometa se desvanece en .45 s.
- **Teclado**: `:focus-within` activa el anillo del campo o de la tarjeta (al enfocar su botón). El foco visible de botones, enlaces y fichas es un contorno de 2 px del color vivo con 3 px de separación; los campos cambian además su borde a blanco al 55 %.
- **Elegir plan**: pulsar «Elegir X» marca la ficha correspondiente en el formulario (la navegación a `#contacto` es la de un enlace normal).
- **Campos**: etiqueta flotante (sube y se encoge al enfocar o escribir; en foco se tiñe del color vivo). Cursor de texto del color vivo.
- **Envío**: sin salir de la página. Valida que nombre, email (con `@` y punto) y descripción estén rellenos; si no, enseña «Revisa el campo «…».» y enfoca el campo. Si todo está bien: «Recibido, <nombre>. Te escribimos en menos de 24 horas.» con el check que se dibuja.
- **Pausar cometas**: alterna `data-pausa` en `<html>` y detiene todas las animaciones de cometa (queda el trazo fijo donde estaba); actualiza `aria-pressed` y el texto.
- **Táctil**: no hay hover; la tarjeta destacada corre siempre, los campos al tocarlos (foco), las fichas al marcarlas y las tarjetas blancas al enfocar su botón.

## Adaptación a móvil y tablet

- `≤ 1020 px`: portada y contacto a una columna; los planes pasan a una columna de `max-width:560px` y **la tarjeta negra destacada sube la primera** (`order:-1`) para verse sin hacer scroll.
- `≤ 640 px`: se ocultan los tres enlaces de la cabecera (queda el botón), cabecera de 68 px, tarjetas con `padding:24px`, párrafo de portada a 16 px, las fichas se reparten el ancho (`flex:1 1 auto`) y los campos giran el cometa en 6 s.
- Sin scroll horizontal de 360 a 1920 px. Objetivos táctiles de 44 px o más.

## Accesibilidad y movimiento reducido

- HTML semántico: `header`, `nav`, `main`, `section`, `article`, `form`, `fieldset/legend`, `footer`. Los anillos de cometa, puntos y checks son `aria-hidden`.
- Controles con etiqueta (`label` envolviendo cada campo), `autocomplete` correcto y mensaje de estado con `role="status"` y `aria-live="polite"`.
- El botón «Pausar cometas» cumple la pauta de pausar contenido en movimiento de más de 5 s.
- `prefers-reduced-motion: reduce`: el cometa no se anima; queda aparcado en `--t:9` (arriba a la izquierda) en las situaciones activas, sin entradas ni latidos. La pieza sigue siendo legible y la opción destacada se distingue.
- Contraste AA en todo el texto; el color vivo nunca es el único portador de información (la insignia «Más elegido» lo dice con texto).

## Rendimiento

- Cero librerías; la pieza completa pesa unos 27 KB.
- Solo se animan `--t` (dentro de cada anillo) y `opacity`; los anillos inactivos están en pausa y con `opacity:0`.
- Un `IntersectionObserver` marca `data-fuera` en los anfitriones fuera de pantalla (margen 80 px) y los pausa.
- Si el navegador no soporta `offset-path:inset()`, un `@supports not` oculta los segmentos y deja un anillo cónico que gira con el mismo color (sin brillo).

## Personalización

- **Color del cometa**: cambia `--cometa` (valor por defecto `#ff4b14`); es el único color vivo de la página (insignia, subrayado, punto, foco). Elige uno saturado; los pasteles se pierden sobre blanco.
- **Velocidad**: cambia `--dur` en el anfitrión (más segundos = más lento). Cola más larga o corta: `--seg` (el largo total es 7 × `--seg`).
- **Grosor**: `--w` en `.cometa` (1,5 px por defecto). Si lo cambias, no toques `--p`: se recalcula.
- **Redondeo**: `--radio` debe coincidir con el `border-radius` del anfitrión (en una píldora, la mitad del alto).
- **Usar el cometa en otro elemento**: añade la clase `con-cometa` (o `destacada` para que corra siempre), declara `--radio`, `--dur`, `--seg` y pega el anillo como primer hijo.
- Textos, marca, ciudad, email, teléfono y precios se cambian con las variables.

## Comprobación final

1. Al cargar, la tarjeta negra «Estudio» tiene un cometa naranja que recorre todo su borde sin cortes en las esquinas.
2. La cola se desvanece de forma continua (sin escalones visibles) y dobla las cuatro esquinas.
3. Pasar el puntero por las tarjetas blancas muestra un cometa solo de trazo; al salir se desvanece.
4. Enfocar un campo con el teclado hace correr el cometa por su borde y tiñe la etiqueta del color vivo.
5. La ficha de plan marcada tiene cometa; al marcar otra, el cometa se mueve a esa.
6. Los botones píldora tienen el cometa siguiendo la forma redondeada completa.
7. «Pausar cometas» detiene todo el movimiento de cometas y cambia su texto.
8. Con `prefers-reduced-motion` no hay animación y el cometa queda aparcado y visible en el estado activo.
9. En 390 px la tarjeta negra aparece la primera, sin scroll horizontal.
10. No hay errores en consola y el único color fuera de blanco, negro y grises es el vivo.
11. Enviar el formulario vacío muestra el aviso de revisión; enviarlo completo muestra «Recibido, …» y el check se dibuja.
12. Los titulares usan Bricolage Grotesque; no hay cursivas en ningún sitio.

Prueba en frío

La prueba en frío

Aún sin publicar para esta pieza

En la prueba en frío pegamos el prompt en Claude Sonnet 5.5, sin ayuda ni contexto, y comparamos lo que genera con la demo. Cuando esté hecha, aquí verás la captura, el veredicto y la fecha.

Paso a paso

Cómo usarlo en 4 pasos

  1. 01

    Personaliza

    Rellena el formulario de arriba con el nombre, los colores y los textos de tu cliente. Se meten en el prompt al copiar.
  2. 02

    Copia el Completo o el Lite

    El Completo, para Claude, ChatGPT, Gemini o Cursor. El Lite, más corto, para Lovable, Bolt o v0, que aceptan menos texto.
  3. 03

    Pega e itera

    Pégalo en una conversación nueva. Si quieres cambiar algo, pídelo con una frase corta:
    • «Haz el cometa más lento, una vuelta cada 14 segundos»
    • «Cambia el color vivo a azul eléctrico»
    • «Que la cola sea el doble de larga»
    • «Pon el cometa solo en el plan destacado y no en los campos del formulario»
  4. 04

    Publica

    Guarda el resultado como HTML (o en tu proyecto) y súbelo a Vercel, Netlify o tu hosting de siempre. Tienes los pasos en la guía.

Guías por herramientaClaudeChatGPTGeminiCursorLovableBoltv0

Licencia en claro

Qué puedes hacer con esta pieza

Todas las piezas incluyen licencia de uso comercial. Usa el resultado tal cual en tus productos, encargos freelance o webs de clientes, sin atribución.

Puedes

  • Usarlo en tus webs y en las de tus clientes, también si cobras por ellas.
  • Cambiarlo todo lo que quieras.
  • Publicar el resultado sin citarnos.

No puedes

  • Revender o regalar el prompt, la demo o el código como plantilla o biblioteca.
  • Compartir tu cuenta Pro.

Es la misma licencia para lo gratis y lo Pro. La tienes entera en licencia de uso.

Preguntas frecuentes

Lo que suele preguntarse

¿Puedo usar el cometa en un solo botón o tarjeta de mi web?
Sí. Añade la clase con-cometa al elemento, declara sus variables --radio, --dur y --seg, y pega el anillo (el span con siete i) como primer hijo. No necesita JavaScript para funcionar.
¿Por qué la cola está hecha de siete trozos y no de uno solo?
Un único rectángulo recto se corta en cada esquina redondeada. Con siete tramos encadenados por una distancia fija, la cola dobla la curva y se desvanece sin saltos.
¿Qué pasa en navegadores antiguos o con movimiento reducido?
Si no hay offset-path con inset(), un bloque @supports deja un anillo cónico que gira con el mismo color. Con prefers-reduced-motion el cometa no se anima: queda aparcado en la esquina superior izquierda en los estados activos.
¿Gasta mucha batería tener el cometa siempre en marcha?
Solo corre en el elemento destacado, o mientras hay hover o foco. Los anillos inactivos están en pausa y transparentes, los que salen de pantalla se pausan solos y el botón Pausar cometas detiene todos.
¿Qué diferencia hay entre el prompt Completo y el Lite?
El Completo (≈9675 tokens) describe la pieza con todo detalle y es el que mejor resultado da en Claude, ChatGPT, Gemini o Cursor. El Lite (≈2789 tokens) resume lo esencial para herramientas que aceptan menos texto, como Lovable, Bolt o v0.

Versión 1.0 · publicada el 01-10-2026

Cópialo desde aquí

Tu navegador no nos deja escribir en el portapapeles. El texto ya está seleccionado: pulsa Ctrl + C (o ⌘ + C) o el botón.