6.8 KiB
Eidos TextGradient
<TextGradient> pinta un gradiente animado A TRAVÉS del texto
(background-clip: text), con borde opcional enmarcado en el mismo
gradiente. El texto queda intacto en el DOM — efecto solo de pintura, los
lectores de pantalla no notan nada.
Familia text-effects (TextBlur / TextCircular / TextFocus /
TextScramble) — diseño de familia: docs/decisions/design-text-effects.md.
Superficie
<TextGradient>Shiny words</TextGradient>
<TextGradient colors={['--color-primary-solid', '--color-tertiary-solid']}>Lista de stops del tema</TextGradient>
<TextGradient colors="aurora" direction="diagonal">Gradiente canónico con nombre (S9)</TextGradient>
<TextGradient showBorder pauseOnHover yoyo={false}>Con marco</TextGradient>
colors discrimina por forma: un string[] es una lista de stops; un
string a secas nombra un gradiente canónico del theming
(var(--gradient-{name})).
Props clave
| Prop | Tipo | Default | Notas |
|---|---|---|---|
children |
Snippet |
— | El texto real (queda en el DOM). |
colors |
string | string[] |
naranjas del seed | string[] = lista de stops (tokens --color-* → var() o cualquier color CSS). string = nombre de gradiente canónico (var(--gradient-{name})). |
animationSpeed |
number (s) |
8 |
Duración del ciclo de pan. |
showBorder |
boolean |
false |
Marco con el mismo gradiente. |
direction |
'horizontal' | 'vertical' | 'diagonal' |
'horizontal' |
Eje del pan. |
pauseOnHover |
boolean |
false |
Pausa al hover. |
yoyo |
boolean |
true |
Alterna la dirección (alternate) o loop continuo. |
Talla y tema
Contrato en lib/recipes/base.ts > text-gradient (7 claves, entrada NUEVA).
Alcance del censo: 100 % (era 67 %). Guard R-5.4
(npm run theming:sentinel -- text-gradient <url>): 7/7 tokens mueven un
computed en vivo, sin una sola excepción. Corrido 2026-08-22.
--text-gradient-radius var(--radius-lg)
--text-gradient-font-weight var(--font-weight-medium)
--text-gradient-blur var(--blur-sm)
--text-gradient-border-padding-block var(--space-1)
--text-gradient-border-padding-inline var(--space-2)
--text-gradient-border-width var(--border-width)
--text-gradient-border-inner-bg var(--color-surface-default)
Sin eje size: el efecto toma la tipografía de su contexto.
El marco es su propio trazo. El hueco del borde era calc(100% - 2px) —
dos trazos del gradiente asomando alrededor—, así que el knob es el TRAZO
(border-width) y el hueco se deriva de él. Un tema que quiera marco grueso
escribe un número, no dos restas.
blur va a la escala, no a un literal. El blur(4px) de partida era
ciego al zoom global: blur es familia MÉTRICA del eje scaling
(theming §23), y --blur-sm (4px × scaling) es el mismo píxel a scaling 100
y el correcto al 90 y al 110.
Lo que NO es contrato
--_text-gradient-duration y --_text-gradient-play-direction los escribe el
wrapper INLINE desde animationSpeed y yoyo. Ningún token gana a un
estilo inline, así que declararlos sería acuñar dos nombres que mienten —
misma clase que los cuatro ausentes de knob, el item-gap de carousel
y el preview-z de drag-drop. Se escriben por prop, que es su canal.
Baseline
Port limpio del seed web/routes/demos/animations/text/gradient/gradient.svelte
(colección intacta como referencia — provenance en docs/architecture/packs.md). El seed ya era
CSS puro con reduced-motion; sus déficits: colores solo crudos, #000
fijo en el interior del borde, radius/weight/padding mágicos, y
margin: 0 auto (opinión de layout).
Comparativa
| Capacidad | Eidos | Tailwind bg-clip | Framer Motion text | animate-gradient libs |
|---|---|---|---|---|
| Stops = tokens del tema (re-tint al cambiar modo) | Sí | Manual | No | No |
| Gradientes con NOMBRE del sistema (S9) | Sí | No | No | No |
| CSS puro (cero JS por frame) | Sí | Sí | No (JS) | Depende |
| Borde en el mismo gradiente | Sí | Manual | No | No |
| Reduced motion | Sí | Manual | Sí | No |
Referencias externas: MDN background-clip (https://developer.mozilla.org/docs/Web/CSS/background-clip) · Tailwind gradient utilities (https://tailwindcss.com/docs/background-image) · react-bits GradientText (https://reactbits.dev/text-animations/gradient-text).
Decisiones
- Stops por
var()interpolado — un token--color-primary-solidva allinear-gradientcomovar(--color-primary-solid): CSS nativo, reactivo al tema sinresolveTokenJS. colorsdiscrimina nombre vs stops (D-T3) — unstringresuelvevar(--gradient-{name})(el set canónico deEidosConfig.gradients/applyGradients, jaula abierta → el tipo se queda enstring, no una unión cerrada); unstring[]son stops libres. Una sola prop en vez decolors+preset: el vocabulario canónico S9 y los stops crudos son la MISMA entrada, discriminada por forma (sin alias de prop).- El interior del borde ya no es
#000: token público--text-gradient-border-inner-bgcon default--color-surface-default(el seed asumía fondo negro; aquí sigue al tema — fija el token para recuperar el look del seed). margin: 0 autodel seed NO se porta — centrar es del consumidor.- Keyframes locales anotados
/* functional: */(R-4.5): pan ambiental decorativo, no firma perceptual de evento. - No emite eventos sema (pausa por hover = estado CSS, sin percepción).
Gaps
- Ángulos arbitrarios del pan (más allá de 3 ejes): diferir — el eje
canónico de ángulos existe (
--gradient-angle-*); si un consumidor lo pide,directionacepta entonces esas keys. - Pan del gradiente con nombre respetando SU ángulo interno: descartar
— el pan mueve
background-position; el ángulo del nombre es parte del gradiente y se respeta tal cual. - Nombres MESH (
colors="aurora"role-mesh): no soportado por naturaleza — un mesh serializa a radiales + un color base, y ese color base no es unbackground-imageválido (sí unbackgroundshorthand), así que no pinta a través debackground-clip: text.colorscon nombre exige un gradiente de un solo<image>(linear / radial / conic). - Texto multilínea con clip por línea: implementar cuando haya
consumidor —
background-clip: textya cubre el caso común.
Passive justification
Pasivo por diseño: tratamiento de pintura sobre contenido real. Sin
estados interactivos propios (el pause-on-hover es animation-play-state
CSS), sin foco, sin teclado, sin ARIA extra — el contenido ES el
contrato de accesibilidad.
Referencias
- Seed portado:
web/routes/demos/animations/text/gradient/gradient.svelte. - Gradientes con nombre:
EidosConfig.gradients→--gradient-{name}(src/uix/eidos/lib/render-css.ts).