4.0 KiB
Eidos TextScramble
<TextScramble> hace parpadear los caracteres cercanos al puntero a
través de un charset de scramble, y los devuelve al texto real al agotarse
su duración (proporcional a la proximidad).
Familia text-effects (TextGradient / TextBlur / TextCircular /
TextFocus) — diseño de familia: docs/decisions/design-text-effects.md.
Superficie
<TextScramble text="Hover to distort this paragraph." />
<TextScramble text="0101 0110 1000" scrambleChars="01" radius={160} />
<TextScramble text="Slow burn" duration={2.5} speed={0.2} />
Props clave
| Prop | Tipo | Default | Notas |
|---|---|---|---|
text |
string |
— | El texto (también la superficie SR). |
radius |
number (px) |
100 |
Radio de influencia del puntero. |
duration |
number (s) |
1.2 |
Scramble en el centro; decae con la distancia. |
speed |
number |
0.5 |
Multiplicador del ritmo de parpadeo. |
scrambleChars |
string |
'.:' |
Charset del parpadeo. |
Tokens públicos
--text-scramble-font · --text-scramble-size.
Baseline
Port limpio del seed web/routes/demos/animations/text/scrambled/scrambled.svelte
(colección intacta como referencia — provenance en docs/architecture/packs.md). El seed ya
traía el motor de parpadeo con age-out y reduced-motion; sus déficits:
medía el rect de CADA carácter en CADA pointermove (tormenta de
reflows), split imperativo destructivo del DOM (innerHTML juggling), sin
superficie SR (los lectores podían leer los glifos scrambled), y rAF/
listeners crudos.
Comparativa
| Capacidad | Eidos | GSAP ScrambleText | react-bits ScrambledText | baffle.js |
|---|---|---|---|---|
| Proximidad de puntero con falloff | Sí | Manual | Sí | No |
| Superficie SR endurecida (texto real + flicker aria-hidden) | Sí | No | No | No |
| O(1) lecturas de layout por pointermove (cache de centros) | Sí | No | No (por char) | N/A |
| rAF/RO/measure del ecosistema | Sí | No | No | No |
| Reduced motion | Sí | Manual | Sí | No |
Referencias externas: GSAP ScrambleTextPlugin (https://gsap.com/docs/v3/Plugins/ScrambleTextPlugin/) · react-bits ScrambledText (https://reactbits.dev/text-animations/scrambled-text) · baffle.js (https://camwiegert.github.io/baffle/).
Decisiones
text: stringen vez de children (el seed aceptaba un Snippet y extraíatextContentdestruyendo el markup interno): el split por caracteres solo es honesto con texto plano, y la superficie SR lo necesita — API más estricta, declarada.- Cache de centros por carácter (relativos al root) vía
eidos.dom.measure, invalidado porobserveResizey cambios de texto. El handler de move hace UNA lectura del rect del root (sin write previo — legal según la regla de layout reads) + aritmética. El seed: O(N) rects por evento. - SR hardening — upgrade sobre el seed: texto real en span
visually-hidden; el párrafo que parpadea es
aria-hidden. - Render declarativo de spans (Svelte each) — sin
innerHTMLjuggling ni cleanup destructivo. - Flicker por rAF del ecosistema (
eidos.dom.requestFrame); teardown restaura todo carácter en vuelo. - No emite eventos sema: parpadeo decorativo por proximidad.
Gaps
- Grafemas compuestos (emoji/ZWJ): implementar cuando haya consumidor
—
Array.fromya respeta surrogates; los clusters ZWJ requierenIntl.Segmenter. - Scramble por toque en pantallas táctiles (pointerdown burst): diferir — el seed era hover-only; un burst táctil es diseño nuevo.
- Charset con pesos (caracteres más frecuentes): descartar — sin caso.
Passive justification
Pasivo por diseño: parpadeo decorativo por proximidad sobre texto real. Sin commit, sin emerge, sin teclado, sin foco — el puntero solo perturba la presentación y el contenido accesible permanece intacto.
Referencias
- Seed portado:
web/routes/demos/animations/text/scrambled/scrambled.svelte. - Regla de layout reads:
CLAUDE.md§Key Conventions (dom.measure).