La Anatomia de un Input Universal: Como un Dedo, un Mouse y un Lapiz Wacom se Convierten en la Misma Senal
Tres dispositivos entran a tu navegador. Uno reporta coordenadas cartesianas con un booleano de click. Otro anade fuerza capacitiva. El tercero escupe siete propiedades en tiempo real, desde presion hasta rotacion del barril. El trabajo del motor de FAP Desktop Web es recibir esa cacofonia y devolver una sola cosa: una senal normalizada que el motor de dibujo entienda sin preguntar que hay del otro lado. Esto no es un problema de drivers. Es un problema de filosofia de la ingenieria.
La Torre de Babel del Input
Abre las herramientas de desarrollador y escucha los eventos que tu hardware le envia al navegador. Un mouse reporta {clientX, clientY, buttons}. Tres campos. Un dedo sobre una pantalla tactil reporta {clientX, clientY, force}. Misma estructura, pero force no es buttons. Un lapiz Wacom, Huion o XP-Pen reporta {clientX, clientY, pressure, tiltX, tiltY, twist, tangentialPressure}. Siete campos, cinco mas que el mouse. Son lenguajes distintos hablandole al mismo programa.
El problema no es nuevo. Los sistemas operativos llevan decadas traduciendo HID reports a eventos de sistema. Pero en la web, hasta la llegada de Pointer Events en 2015, cada tipo de input vivia en su propio reino: MouseEvent, TouchEvent, y los fabricantes de tabletas rogando que alguien implementara algo decente. Pointer Events unifico la capa de transporte: ahora todo dispositivo emite eventos con la misma interfaz. Pero unificar el transporte no resuelve la disparidad semantica. Un pointerType='mouse' nunca tendra tiltX. Un pointerType='touch' en Android rara vez tendra pressure. La API te da el canal. El resto lo construyes tu.
La Maquina de Normalizacion
FAP implementa una funcion de traduccion universal. Su proposito es tomar cualquier evento de puntero –venga de donde venga– y devolver un objeto con propiedades estandar que el motor de pinceles pueda consumir sin bifurcaciones:
function getPos(e) {
const rect = drawCanvas.getBoundingClientRect();
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
return {
x: (clientX - rect.left) * (drawCanvas.width / rect.width),
y: (clientY - rect.top) * (drawCanvas.height / rect.height),
pressure: e.touches ? (e.touches[0].force || 1) : (e.pressure || 0.5),
tiltX: e.tiltX || 0,
tiltY: e.tiltY || 0
};
}
Cada linea de esta funcion es una decision de diseno con consecuencias matematicas y filosoficas.
La conversion de coordenadas es la primera capa de abstraccion. El factor drawCanvas.width / rect.width desacopla la resolucion logica del canvas de su representacion visual en pantalla. Internamente, FAP siempre dibuja sobre un canvas de 1920×1080. Externamente, el CSS lo escala con width:100% para que quepa en tu viewport. Sin ese factor de conversion, un click en la posicion 500 de una ventana de 1366 pixeles se mapearia a la coordenada 500 del canvas interno, cuando en realidad corresponde a la coordenada 703 en el espacio logico de 1920. Cada trazo estaria desplazado. La correccion es trivial en codigo, pero su ausencia destruiria la experiencia completa.
La presion sigue una logica de fallback en cascada. Si estas en un dispositivo tactil que reporta force (iOS), se usa ese valor. Si estas en una tableta grafica con pressure, se usa ese. Si no hay nada –como con un mouse– se asume 0.5. El motor de pinceles nunca recibe undefined. Nunca bifurca. Aplica la misma formula brushSize * pressure para todos. La calidad del arte varia segun tu hardware, pero la herramienta no te castiga.
La Presion como Coeficiente de Modulacion
En el mundo fisico, presionas mas fuerte y sale mas pintura. En FAP, la presion deja de ser una sensacion tactil y se convierte en un escalar que modula dos variables criticas:
brushSizeFinal = brushSize * pressure
brushOpacityFinal = brushOpacity * pressure
Con un lapiz Wacom, event.pressure entrega valores de 0.0 a 1.0 en aproximadamente 1024 niveles discretos. Cada micro-variacion en la fuerza de tu mano produce un incremento de ~0.001 en el coeficiente. El trazo responde con la misma granularidad: un degradado de grosor y opacidad que sigue la fisiologia de tus dedos.
Con un dedo en iOS, force te da un rango similar, aunque con menos granularidad. Con un mouse, el coeficiente es 0.5 fijo. El motor no sabe lo que hay del otro lado del evento. Recibe un numero entre 0 y 1 y lo multiplica. Punto. Esta indiferencia del motor hacia el origen del dato es lo que hace posible que la misma herramienta funcione con un touchpad de laptop, una Wacom Cintiq de 2000 dolares, o el trackpoint de una ThinkPad. El codigo es identico. La senal es identica. Lo unico que cambia es la fidelidad del dato de entrada.
Tilt: Cuando el Angulo Importa
Los pinceles caligraficos no producen circulos. Producen elipses cuyo ratio depende del angulo entre el lapiz y la tableta. Un lapiz perpendicular a la superficie genera un trazo circular. Un lapiz inclinado a 45 grados genera un trazo eliptico donde la altura es el coseno del angulo multiplicado por la anchura.
FAP lee event.tiltX y event.tiltY –angulos entre -90 y 90 grados– y los convierte en deformacion del pincel:
tiltAngle = atan2(tiltY, tiltX) * (180 / PI)
tiltMagnitude = sqrt(tiltX^2 + tiltY^2)
Si el pincel tiene definida la propiedad slant y los datos de tilt existen, FAP modula la escala vertical del trazo. El resultado es un pincel caligrafico que responde al angulo de tu mano igual que una plumilla metalica sobre papel. Inclinas la muneca y el trazo se estiliza. Enderezas y vuelve a ser redondo. Es la diferencia entre una linea generada por computadora y una linea que parece dibujada por una persona.
Con un mouse, tiltX y tiltY son siempre 0. El pincel caligrafico se comporta como un pincel redondo estandar. No hay deformacion. No hay caracter. La herramienta no te lo niega: simplemente no tienes los datos para activar esa dimension de expresion. Pero enchufas una tableta y, sin tocar una sola configuracion, esa dimension cobra vida. El mismo pincel, el mismo codigo, la misma funcion getPos. La abstraccion lo hizo posible.
La Paradoja del Input Perfecto
Cuando pasas suficiente tiempo abstrayendo inputs, llegas a una conclusion inquietante: el dispositivo perfecto no existe. El lapiz Wacom te da precision sub-pixel, 1024 niveles de presion, tilt, twist, y presion tangencial. Pero requiere una superficie. No puedes dibujar en el aire. El dedo es inmediato, no necesitas cargar nada, pero tu propia mano tapa lo que estas dibujando y la precision es baja. El mouse es preciso y ubicuo, pero carece de presion, tilt y cualquier dato analogico. Son tres optimos de Pareto: no puedes maximizar portabilidad, precision y expresividad simultaneamente.
FAP no resuelve esta paradoja. La abraza. En lugar de forzarte a un dispositivo, te da lo mejor del que tengas en este momento. La arquitectura de normalizacion de inputs significa que la herramienta no tiene favoritos. Los parametros que un mouse deja en 0 —tiltX, tiltY, twist, tangentialPressure— estan ahi, esperando. Cuando conectas una Wacom, esos ceros se convierten en datos reales. El motor no cambio. Tu input cambio. La herramienta se expandio porque su arquitectura ya contemplaba esas dimensiones antes de que existieran en tu escritorio.
Esto es ingenieria de abstraccion en su estado mas puro. No programas para dispositivos. Programas para senales.
Programamos para Senales
En Free Animation Power, un dedo, un mouse y un lapiz Wacom son, en el fondo, la misma cosa: un flujo de coordenadas con metadatos opcionales. Al abstraer el input a su esencia matematica –posicion, presion, inclinacion– creamos un motor de dibujo que funcionara con cualquier dispositivo que la humanidad invente manana.
Porque manana habra otro input. Un guante haptico. Un sensor ocular. Una interfaz neuronal. Lo que sea. Pero la senal, en su nucleo irreductible, sera siempre (x, y, pressure, tiltX, tiltY). Cinco numeros. Cinco dimensiones. Y FAP ya sabe que hacer con ellos.
Eso es lo que construimos en esas 2,867 lineas de codigo que corren en tu navegador, en este momento, esperando que muevas el cursor. No un editor de dibujo. Un traductor universal de intencion humana a pixeles en pantalla.
Eduardo Fierro Duque — fierroduque.com
Hashtags: #InputUniversal #UniversalInput #AnatomiaDelInput #InputAnatomy #PointerEvents #NormalizacionDeEntrada #InputNormalization #Mouse #Finger #Dedo #Lapiz #Pen #Wacom #CoordinateSystem #SistemaDeCoordenadas #Pressure #Tilt #Inclinacion #AbstraccionDeInput #InputAbstraction #SenalNormalizada #NormalizedSignal #MotorDeDibujo #DrawingEngine #FreeAnimationPower #FAP #DesktopWeb #ClientX #ClientY #getBoundingClientRect #FactorDeConversion #ConversionFactor #Fallback #CascadaDeFallback #FallbackCascade #ParetoOptimal #OptimoDePareto #TouchEvent #MouseEvent #PenInput #TouchInput #HID #HumanInterfaceDevice #TrackPoint #ThinkPad #iOSforce #AndroidTouch #Caligrafico #Calligraphic #atan2 #IngenieriaWeb #WebEngineering #DispositivosDeEntrada #InputDevices #ArquitecturaDeSoftware #SoftwareArchitecture #ProgramamosParaSenales #ProgrammingForSignals
