La técnica de programar mi letra a mano
(amygoodchild.com)Escritura de imprenta
- El artículo anterior trataba sobre una versión en imprenta de las letras del alfabeto.
- En resumen, se hizo mediante el siguiente proceso:
- Escribir código que define los puntos clave de la ruta de cada letra (~10 puntos por letra).
- Suavizar la ruta usando el algoritmo de curvas de Chaikin.
- Convertir la ruta en una forma de grosor variable.
- Dibujar la ruta de la forma usando p5js.
- Se veía así:
- Pronto habrá un artículo sobre cómo generar oraciones con este sistema. Suscríbete al boletín para enterarte.
- Definir las rutas originales de las letras era un trabajo muy manual: había que escribir las posiciones en el código y ajustar los puntos hasta que la letra se viera bien.
- Al programar la cursiva, simplifiqué este proceso.
Diseño de letras
- Creé una herramienta para definir y exportar los puntos clave de una ruta, de forma que fuera fácil acceder a ella desde el editor de p5js.
- Muestra una letra de ejemplo y ofrece un área para diseñar letras nuevas.
- Los pasos son los siguientes:
- Hacer clic para colocar los puntos clave de la ruta; se muestra la ruta curva resultante con Chaikin.
- Presionar
ppara cambiar al modo de edición. - Seleccionar puntos y arrastrarlos hasta su posición.
- Presionar
enterpara imprimir la ruta en la consola.
- Hice de 2 a 3 opciones para cada letra.
- La ruta resultante se ve así:
[{x:0.7,y:22.5},{x:8.2,y:18.1},{x:8.9,y:11.2},{x:3.7,y:11.4},{x:1.7,y:18.9},{x:8.4,y:22.4},{x:17.7,y:22.0}] - Quería usar mi propia letra como guía, así que escribí ejemplos en minúsculas y mayúsculas, cargué la imagen directamente en la herramienta y la calcé.
- Usé las teclas
w/a/s/dpara colocar la imagen en la posición correcta, yr/epara ampliar o reducir la imagen. - Los números son las coordenadas
x ypara colocar esa área en la ventana de generación de letras. - Después de crear todas las rutas, dibujar las curvas y convertirlas en formas de ancho variable, cada letra se veía así de manera individual.
Convertirlo en cursiva
- A veces conectar letras es fácil. Basta con pasar directamente de la ruta de puntos clave de una letra a la siguiente y luego aplicar la curva de Chaikin de una sola vez.
- Pero algunos pares de letras no encajan bien.
- Por ejemplo, en el par na, el último punto de n está abajo y el primero de a está arriba, así que aparece una ruta que cruza a en diagonal y hace que parezca una e.
- En el par ti, t termina por encima de la línea base e i empieza en la línea base, lo que crea una cresta poco natural.
- Para resolver estos problemas, se pueden agregar puntos extra al inicio de a y eliminar los dos últimos puntos de t.
- Sin embargo, no es posible modificar las letras así en todos los escenarios.
- Por ejemplo, si a está al principio de una palabra, el punto extra queda en el lugar equivocado, y si va después de una letra como w, aparece una línea que cruza a de otra manera.
- Si t forma pareja con k, también se deforma.
- Los puntos de inicio y fin de la ruta de una letra deben variar según su posición respecto de las otras letras.
- Al principio intenté detectar pares “problemáticos” específicos y escribir reglas para ellos, pero al final opté por agregar números al inicio y al final de cada ruta para indicar lo siguiente:
- No se conecta con otra letra (0)
- Se conecta con otra letra alrededor de la línea base (1)
- Se conecta con otra letra justo por encima de la línea base (2)
- Se conecta con otra letra alrededor de la altura x (3)
- Ejemplo:
- Ahora cada ruta de letra se ve así. Fíjate en los números de un dígito al inicio y al final:
[0,{x:12.2,y:13.2},{x:13.5,y:11.0},{x:6.2,y:8.4},{x:1.1,y:13.0},{x:1.8,y:19.0},{x:7.0,y:23.4},{x:15.2,y:23.6},{x:18.4,y:22.1},1] - Probé todos los pares de letras:
- Aquí se puede ver que tengo varias opciones de ruta para cada letra, y también los cambios que se producen cuando una letra se edita según las letras vecinas.
- Idealmente me gustaría tener al menos de 5 a 6 opciones de ruta por letra, pero hay que equilibrarlo con el tamaño del archivo.
Generación de palabras
- Cuando se genera una palabra:
- Para cada letra se elige una ruta base entre 2 o 3 opciones diferentes.
- La información sobre el final de la ruta se pasa a las letras vecinas (como distintas opciones de ruta para una misma letra pueden tener diferentes puntos finales, primero hay que elegir todas las rutas de letras).
- La ruta base se ajusta en respuesta a las letras vecinas. Por ejemplo, si la altura final de la letra anterior es 2, se elimina 1 punto al inicio de esta ruta; o si la altura inicial de la siguiente letra es 1, se agrega un punto extra en una posición específica.
- La función de ajuste puede ser algo compleja. Por ejemplo, la función para la letra q es la siguiente:
// ip = ruta // pc = información del final de la letra anterior // nc = información del inicio de la siguiente letra // n = índice de la ruta elegida para esta letra adjust: (ip, pc, nc, n) => { // agregar una interrupción al final de esta letra con 70% de probabilidad if (rand() < 0.7 ) ip.splice(-1, 1, 0); // si se eligió [2] para esta ruta entre las 4 opciones if (n < 2) { // si la letra anterior termina en 3, reemplazar los dos primeros puntos por otro punto if (pc == 3) ip.splice(1, 2, {x:10,y:12}); // de lo contrario, si no es 0, agregar un punto al inicio else if (pc > 0) ip.splice(1, 0, {x:10,y:20}); } // si no hay interrupción entre esta letra y la siguiente (0) if (nc > 0 && ip[ip.length-1] != 0){ // reemplazar los dos últimos puntos por otro punto ip.splice(-3, 2, {x:16,y:34}); } } - Pero muchas veces es corta. Por ejemplo, la función para la letra n es la siguiente:
adjust: (ip, pc, nc) => { // si la siguiente letra empieza en 3, generar una interrupción aleatoria o mover el último punto if (nc == 3) rand() < 0.3 ? ip.splice(-1, 1, 0) : ip.splice(-2, 1, {x:17,y:23.8}); } - Luego se conectan todas las rutas base de las letras. En este proceso se ignoran los 1, 2 y 3 de las rutas, pero cada vez que aparece un 0 se inicia una ruta nueva para generar una interrupción.
- Después, las rutas se convierten en curvas, luego en formas de ancho variable, y se agrega un poco de vibración usando ruido Perlin; así se ve la escritura cursiva.
- Pronto habrá un artículo sobre cómo generar esta oración. Suscríbete al boletín para enterarte.
- Y por diversión, aquí hay una comparación lado a lado entre la letra programada ejecutada con un plóter y la letra real.
¿Cuánto pesa?
- La clase de letras para imprenta pesaba 9.7kb.
- La clase de letras cursivas ahora pesa 26.1kb (comprimida).
- Esta clase es más grande porque incluye varias rutas por letra y funciones para ajustar los puntos. Pero también hay algunas otras formas de ahorro.
- Creo que todavía se puede reducir más. No soy un mago del code golf, pero tengo algunas ideas.
- Por ejemplo, actualmente las letras están diseñadas con un tamaño base de fuente de 20 y luego se escalan. Eso significa que muchos puntos están definidos como
x: 14.5, pero si cambio el tamaño base a 200 podría definirlos como 145 y eliminar los decimales. Como ese cambio hay que hacerlo con cuidado, lo dejé para mi lista de pendientes.
Cómo usarlo
- El objetivo principal de esta letra es usarla en los títulos, etiquetas y notas tipo garabato de los diagramas en los que estoy trabajando.
- Pero también es muy divertido jugar con el texto en sí.
- Como las rutas están codificadas, en vez de usar una fuente se puede jugar directamente con las rutas. Por ejemplo, mover la posición de las letras o cambiar el grosor de letras individuales.
- Lo próximo será integrar esta letra en mis diagramas, pero también planeo crear algo centrado en el texto mismo. Es muy bonito y tiene muchísimas posibilidades.
Opinión de GN⁺
- Este artículo ofrece un ejemplo interesante del proceso de digitalizar la escritura a mano usando JavaScript y p5.js. Puede ser una buena oportunidad para que los ingenieros de software practiquen sus habilidades de programación mediante un proyecto creativo.
- Se puede aprender cómo aplicar algoritmos matemáticos como el de curvas de Chaikin en proyectos reales. Esto ayuda a profundizar la comprensión de la programación gráfica.
- También se puede aprender a manejar lógica compleja, como las funciones de ajuste de rutas. Esta es una habilidad importante para mejorar la flexibilidad y escalabilidad del código.
- El proyecto aborda problemas prácticos como la optimización del tamaño de archivo. Eso es una consideración importante en el desarrollo de software real.
- Al adoptar esta técnica, hay que tener en cuenta que definir rutas y escribir funciones de ajuste puede tomar mucho tiempo. Sin embargo, el resultado ofrece una forma de expresión de texto muy personalizada y única.
Aún no hay comentarios.