You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/TYPOGRAPHY_ENGINE_RFC.md

11 KiB

RFC — Motor de tipografía reference-grade (eidos)

Estado: PROPUESTA (2026-06-05). Plan para elevar la tipografía de eidos a la par o por encima de los frameworks de referencia, replicando el enfoque del color (COLOR_ENGINE_RFC.md): auditar → comparar → extender de forma ADITIVA detrás del contrato de tokens congelado, por fases.

1. Estado actual (auditoría)

TypographyPrimitiveSet (lib/primitives/typography.ts + config-types.ts) → emisión en render-css.ts → tokens → componentes <Text> / <Heading> / <SText>.

  • 4 familias (primary Instrument Sans · secondary/display Lora · mono Azeret Mono).
  • 8 tamaños xxs 10px … xxxl 80px, cada uno size / lineHeight / letterSpacing fijos en px.
  • 4 pesos (400/500/600/700).
  • 13 estilos nombrados (hero, h1–h6, body, prose, label, caption, code) con size responsive por breakpoint en algunos ({ base, md }).
  • Eje --scaling (zoom global 90–110%) que multiplica los px.
  • Tokens: --font-family-*, --font-size-* (calc(px * --scaling)), --font-line-height-*, --font-letter-spacing-*, --font-weight-*, --style-{name}-*.
  • Brazo de medición: el motor canvas-text (<SText>) cuenta líneas exactas replicando el navegador (productionizado — ver lib/canvas-text/fix-stext.md).

Bueno hoy: estilos semánticos nombrados, sizes responsive, eje de scaling (poco común), contrato de tokens + theming, medición exacta de líneas.

2. Comparación con referencia (el gap)

Capacidad Referencia Eidos hoy
Tipografía fluida (clamp() por viewport) Utopia, Carbon, Tailwind(opt) ❌ px fijos + breakpoints manuales
Variable fonts (1 archivo, wght + opsz) Material 3, Apple ❌ TTF estáticas por peso
WOFF2 + subsetting + fallback con métricas (anti-CLS) Next/Fontaine ❌ TTF, sin subset, sin size-adjust
Optical sizing (opsz) Apple, Material ❌
Tracking por tamaño (óptico) Material, Apple, Radix ❌ todo 0
text-wrap: balance/pretty Tailwind, Chakra ❌
Measure (ancho de línea ~65ch) clásico, Tailwind prose ❌
font-feature-settings (tabular-nums…) Tailwind, Radix ❌
Estilos nombrados · eje de scaling Chakra/Material · Apple(parcial) ✅

3. Modelo de inclusión: extender, no reemplazar

Principio rector (idéntico a color): todo lo nuevo es ADITIVO sobre TypographyPrimitiveSet, detrás del contrato de tokens congelado. Lo viejo (px fijos) sigue funcionando; lo nuevo se activa por config. Los nombres de token (--font-size-X, --style-Y-*) no cambian — solo cambia la fórmula del valor (igual que en color el token --scale-* pasó de hex a oklch() sin renombrar).

Capas de la implementación, paralelas a color:

Pieza Dónde Análogo en color
Matemática pura (fluid scale Utopia) eidos/lib/type-scale.ts (puro) arts/color / build-scheme.ts
Tipo + config config-types.ts (TypographyPrimitiveSet) EidosConfig
Emisión CSS render-css.ts (appendTypographyDeclarations) appendColorScaleDeclarations
Fuentes themes/fonts.css (woff2/variable) themes/base (paleta)
Componentes <Text> / <Heading> (props nuevas) <Button> etc.
Runtime opcional eidos.applyTypeScale(seed) eidos.applyColorScheme(seed)

4. Tipografía fluida (Fase 1, el corazón)

Fórmula (estilo Utopia) — un tamaño se vuelve un clamp(min, fluido, max) en rem (a11y: respeta el zoom del navegador), donde el tramo fluido interpola entre dos viewports:

slope      = (maxRem − minRem) / (maxVw − minVw)
interceptRem = minRem − slope · minVw
size = clamp(minRem, interceptRem + slope·100vw, maxRem)
  • rem, no px: mejora la accesibilidad (el zoom de fuente del SO/navegador escala). El token --font-size-X mantiene su nombre; su valor pasa de calc(px*scaling) a calc(clamp(...rem...) * var(--scaling)) — transparente para los consumidores.
  • El eje --scaling (zoom discreto del sistema) compone encima del clamp vía calc(clamp(...) * var(--scaling)). Dos ejes ortogonales: fluid (continuo, por viewport) + scaling (discreto, preferencia).
  • Simplifica los estilos nombrados: hero/h1/h2 ya no necesitan size responsive { base, md } manual — el clamp cubre el viewport de forma continua. El emisor de @media por breakpoint para size se puede retirar (menos CSS).
  • Tipo: TextMetric.size acepta hoy string; se extiende a string | FluidSize donde FluidSize = { min: string; max: string; minVw?: string; maxVw?: string }. string (px fijo) sigue válido → backward-compatible.

5. Fuentes modernas (Fase 2, mayor golpe perf+calidad)

  • WOFF2 + variable: migrar fonts.css de TTF estáticas por peso a woff2 variable (Instrument Sans / Lora / Azeret Mono tienen versión variable con eje wght; Lora además ital). Un archivo por familia en vez de 3–10.
  • Anti-CLS: por cada familia, un @font-face de fallback con métricas sobreescritas (size-adjust, ascent-override, descent-override, line-gap-override) que iguala la geometría de la webfont al fallback de sistema → cero salto de layout al cargar (enfoque Fontaine / next/font). Las métricas se precalculan por fuente.
  • unicode-range subsetting (latin / latin-ext separados) → cargar solo lo usado.
  • preload de la familia crítica (primary regular).
  • Tipo: FontFamily += axes?: { wght?: [min,max]; opsz?: [min,max] } + sizeAdjust? / overrides de métricas + unicodeRanges?. source ya existe. ✅
  • Optical sizing ✅: font-optical-sizing: auto en :root cuando alguna familia declara opsz.
  • Eje de peso variable ✅: cuando un face omite weight y la familia declara axes.wght, el @font-face emite el rango (font-weight: 100 900) → un solo face cubre todo el eje. (render-css > renderFontFace; test en active-eidos-config.test.ts.)

Estado §5: el motor está cableado — @font-face config-driven, fallback anti-CLS, unicode-range, y ahora el consumo de axes (rango de peso + optical sizing). Inerte hasta que un tema declare axes — como el wide-gamut de color: listo, pero no ejercitado por los assets actuales (TTF estáticas). Pendiente de assets: migrar a woff2 variable reales; preload (cierre aparte).

6. Tracking · leading · features · measure · wrap (Fase 3)

  • Tracking/leading como escalas (estilo Tailwind): TypographyPrimitiveSet += tracking + leading → --tracking-{key} / --leading-{key}. Tracking óptico por defecto (negativo en display, ~0 en body, positivo en xs/caption).
  • font-feature-settings: features?: Record<string,string> → --font-feature-{key} (presets tabular, oldstyle, ligatures, smallcaps). Prop numeric en componentes.
  • Measure: token --measure-{key} (60ch/66ch/72ch) para prosa legible.
  • text-wrap: props wrap: 'balance' | 'pretty' | 'nowrap' en <Text>/<Heading> (keyword CSS, sin token); default balance en headings, pretty en prose.

7. Vínculo con <SText> (brazo de medición)

El motor canvas-text cuenta líneas exactas replicando el navegador (ya productionizado). Es la otra mitad del sistema: la tipografía visual (este RFC) y la medición (SText). Al emitir fluid/tracking, <SText> los mide igual (lee getComputedStyle real), así que el conteo sigue siendo fiel sin cambios — el epoch de useFontReady (T1) ya cubre el re-cálculo tras cargar variable fonts.

8. Doctrina (paralela a color)

  • Escala + estilos nombrados = canon del eidos (como roles/variants de color): valores themeables, pero el set de estilos es canon.
  • Fuentes = dato del tema (como la paleta): el tema trae las suyas.
  • Fluid / tracking / features = capacidades del motor, default-on con fallback (como el wide-gamut OKLCH): sRGB-idéntico donde no hay soporte.
  • Theme = retintar/retipar lo perceptualmente fijo: cambia QUÉ fuente es primary, no QUÉ significa h1.

9. Contrato de tokens (añadidos)

Congelados, bare-prefixed (§6 THEMING). Nuevos: --tracking-{key}, --leading-{key}, --font-feature-{key}, --measure-{key}. Reformulados (mismo nombre, valor fluido): --font-size-{key}. Sin cambios de nombre → cero rotura de componentes.

10. Fases — estado (cerrado)

  1. ✅ Motor fluido — type-scale.ts (puro fluidClamp) + FluidSize + clamp() rem en appendTypographyDeclarations (scaling compone); @media de size retirado.
  2. ✅ Fuentes — @font-face config-driven + fallback anti-CLS (métricas) + unicode-range + FontFamily.axes (rango de peso variable + font-optical-sizing) + font preloads (collectFontPreloads / eidos.fontPreloads()). Assets aún TTF estáticas → la variabilidad es capacidad de motor, no visible todavía (como wide-gamut).
  3. ✅ Tracking/leading/features/measure/wrap — escalas config-driven + props de componente (<Text>/<Heading>) + tokens semánticos (--leading-{role} / --tracking-{role}) ahora config-driven (typography.semanticLeading / semanticTracking).
  4. ✅ Escala — diseño de dos zonas (intencional), ver abajo. NO se cambiaron los valores (sería regresión perceptual): la "irregularidad" es deliberada.
  5. ✅ Docs + demo — este RFC + demo /temas/tipografia (escala/familias/ejes en vivo)
    • eidos.applyTypeScale(seed) runtime (buildTypeScale, hermano de applyColorScheme).

Fase 4 — la escala es un diseño de dos zonas (intencional)

La escala (xxs 10 · xs 12 · sm 14 · md 16 · lg 18→20 · xl 24→28 · xxl 40→48 · xxxl 64→80) NO es un único ratio modular, y eso es deliberado:

  • Zona UI (xxs–md): pasos finos (~1.14–1.2) para controles, etiquetas y cuerpo, donde la granularidad importa y los saltos grandes molestan.
  • Zona display (lg–xxxl): saltos grandes (~1.25–1.7) para jerarquía y titulares, donde el contraste manda.

Un ratio único uniforme (lo que produce applyTypeScale) es la alternativa opt-in en runtime; la escala autorada conserva su afinado de dos zonas (como Radix / Material, que también afinan en vez de imponer un ratio puro). Cambiarla sería una regresión, no una mejora — por eso Fase 4 es documentación, no recableado.

Verificación por fase

  • npm run check 0 errores; render-css snapshot regenerado (generated/base.css).
  • Backward-compat: un config con sizes en px (string) sigue emitiendo igual.
  • Navegador: el fluid escala con el viewport; <SText> cuenta líneas correctas; sin CLS al cargar las variable fonts.

Fuera de alcance

  • Justificación / guionado / balanceo de líneas propio (el navegador + text-wrap lo hacen; <SText> solo mide).
  • Subsetting dinámico en runtime (los unicode-range estáticos bastan).

Powered by TurnKey Linux.