Ir al contenido
Evaluar mi proyecto
Componentes · Texto y animacionesDisponible

Título 3D retro Y2K

Título extruido con relieve que apunta lejos del puntero; amarillo, rosa y contorno morado al estilo de 2001.

Código completo

Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.

texto-retro-3d.tsx41 líneas
Descargar
"use client";

import { useState, type CSSProperties, type PointerEvent } from "react";

/** Título extruido en 3D al estilo Y2K: la profundidad apunta lejos del puntero y el relieve cromado se inclina con él. React + TypeScript, sin dependencias. */
export type TextoRetro3dProps = {
  text?: string;
  depth?: number;
  face?: string;
  side?: string;
  className?: string;
  style?: CSSProperties;
};

const CSS = `
.gctrx-root { display: inline-block; max-width: 100%; padding: .25em .35em .5em; color: var(--f); font: 900 clamp(44px, 11vw, 120px)/.95 "Arial Black", "Impact", ui-sans-serif, system-ui, sans-serif; letter-spacing: -.02em; text-transform: uppercase; text-align: center; -webkit-text-stroke: 3px #19104a; paint-order: stroke fill; touch-action: pan-y; transition: transform .25s cubic-bezier(.16, 1, .3, 1); }
.gctrx-root *, .gctrx-root *::before, .gctrx-root *::after { box-sizing: border-box; }
@media (prefers-reduced-motion: reduce) { .gctrx-root { transition: none; } }`;

export function TextoRetro3d({ text = "Hola mundo", depth = 14, face = "#ffe14d", side = "#ff3fa4", className = "", style }: TextoRetro3dProps) {
  const [d, setD] = useState({ x: 0.6, y: 1 });

  function move(event: PointerEvent<HTMLSpanElement>) {
    if (event.pointerType === "touch") return;
    const rect = event.currentTarget.getBoundingClientRect();
    const x = (event.clientX - (rect.left + rect.width / 2)) / (rect.width / 2);
    const y = (event.clientY - (rect.top + rect.height / 2)) / (rect.height / 2);
    setD({ x: -Math.max(-1, Math.min(1, x)), y: -Math.max(-1, Math.min(1, y)) });
  }

  const extrusion = Array.from({ length: depth }, (_, i) => `${(d.x * (i + 1) * 1.1).toFixed(1)}px ${(d.y * (i + 1) * 1.1).toFixed(1)}px 0 ${i % 3 === 2 ? "#c21f80" : side}`).join(", ");
  const shadow = `${extrusion}, ${(d.x * (depth + 8)).toFixed(1)}px ${(d.y * (depth + 8)).toFixed(1)}px 18px rgba(25, 16, 74, .45)`;

  return (
    <span className={`gctrx-root ${className}`} style={{ "--f": face, textShadow: shadow, ...style } as CSSProperties} onPointerMove={move} onPointerLeave={() => setD({ x: 0.6, y: 1 })} aria-label={text} role="text">
      <style>{CSS}</style>
      <span aria-hidden="true">{text}</span>
    </span>
  );
}

Úsalo en tu proyecto

Instálalo con la CLI de shadcn.

terminal.sh1 líneas
npx shadcn@latest add https://www.gassierconsulting.com/r/texto-retro-3d

Ejemplo de uso de Título 3D retro Y2K

Después de copiar texto-retro-3d.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.

ejemplo.tsx5 líneas
import { TextoRetro3d } from "./texto-retro-3d";

export default function Ejemplo() {
  return <TextoRetro3d text="Ejemplo" />;
}

Propiedades de TextoRetro3d

TextoRetro3d acepta 6 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.

PropiedadTipoDescripción
text?stringOpcional.
depth?numberOpcional.
face?stringOpcional.
side?stringOpcional.
className?stringOpcional.
style?CSSPropertiesOpcional.

Accesibilidad y rendimiento

El archivo tiene 41 líneas (2 KB) y no necesita @keyframes. Esto es lo que hace Título 3D retro Y2K por quien lo usa:

  • Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
  • Declara roles ARIA para lectores de pantalla: text.
  • Reacciona al puntero con eventos pointer (ratón, lápiz y táctil).
  • Es un componente de cliente de Next.js: incluye la directiva "use client".
Licencia
MIT
Dependencias
React >=18
Compatibilidad
React 18 y 19 · Next.js (componente de cliente)