Interfaces en pixel art: cajas de texto, fuentes y japonés
La caja de diálogo de Pokémon Emerald es un marco de 30 por 6 tiles, todo el ancho de 240 pixeles de la pantalla y el 30 % de su altura, alrededor de una ventana de texto de 27 por 4 tiles que contiene dos líneas de una fuente de 16 pixeles; la de Crystal mide 20 por 6 tiles, dos líneas de 18 caracteres.123 Emerald imprime un carácter cada 8, 4 o 1 fotogramas según su ajuste de velocidad, 7,5, 15 o 60 por segundo a 60 hercios; el ajuste rápido de Crystal y Final Fantasy VI también imprimen uno por fotograma.14 Los guionistas de Emerald cortaron cada línea a mano: en 24.100 líneas de texto del guion, la más ancha mide 208 pixeles frente a una ventana de 216, y ninguna se desborda.1 Una fuente pixelada japonesa que cubre el conjunto estándar dibuja unos siete mil caracteres: JIS X 0208 tiene 6.879, Misaki los dibuja todos en una celda de 8 por 8, PixelMplus10 todos salvo tres puntos de código sobre una cuadrícula de 10 pixeles, y el productor de Final Fantasy Pixel Remaster cifró la nueva fuente japonesa de su equipo en «around 7,500 characters» (unos 7.500 caracteres).5678 En mi Mac, con el suavizado de fuentes desactivado, Core Text dibujó las fuentes pixeladas TrueType cuya cuadrícula se apoya en la línea base y cuyos avances son de pixeles enteros (Misaki, PixelMplus10 y Press Start 2P) sin ningún pixel parcial en los múltiplos enteros de su cuadrícula, y con entre el 19,4 % y el 82,2 % de los pixeles entintados emborronados entre esos múltiplos; PixelMplus12, cuya cuadrícula queda desplazada respecto de la línea base, Silkscreen, con puntos de contorno sueltos, y DotGothic16, sin cuadrícula, salieron con pixeles parciales en todos los tamaños medidos, y k8x12 en todos los tamaños en cuanto sus glifos se colocaron con exactitud; con el suavizado predeterminado del contexto de dibujo, incluso PixelMplus10 a sus propios 10 pixeles dio 178 de 272 pixeles entintados parciales.79 A 3×, un em de 10 pixeles cae en pixeles de dispositivo enteros en solo uno de los doce tamaños de Body de iOS, 40 puntos.710 Hoy Kiradex World compone cada palabra en la fuente monoespaciada del sistema, habla solo inglés y le da a VoiceOver las coordenadas de las pruebas de caminata.11 Así que medí las cajas, las fuentes y las velocidades del canon en las descompilaciones, medí cinco fuentes pixeladas japonesas y dos latinas en Core Text y escribí un encargo: una sola fuente con licencia para los dos idiomas, Dynamic Type redondeado a la cuadrícula de la fuente, un marco dibujado por la forja, dos líneas y páginas, y un escenario que VoiceOver pueda describir.
Lo esencial
- La caja es el tercio inferior y dos líneas. El marco de diálogo de Emerald mide 30 por 6 tiles (240 por 48 pixeles, el 30 % de la altura de la pantalla) alrededor de una ventana de 27 por 4 tiles con dos líneas de 16 pixeles; la caja de Crystal mide 20 por 6 tiles, el 33 % de la altura, dos líneas de 18 caracteres, y la de Red es la misma de 20 por 6. La caja de Emerald no tiene campo de nombre, y 934 de sus 14.412 párrafos de guion (el 6,5 %) nombran al hablante dentro del texto.12312
- La velocidad es un recuento de fotogramas. Emerald y FireRed tardan 8, 4 o 1 fotogramas por carácter (7,5, 15 o 60 por segundo a 60 hercios), y un fotograma mientras se mantiene A o B una vez que se ha pulsado durante la impresión; Crystal y Red esperan 5, 3 o 1 fotograma (12, 20 o 60); Final Fantasy VI dibuja el diálogo de campo a una letra por fotograma, sin ajuste para ello (su velocidad de mensajes de seis pasos es cuánto espera un mensaje de combate). La flecha de avance de Emerald se desplaza 0, 1, 2 y 1 pixeles desde el reposo, un paso cada 9 fotogramas, en un ciclo de 0,6 segundos; el ▼ de Crystal parpadea contra el tile del borde.1131415164
- Cinco fuentes gratuitas ya dibujan el japonés que necesita un juego. Misaki dibuja los 6.879 caracteres de JIS X 0208 en 8 por 8, con cada kanji dentro de 7 por 7; k8x12, en 8 por 12; PixelMplus12 y PixelMplus10 dibujan todos salvo tres puntos de código a 12 y 10 pixeles; DotGothic16 los dibuja todos, pero sin cuadrícula de pixeles. La licencia de tres frases de Misaki, k8x12 y PixelMplus concede el uso, la copia y la distribución «either commercially or noncommercially» (con fines comerciales o no comerciales).5671718
- Una fuente pixelada es nítida solo con pixeles de dispositivo enteros por pixel de fuente, y solo si el archivo está limpio. Medido con Core Text en macOS 27.0, no en un iPhone, con el suavizado de fuentes desactivado: 0,0 % de pixeles parciales en los múltiplos enteros de una cuadrícula apoyada en la línea base y con avances de pixeles enteros (Misaki, PixelMplus10, Press Start 2P), y entre el 19,4 % y el 82,2 % entre esos múltiplos.7 Con el suavizado predeterminado del contexto de dibujo, PixelMplus10 a sus propios 10 pixeles dio 178 de 272 pixeles entintados parciales, así que el resultado limpio en los múltiplos enteros solo se cumple con el suavizado desactivado.9 La cuadrícula de PixelMplus12 queda 0,39 pixeles por debajo de la línea base y, con el suavizado desactivado, se emborrona en todos los tamaños; el avance de kana de k8x12, de 8,01 pixeles, se emborrona en cuanto los glifos se colocan con exactitud.719
- Dynamic Type hay que redondearlo, no seguirlo. De los doce tamaños de Body de iOS, de 14 a 53 puntos, un em de 10 pixeles es entero a 3× solo en 40 puntos, un em de 8 pixeles en 16 y 40, y uno de 12 pixeles en 16, 28 y 40. Apple pide que una fuente personalizada implemente los comportamientos que tienen las fuentes del sistema, entre ellos Dynamic Type, y, para el texto de una app, que idealmente se pueda ampliar al menos un 200 por ciento.71020
- El salto de línea japonés es estricto sin etiqueta y laxo con etiqueta. En Core Text sobre macOS, un párrafo de 131 caracteres se cortó sin que ninguna línea empezara por un carácter de la lista de inicio de línea de la sonda (una lista parcial, en su mayoría caracteres de JLREQ, con siete en sus formas de ancho completo) en ninguno de los anchos medidos, sin etiqueta; con la etiqueta
ja, una kana pequeña abrió una línea en 6 de 7 anchos en Hiragino Sans, Misaki, PixelMplus y DotGothic16, la regla menos estricta que describen los requisitos de composición japonesa del W3C.721 - Lo que esto le da a Kiradex. Un encargo, no una compilación: PixelMplus10 para cada palabra dibujada sobre el mundo (de las dos fuentes medidas con japonés, cuadrícula limpia y avances de pixeles enteros, Misaki y PixelMplus10, la más grande), tamaños redondeados a pixeles de dispositivo enteros por pixel de fuente (16,67 puntos en el tamaño predeterminado en los iPhone de 3×, 15 en los de 2×), un marco propio dibujado por la forja, dos líneas y páginas, un revelado de 30 caracteres por segundo con una marca que avanza a pasos, globos de una línea dimensionados para caber en el iPhone más estrecho que lista el simulador de iOS 27.0 cuando sus lados no tienen márgenes, una línea que no cabe que pasa a la caja, líneas en japonés revisadas por un hablante de japonés y un escenario que VoiceOver describe con palabras en lugar de coordenadas, cada punto con una comprobación que un script, una línea de registro o una captura pueden aprobar o suspender, salvo una comprobación manual de VoiceOver.2211
1. Emerald y FireRed: un marco de lado a lado, dos líneas, escritas a mano
Esta serie empezó por el mundo y ha ido trabajando hacia dentro. Mundos de pixel art en el iPhone fijó el sistema de tiles, la receta de RealityKit y una dirección para el texto en una regla, «Text is art» (el texto es arte), y una frase de plan: «m5x7 at integer multiples in a 24-by-24 nine-slice box, two lines, typewriter reveal, a two-frame advance arrow» (m5x7 en múltiplos enteros en una caja nine-slice de 24 por 24, dos líneas, revelado de máquina de escribir, una flecha de avance de dos fotogramas).23 Los artículos posteriores construyeron el coleccionista, los edificios, el movimiento, la vida propia del pueblo, las habitaciones y los caminos. El texto se quedó en esa frase. Este artículo mide de dónde salen sus números, encuentra cuatro puntos en los que el artículo del mundo se equivoca o es impreciso y añade lo que no tenía: japonés en matrices de 8, 10 y 12 puntos, lo que Core Text hace realmente con una fuente pixelada TrueType, cómo pueden ponerse de acuerdo Dynamic Type y una cuadrícula de pixeles, el salto de línea japonés y VoiceOver sobre un escenario de RealityKit.
El texto de Kiradex World es hoy sencillo. Cada palabra es SwiftUI en la fuente monoespaciada del sistema que define el tema. Los globos sobre las cabezas de los coleccionistas son una línea del rol caption del kit en negrita, sobre papel crema con un borde de tinta de 2 puntos, mostrada mientras la línea tiene menos de 4 segundos. La línea del lugar va en una caja de texto crema en la parte inferior de la pantalla. La app está solo en inglés, las líneas predefinidas viven en el servidor en inglés, el letrero de la forja es una tabla de 12 por 11 con garabatos de tinta y ninguna letra, y VoiceOver lee el escenario como un único elemento cuyo valor es la traza de pasos de las pruebas de caminata.11242526272829 La sección 10 tiene el detalle; el encargo de la sección 12 está escrito como un diff contra eso.
Cada número de Pokémon de este artículo se midió en clones superficiales de las descompilaciones de pret, en pokeemerald 731ad5b (1 de octubre de 2026), pokefirered 037335f, pokecrystal 5beda23 y pokered d2704a6, con un único script de Python, measure_gen_text.py, cuya salida está guardada a su lado; los números de Final Fantasy VI salen de un segundo script sobre el desensamblado everything8215/ff6. Los dos se vuelven a ejecutar en segundos, y las notas nombran el archivo fuente detrás de cada cifra.3014
Las fuentes
Emerald declara sus fuentes en una sola tabla, sFontInfos en src/text.c, cada una con un ancho y una altura máximos de letra en pixeles. La fuente pequeña mide 5 por 12; la normal, la que usa la caja de diálogo, 6 por 16; la corta, 6 por 14, declarada cuatro veces (ella misma y tres copias); la estrecha, 5 por 16; la pequeña estrecha, 5 por 8; la negrita, 8 por 8; y la de braille, 8 por 16 con 8 pixeles de interlineado. Todas las demás tienen un interlineado de 0: la celda de 16 pixeles es la línea.113
La fuente latina normal es proporcional. Indexadas a través del charmap.txt del juego en gFontNormalLatinGlyphWidths de src/fonts.c, las minúsculas de la a a la z miden de media 5,77 pixeles de ancho, de 4 a 6; las mayúsculas de la A a la Z y los dígitos del 0 al 9 miden todos 6; el espacio y el punto, 3, y el signo de exclamación, 4.131 En texto corrido eso da una media de 5,25 pixeles por carácter, medida sobre cada línea del guion del juego que se analiza más abajo.1
La velocidad es un recuento de fotogramas
En Emerald, la velocidad del texto es un retardo en fotogramas. Las tres velocidades de la pantalla de Opciones se traducen, mediante sTextSpeedFrameDelays en src/menu.c, en retardos de 8 (lenta), 4 (media) y 1 (rápida). AddTextPrinter, en src/text.c, guarda el retardo menos uno como la velocidad de la impresora; la impresora pone su contador en esa velocidad guardada cuando imprime un carácter y lo descuenta de uno en uno por fotograma, y el siguiente carácter se imprime en el fotograma posterior a que el contador llegue a 0. Así, un carácter tarda el propio retardo: 8, 4 y 1 fotogramas. A 60 hercios, eso son 7,5, 15 y 60 caracteres por segundo.1213 Ese recuento es mi lectura de la máquina de estados de la impresora (AddTextPrinter y el caso RENDER_STATE_HANDLE_CHAR en src/text.c), que el script afirma en lugar de ejecutar.1 La Game Boy Advance no funciona a 60 hercios exactos: GBATEK da su fotograma como «Total 228 lines, 16.743 ms, 280896 cycles - ca. 59.737 Hz» (228 líneas en total, 16,743 ms, 280.896 ciclos, unos 59,737 Hz), 160 de esas líneas visibles, cada una de 240 puntos de ancho, de modo que el ajuste rápido da unos 59,7 caracteres por segundo en el hardware.3233
Mantener un botón acelera los ajustes más lentos. Una nueva pulsación de A o B mientras se descuenta el retardo de un carácter, en un mensaje que lo permita (gTextFlags.canABSpeedUpPrint), activa hasPrintBeenSpedUp. A partir de ahí, la impresora comprueba JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp y, cuando se cumple, baja el contador a 0: un carácter por fotograma, 60 por segundo, la misma cadencia del ajuste rápido.131
El texto con desplazamiento automático tiene su propio retardo. Cuando gTextFlags.autoScroll está activo, la impresora pone el contador en 3 en lugar de en la velocidad guardada, 4 fotogramas por carácter, salvo en los combates grabados: la condición es if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED) && gTextFlags.autoScroll).131 Los mensajes de combate activan el desplazamiento automático en los combates por cable y en los grabados, y el comando de script messageautoscroll lo activa y fuerza la velocidad media.34 Así, el retardo de 3 puede aplicarse a otras ventanas de combate en los combates por cable y a los mensajes con desplazamiento automático de los scripts, y nunca en los combates grabados, cuyos mensajes se imprimen a la velocidad que recibió la impresora: en los mensajes de combate, la velocidad de texto guardada con la grabación, salvo en un combate por cable grabado, cuya ventana de mensajes recibe 1, como la de un combate por cable.341 Según mi lectura, el contador solo corre mientras la velocidad guardada de la impresora es mayor que 0, y la ventana de mensajes de un combate por cable recibe el retardo de 1, lo que deja su texto a un carácter por fotograma con el desplazamiento automático activo.1334
Los tres códigos de corte hacen tres cosas distintas. \n baja la impresora a la segunda línea; \l espera bajo la flecha de avance a que se pulse un botón y luego desplaza la caja una línea hacia arriba; \p espera igual y luego vacía la caja y vuelve a empezar arriba.1335 En un desplazamiento, la línea de 16 pixeles sube a 1, 2 o 4 pixeles por fotograma según el ajuste de velocidad (sWindowVerticalScrollSpeeds), así que un desplazamiento tarda 16, 8 o 4 fotogramas.113
La velocidad del texto en cada juego medido y los dos ajustes que propone el encargo; dibujado por figures/make_figures.py a partir de las salidas de las mediciones.
La flecha
Cuando una página está llena, la caja espera bajo una flecha pequeña. Emerald copia una celda de flecha de 8 por 16 con desplazamientos verticales de { 0, 1, 2, 1 } pixeles (sDownArrowYCoords) y la vuelve a dibujar cuando se agota su retardo, que se reinicia a 8. Eso es un paso cada 9 fotogramas y un ciclo de 36 fotogramas, 0,60 segundos a 60 hercios.113 La flecha no parpadea; se balancea, por tres posiciones y de vuelta.
La caja y su marco
La caja de texto de campo de Emerald la define sStandardTextBox_WindowTemplates en src/menu.c. La ventana de texto está en la columna de tiles 2, fila 15, y mide 27 por 4 tiles: 216 por 32 pixeles, dos líneas de la fuente normal de 16 pixeles. Su marco, dibujado por WindowFunc_DrawDialogueFrame y evaluado por el script para esa ventana, va de la columna 0 a la 29 y de la fila 14 a la 19: 30 por 6 tiles, 240 por 48 pixeles, todo el ancho de la pantalla y el 30 % de sus 160 pixeles de altura.12
Ese marco no es un nine-slice. LoadMessageBoxGfx lo carga de message_box.png, una tira de 56 por 16 pixeles, 14 tiles, y el marco se dibuja a partir de ocho posiciones de tile, con la fila inferior igual a la superior volteada verticalmente con BG_TILE_V_FLIP.1362 El script mide la extensión del marco y el tamaño del PNG; el volteo se lee en las llamadas de relleno.1
Los marcos que elige el jugador son para las otras ventanas: los menús y las cajas de sí o no. WINDOW_FRAMES_COUNT vale 20, y los veinte marcos son PNG de 24 por 24 pixeles, tres por tres tiles de 8, que carga LoadUserWindowBorderGfx según el tipo de marco que guarda la opción FRAME de la pantalla de Opciones.136
Eso corrige el artículo del mundo. Su regla 10 dice «Pokémon Emerald’s text-window frame is a 24-by-24 image, three by three hardware tiles, which is a nine-slice» (el marco de la ventana de texto de Pokémon Emerald es una imagen de 24 por 24, tres por tres tiles de hardware, es decir, un nine-slice).23 Las veinte imágenes de 24 por 24 de graphics/text_window/ son los marcos seleccionables de las ventanas de menú. La caja de diálogo, la caja de texto que recuerdan los jugadores, se dibuja a partir del message_box.png de 56 por 16 pixeles como un marco de 30 por 6 tiles con el borde inferior reflejado, no como un nine-slice de una imagen de 24 por 24.136 La idea del nine-slice se sostiene, y los menús la usan; la atribución a la caja de diálogo, no.
Las dos cajas de diálogo como cuadrículas de tiles, sin arte de los juegos; dibujado por figures/make_figures.py, que comprueba cada extensión contra measure_gen_text.out.
El texto se escribió para la caja
Para ver lo llena que va la caja, el script leyó cada línea del texto de guion de Emerald: 504 archivos, los 36 de data/text/*.inc y los scripts.inc de los 468 mapas, 24.100 líneas sin marcador de sustitución y 3.000 con uno, cortadas en los tres códigos de corte del juego, \n, \l y \p. La línea mediana tiene 29 caracteres y 150 pixeles; el percentil 95, 38 caracteres y 196 pixeles; la más larga, 53 caracteres, y la más ancha, 208 pixeles. Ninguna supera los 216 pixeles de la ventana, y el carácter medio mide 5,25 pixeles de ancho.137
A 5,25 pixeles por carácter, la ventana admite 41; los guionistas se quedaron en 38 en el 95 % de las líneas.331 Cada corte es un código colocado a mano. El juego nunca ajusta una línea; confía en quien la escribe.
La caja tiene una sola ventana y ningún campo de nombre. Cuando los guionistas querían un hablante, escribían el nombre y dos puntos dentro de la línea, como en el «MOM: {PLAYER}, we’re here, honey!» (MAMÁ: {PLAYER}, ¡ya llegamos, cariño!) de Littleroot Town. De 14.412 párrafos, 934, el 6,5 %, empiezan con un nombre en mayúsculas y dos puntos.137 Que no haya un campo de nombre aparte es mi lectura de la plantilla de ventana, que tiene sitio para las dos líneas de texto y nada más.2
Japonés en el juego en inglés
El Emerald en inglés sigue llevando glifos japoneses, para los nombres de criaturas y entrenadores que vienen de cartuchos japoneses. La impresora cambia de juego de glifos con el código de control EXT_CTRL_CODE_JPN y vuelve con EXT_CTRL_CODE_ENG, que llevan esos nombres (los insertan international_string_util.c, contest.c y battle_tower.c). En ese modo, la fuente normal mide 8 pixeles de ancho para cada carácter y 15 de alto (DecompressGlyph_Normal, y GetGlyphWidth_Normal devuelve 8).11338
Las hojas a partir de las que se compila la ROM en inglés: japanese_normal.png mide 128 por 512 pixeles en celdas de 8 por 16, con 302 de sus 512 celdas dibujadas; japanese_small.png, del mismo tamaño, 307 dibujadas; japanese_bold.png, 128 por 256, 246 de 256 dibujadas; y el japanese_frlg_male.png de FireRed, también en el árbol de Emerald, 256 por 512 pixeles en celdas de 16 por 16, 269 de 512 dibujadas, con una tabla de anchos de 512 entradas de 0 a 10 pixeles, 10 en 408 de ellas.138 pret compila los juegos en inglés, así que estas son las hojas para nombres de una ROM en inglés; no se leyó la caja, las velocidades ni la fuente propias de ninguna ROM japonesa (sección 11).30
Así que, en los propios términos del canon, un carácter japonés en una línea de 16 pixeles mide 8 pixeles de ancho en Emerald y casi siempre 10 en la hoja de FireRed, frente a una letra latina de 4 a 6.1
FireRed
FireRed conserva los retardos de Emerald, 8, 4 y 1, guardados menos uno por su propio AddTextPrinter en src/text_printer.c igual que los de Emerald, y una ventana de texto estándar de 26 por 4 tiles en la columna 2 (src/new_menu_helpers.c), un tile más estrecha que la de Emerald.139 Su impresora también tiene el mantenido de Emerald: if (JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp) baja el contador a 0, y una nueva pulsación de A o B mientras se descuenta el retardo de un carácter, en un mensaje que lo permita, activa hasPrintBeenSpedUp.14
2. Crystal y Red: dieciocho caracteres y una marca que parpadea
La caja de la Game Boy es el antepasado de la de la Game Boy Advance a una resolución menor. La pantalla de Crystal mide 20 por 18 tiles (SCREEN_WIDTH 20, SCREEN_HEIGHT 18), 160 por 144 pixeles. Su caja de texto es TEXTBOX_WIDTH = SCREEN_WIDTH por TEXTBOX_HEIGHT 6: todo el ancho y un tercio de la altura, el 33 %. Con BORDER_WIDTH 2, el interior mide 18 por 4 tiles, y la fuente de 8 por 8 da 18 caracteres por línea. El texto empieza dos filas dentro de la caja, TEXTBOX_INNERY = TEXTBOX_Y + 2, y las líneas están a dos filas de distancia, así que la caja muestra dos líneas con una fila en blanco entre ellas; la disposición en dos líneas es mi lectura de esas constantes.13 La caja de mensajes de Red es db MESSAGE_BOX, 0, 12, 19, 17: los mismos 20 por 6 tiles en la parte inferior.112
Los dos juegos también cuentan la velocidad en fotogramas. Los retardos son TEXT_DELAY_FAST 1, medio 3 y lento 5 fotogramas por letra: 60, 20 y 12 letras por segundo a 60 hercios. El PrintLetterDelay de Crystal lo dice sin rodeos: «The text speed setting in wOptions is actually a frame count» (el ajuste de velocidad del texto en wOptions es en realidad un recuento de fotogramas). Mientras se mantiene A o B, espera un fotograma por letra.115 Así que el ajuste rápido de Crystal coincide con el de Emerald, 60 por segundo, y mantener A o B en Emerald da la misma cadencia; los ajustes medio y lento de Crystal, 20 y 12, son más rápidos que los 15 y 7,5 de Emerald.1 Pan Docs da el fotograma de la Game Boy como «One frame: 70224 dots @ 59.7 fps» (un fotograma: 70.224 puntos a 59,7 fps) y señala que un fotograma «takes ~16.74 ms instead of ~16.67» (tarda unos 16,74 ms en lugar de unos 16,67).40
Crystal deja que el jugador elija entre ocho marcos, de FRAME_1 a FRAME_8, cada uno de TEXTBOX_FRAME_TILES, 6 tiles de 1 bit, guardados como PNG de 24 por 16 pixeles; un noveno marco está en la ROM sin usar. La hoja de la fuente, gfx/font/font.png, mide 128 por 64 pixeles, 128 celdas de 8 por 8, y la de Red tiene el mismo tamaño.141
La marca parpadea
La marca de avance de Crystal forma parte del marco. WaitPressAorB_BlinkCursor espera A o B mientras BlinkCursor alterna el tile de (18, 17), en la propia fila inferior del marco, entre '▼' y el tile de borde '─'.16 Los dos estados se leen en el código; el periodo del parpadeo no se dedujo (sección 11).
Esa es la segunda imprecisión del artículo del mundo. Su plan de texto pide «a two-frame advance arrow» (una flecha de avance de dos fotogramas).23 Una marca de dos estados es el parpadeo de Crystal. La flecha de Emerald, la que sigue el resto de ese plan (la línea de 16 pixeles, la caja abajo), no parpadea: recorre tres posiciones, 0, 1, 2 y 1 pixeles desde el reposo, en un ciclo de 36 fotogramas (el código desplaza las filas de origen del mapa de bits, lo que, según mi lectura, eleva la cuña en pantalla; no lo he ejecutado).113 El encargo de la sección 12 sigue los pasos de Emerald, no su dirección.
3. Final Fantasy VI: una ventana que repintas, una fuente que se ajusta sola
Final Fantasy VI trata la ventana como algo del jugador. Sus números salen aquí del desensamblado everything8215/ff6 en 8130132 (14 de septiembre de 2026), que contiene código y listas de extracción en lugar de los gráficos de la ROM, así que los tamaños salen de rangos de bytes y del código que los lee.304
Ocho ventanas, siete colores cada una
Las listas de extracción en inglés y en japonés dan los gráficos de ventana como 0xED0000 a 0xED1BFF, 7.168 bytes: ocho estilos de 896 bytes, cada uno de 28 tiles de 8 por 8 a 4 bits por pixel. Sus paletas vienen después, de 0xED1C00 a 0xED1CFF, ocho paletas de 16 colores.442 La pantalla de configuración lista 8 patrones de ventana (ConfigWindowNumPos).443
El color de la ventana lo decide el jugador. LoadWindowPal lee los colores del patrón en la memoria de guardado, en $1d57, 14 bytes por patrón, es decir, siete colores de dos bytes, y la pantalla de configuración los edita con barras de R, G y B (ConfigColorBarTextList); un color más, el de la fuente, está en $1d55.443 El paso de 14 bytes se lee en el código y los tres canales, en la lista de barras.4
La velocidad de mensajes de la pantalla de configuración tiene seis ajustes, del 1 al 6 (ChangeConfigOption_02 se detiene en $05), y una partida nueva empieza con «message speed = 3, battle speed = 3» (velocidad de mensajes = 3, velocidad de combate = 3), como lo dice el comentario de menu_sram.asm.443 Es la velocidad de los mensajes de combate, como la llama config.asm en un comentario, «battle speed, battle message speed, magic order, and window pattern» (velocidad de combate, velocidad de mensajes de combate, orden de la magia y patrón de ventana). Fuera de la pantalla de configuración, el único código que lee sus bits del byte de configuración, $1d4d, es mess_wait en src/btlgfx/gfx_cmd.asm, que busca el ajuste en MsgSpeedTbl, «wait duration for each battle message speed» (duración de la espera para cada velocidad de mensajes de combate), y espera esa cantidad de fotogramas: 32, 48, 64, 80, 96 o 112 para los ajustes 1 a 6. Ningún archivo del código de campo lee $1d4d, así que el diálogo de campo no tiene ajuste de velocidad; se imprime a la única cadencia que se describe más abajo.444
Una ventana sombreada sin un tile
La ventana de diálogo se sombrea a lo largo de su altura con la matemática de color del hardware. DlgWindowFixedColorTbl, en src/field/hdma.asm, son 200 bytes de $E0 a $E7, un color fijo en los tres canales con intensidades de 0 a 7, y su primera serie son 72 valores que bajan desde 7, luego hasta 0 y luego vuelven a subir hasta 7.445 La ventana se abre cerca de la parte superior o inferior de la pantalla, «dialog window y position (1 or 18)» (posición y de la ventana de diálogo, 1 o 18) en el comentario de event.asm.45 Que la tabla se consume a un valor por línea de barrido se lee en los comentarios, no se rastreó, y no se vio cómo se ve el degradado, porque el desensamblado no tiene pixeles (sección 11).
La fuente
La fuente de diálogo es de 1 bit por pixel, 22 bytes por letra: 11 filas de 16 bits, una celda de 16 pixeles de ancho y 11 de alto. Su sombra no se dibuja: LoadLetterGfx la crea desplazando cada fila un pixel (lsr).446 Los anchos en inglés, de FontWidth, son proporcionales: las mayúsculas miden de media 8,04 pixeles (de 5 a 12), las minúsculas 7,73 (de 4 a 12), los dígitos 7,80 (de 5 a 9), y el espacio, 5.446
La fuente de diálogo de la ROM japonesa, de 0xC494C0 a 0xC4FFFF en su lista de extracción, ocupa 27.456 bytes: 1.248 letras de 22 bytes. Su tabla de anchos tiene 1.280 entradas, en series de 1.056 a 12 pixeles, 180 a 8 y 44 a 12, y las tablas de caracteres del desensamblado listan 1.010 kanji y 173 kana.447 El rango de la fuente grande en inglés, 5.120 bytes, no es un número entero de letras de 22 bytes (232,7), algo que no sé explicar a partir del desensamblado (sección 11).4
Una línea, un ajuste, una letra por fotograma
Una línea de diálogo va de la x 4 a una x máxima de $e0, 224: 220 pixeles, 18 letras japonesas de 12 pixeles.446 El texto en inglés se ajusta por palabras en el código. CalcTextWidth suma el ancho de la palabra siguiente, y se llama a NewLine cuando se pasaría del máximo, así que el guion en inglés no necesita cortes colocados a mano; el script comprueba las llamadas, y la lectura es de UpdateDlgTextOneLine.446
El texto se imprime a una letra por fotograma. El bucle de campo espera el borrado vertical y llama a UpdateDlgText una vez por pasada, y UpdateDlgTextOneLine dibuja una letra y vuelve: 60 letras por segundo a 60 hercios.448 Que haya una pasada por fotograma es mi lectura del bucle. Como una sola fuente genera las dos ROM, los dos idiomas comparten ese bucle, lo que, según mi lectura, significa las mismas letras por segundo en inglés y en japonés.48
El título de un mapa va centrado, ($e0 - width) / 2, y se muestra durante 100 fotogramas, 1,67 segundos.446
Frente a Emerald, Final Fantasy VI muestra la otra manera de construir la misma caja: Emerald escribe cada corte a mano y deja que el jugador elija el marco de los menús, nunca el de la caja de diálogo; Final Fantasy VI ajusta en el código, deja que el jugador repinte la ventana y la sombrea por hardware. La caja de campo de Emerald está abajo, la de Final Fantasy VI arriba o abajo, y las dos imprimen a un recuento fijo de fotogramas.
Chrono Trigger
Quería poner Chrono Trigger junto a Final Fantasy VI y no pude. No se clonó ningún desensamblado público, y el mapa de la ROM del juego en Data Crystal devolvió HTTP 403 al pedirlo, así que nada de lo que dice este artículo sobre cajas de texto viene de ahí (sección 11).49
4. Japonés en matrices de 8, 10 y 12 puntos
Kiradex es una app para coleccionistas de cartas, y la Dex ya muestra los nombres japoneses de las cartas con el inglés debajo, en las fuentes del sistema.50 El texto del mundo también va a necesitar japonés, y una fuente pixelada que no pueda dibujarlo no es candidata. La pregunta es cuán pequeño puede ser un kanji y quién ha dibujado ya siete mil.
El tamaño del trabajo
JIS X 0208, el juego de caracteres con el que se mide la cobertura de las fuentes pixeladas japonesas, tiene 6.879 caracteres según la tabla de correspondencias del Unicode Consortium: 524 que no son kanji, 169 de ellos las kana de las filas 4 y 5; 2.965 kanji de nivel 1 en las filas 16 a 47; y 3.390 kanji de nivel 2 en las filas 48 a 84.576 La tabla es la versión 2.0 y el consorcio la archiva entre sus correspondencias obsoletas; sigue siendo la lista contra la que es más fácil contar la cobertura de una fuente.5
Misaki: 8 por 8
Misaki (美咲フォント), de Num Kadoma, es la más pequeña. Su página la llama «8×8 ドットの日本語ビットマップフォント» (una fuente de mapa de bits japonesa de 8 por 8 puntos) compatible con «JIS 第一・第二水準» (los niveles 1 y 2 de JIS), y dice «一部の記号を除いた全ての文字は 7×7 ドットの範囲に収まっている» (todos los caracteres salvo algunos símbolos caben dentro de 7 por 7 puntos), de modo que, sigue la página, los caracteres puestos uno al lado del otro conservan su interlineado y su espaciado entre letras.51 Según la historia que cuenta la página, se hizo para un controlador de pantalla japonés de las computadoras de bolsillo PC-E500.51
Medida en sus archivos BDF de la versión 2021-05-05, Misaki Gothic tiene 7.171 caracteres: 168 de medio ancho, de 4 pixeles, y 7.003 de ancho completo, de 8 pixeles, en una celda de 8 por 8 con un ascendente de 6 y un descendente de 2. De sus 6.356 glifos de U+4E00 a U+9FFF (un rango de código, de ahí un recuento distinto de los 6.355 kanji de los dos niveles de JIS), ninguno llena la celda de 8 puntos en ninguna dirección, mientras que 53 glifos de ancho completo, símbolos, sí lo hacen. Dibuja los 6.879 caracteres de JIS X 0208.6 Misaki Mincho, que su página describe como Misaki Gothic con los caracteres que no son kanji redibujados en estilo Mincho, mide lo mismo en todos los recuentos. Misaki Gothic 2nd, que según su página usa los 3 por 7 pixeles completos para los caracteres de medio ancho y 7 por 7 para las kana de ancho completo, tiene 7.170 caracteres (167 de medio ancho), un ascendente de 7 y un descendente de 1, y mide lo mismo en el resto.651
k8x12: 8 por 12
k8x12, del mismo autor, conserva el ancho de 8 puntos y añade altura: «8×12 ドットの日本語ビットマップフォント» (una fuente de mapa de bits japonesa de 8 por 12 puntos), niveles 1 y 2 de JIS. Tiene dos variantes: k8x12L, cuyas kana se dibujan altas, y k8x12S, cuyos caracteres que no son kanji miden 8 puntos de alto, hecha, dice la página, pensando en los límites de las consolas antiguas: «8×8 ドット単位でグラフィックを扱うような、昔のゲーム機等の制限を意識しています» (consciente de los límites de las viejas máquinas de juego que manejan los gráficos en unidades de 8 por 8 puntos).52
Medida en el BDF, k8x12 es una celda de 8 por 12 con un ascendente de 10 y un descendente de 2: 7.170 caracteres, 168 de 4 pixeles y 7.002 de 8. Ningún kanji llena la celda; 53 glifos de ancho completo sí la llenan en k8x12 y k8x12L, y 45 en k8x12S. Las tres dibujan los 6.879 caracteres de JIS X 0208.6
PixelMplus: 10 y 12, como contornos
PixelMplus, de itouhiro (2013), es el otro enfoque: contornos TrueType que parecen una fuente de mapa de bits, sin mapas de bits incrustados («埋め込みビットマップは なし», sin mapas de bits incrustados), con todos los kanji de los niveles 1 y 2 de JIS («JIS第1・第2水準のすべての漢字を収録», incluye todos los kanji de los niveles 1 y 2 de JIS) más ISO-8859-1, en un peso regular y uno negrita y dos tamaños, PixelMplus12 y PixelMplus10, trazados a partir de las M+ BITMAP FONTS.18 Medida con Core Text, cada una tiene 7.253 glifos y dibuja 6.876 de los 6.879 de JIS X 0208. Los tres que no asigna son U+301C 〜, U+2016 ‖ y U+2212 −.7 Son caracteres cuya correspondencia Unicode difiere entre el JIS0208.TXT del consorcio y las tablas de otros fabricantes, así que, según mi lectura, las fuentes probablemente llevan esos glifos en los otros puntos de código; eso no se comprobó (sección 11).5
DotGothic16: una fuente de puntos sin cuadrícula
DotGothic16, de Fontworks, está en Google Fonts bajo la SIL Open Font License 1.1 sin Reserved Font Name, listada con los subconjuntos cyrillic, japanese, latin y latin-ext, y añadida el 2020-12-15.53 Tiene 9.362 glifos y dibuja los 6.879 caracteres de JIS X 0208.7 Pero está dibujada como puntos separados, no como pixeles. En su A, los bordes x del contorno vienen por pares, 91 y 102, 153 y 163, 214 y 225, 276 y 287, 338 y 349, 400 y 410 unidades de 1.000: puntos separados unas 62 unidades con huecos de 10 u 11 unidades entre ellos. Ninguna cuadrícula de pixeles enteros encaja con eso, y la sonda no encontró ninguna de 4 a 40 pixeles por em.197 Un paso de unas 62 unidades se acerca a 16 puntos por em, el número del nombre de la fuente, así que la sonda la dibuja a unos 16 puntos por em nominales y a múltiplos de eso; es mi elección de tamaño, no una cuadrícula que declare la fuente. Core Text en macOS 27.0 la dibujó con un 82,3 % de pixeles parciales a 16 pixeles y un 37,3 % a 64, y parcial en todos los tamaños medidos (sección 6).7
Lo que miden las fuentes gratuitas
La cuadrícula de diseño de la tabla es el menor número de pixeles por em en el que el 95 % de los puntos de contorno de una muestra de glifos quedan a menos de 0,04 pixeles, con un desplazamiento constante permitido en cada eje; el script que la encuentra, measure_coretext.swift, se compiló con swiftc -O y se ejecutó en macOS 27.0 (compilación 26A428), así que estos son números del Core Text de un Mac, no de un iPhone.7
| Fuente | Glifos | Tablas de mapa de bits | Cuadrícula de diseño (pixeles por em) | Avance latino / kana (pixeles) | JIS X 0208 dibujados |
|---|---|---|---|---|---|
| Misaki Gothic | 7.174 | EBDT, EBLC | 8, en la línea base | 4 / 8 | 6.879 |
| k8x12 | 7.173 | EBDT, EBLC | 12, en la línea base | 4 / 8,01 | 6.879 |
| PixelMplus10 Regular y Bold | 7.253 cada una | ninguna | 10, en la línea base | 5 / 10 | 6.876 |
| PixelMplus12 | 7.253 | ninguna | 12, 0,39 pixeles por debajo de la línea base | 6 / 12 | 6.876 |
| DotGothic16 | 9.362 | ninguna | ninguna (dibujada a 16 puntos nominales) | 8 / 16 puntos nominales | 6.879 |
Con esa medida, PixelMplus10 Regular tiene 0 de 1.032 coordenadas de contorno muestreadas fuera de su cuadrícula de 10 pixeles, y la Bold 0 de 1.000; Misaki Gothic 0 de 848; k8x12 0 de 988; PixelMplus12 0 de 1.192 una vez que se permite su desplazamiento de 0,39 pixeles, y DotGothic16 tiene fuera las 1.544.7 El desplazamiento de PixelMplus12 se ve en sus coordenadas en bruto: su H va de y −33 a 717 unidades de 1.000, en una cuadrícula de 83,3 unidades por pixel, así que su línea base cae 0,396 pixeles dentro de una fila de la cuadrícula; la estimación de la sonda, 0,39, sale de repartir las fracciones de las coordenadas en intervalos de una cincuentava parte de pixel, y es la cifra con la que se desplazaron los renderizados que vienen más abajo.19733
En todas las fuentes con japonés medidas, un carácter japonés es el doble de uno latino: 8 frente a 4 en Misaki y k8x12, 10 frente a 5 y 12 frente a 6 en PixelMplus.7 El canon está en el mismo rango: el japonés de Emerald mide 8 pixeles de ancho en una línea de 16, la hoja de FireRed casi siempre 10, el de Final Fantasy VI, 12.14
Las licencias
Todo esto es gratuito en los términos más claros. La licencia de Misaki y k8x12, en la página de fuentes del autor, son tres frases: «These fonts are free software. Unlimited permission is granted to use, copy, and distribute them, with or without modification, either commercially or noncommercially. THESE FONTS ARE PROVIDED “AS IS” WITHOUT WARRANTY.» (estas fuentes son software libre; se concede permiso ilimitado para usarlas, copiarlas y distribuirlas, con o sin modificaciones, con fines comerciales o no comerciales; se proporcionan tal cual, sin garantía). El léame de cada archivo lleva los mismos términos con palabras algo distintas, y la página de Misaki nombra la licencia que usa como la licencia de M+ FONTS.1751 PixelMplus está bajo la M+ FONT LICENSE, cuyo texto en inglés, LICENSE_E, son las mismas tres frases.18 DotGothic16 está bajo la SIL Open Font License 1.1, cuyas condiciones están en su propio OFL.txt.53 Según mi lectura, la licencia de tres frases no pide nada a cambio; dar crédito a los autores sigue siendo lo correcto, y el encargo lo hace (sección 12). Son lecturas, no asesoramiento legal.
Lo que cuesta la legibilidad
Una kana en Misaki mide 8 pixeles de fuente de ancho; en PixelMplus12, doce. A la densidad propia del mundo en el iPhone 18 Pro Max, donde un texel son 8 pixeles de dispositivo, una línea de la caja dibujada en Misaki admite 36 caracteres latinos o 18 japoneses.11 La línea japonesa lleva más por carácter, así que la caja no necesita admitir tantos caracteres para decir lo mismo; es mi lectura, no una medición.
5. Fuentes pixeladas latinas, y las que no pude medir
Junto a las japonesas se midieron dos fuentes pixeladas latinas de Google Fonts.30
Press Start 2P, de CodeMan38, está bajo la SIL Open Font License 1.1 «with Reserved Font Name “Press Start 2P”» (con el nombre de fuente reservado “Press Start 2P”).54 Tiene 658 glifos sobre una cuadrícula de 8 pixeles en la línea base, cada carácter latino de 8 pixeles de ancho, y los 95 caracteres ASCII imprimibles. No tiene kana ni kanji: de JIS X 0208 dibuja 150 caracteres que no son kanji (su griego, su cirílico y sus símbolos) y ninguno de los 6.355 kanji.7
Silkscreen, de Jason Kottke, está bajo la SIL Open Font License 1.1 sin Reserved Font Name.55 Tiene 228 glifos sobre una cuadrícula de 8 pixeles, con 10 de 588 coordenadas de contorno muestreadas fuera de ella (su A y su o tienen valores y de 495 y 130 unidades en una cuadrícula de 125), y su A mide 6 pixeles de ancho. De JIS X 0208 dibuja 21 caracteres que no son kanji.719
Otras tres fuentes que se recomiendan a menudo para juegos pixelados no se midieron, y lo digo en lugar de describirlas de memoria.
Pixel Operator, de Jayvee Enaguas: las notas del autor en DaFont dicen «Changed licence to Creative Commons Zero (CC0) 1.0» (licencia cambiada a Creative Commons Zero, CC0, 1.0) y que la tipografía está «licensed under a Creative Commons Zero (CC0) 1.0» (bajo licencia Creative Commons Zero, CC0, 1.0). DaFont la lista como «Bitmap (16 px)», en 15 archivos de fuente, con 241 glifos. El repositorio propio del autor, que las notas sitúan en NotABug, devolvió HTTP 404, y la fuente no se descargó ni se midió. Todo lo que digo aquí sale de esa única página.56
m5x7, de Daniel Linssen: su página de itch.io dice «use font size 16, 32, 48, etc» (usa tamaños de fuente de 16, 32, 48, etc.) y «free to use but attribution appreciated» (de uso libre, aunque se agradece la atribución), indica «Asset license Creative Commons Zero v1.0 Universal» (licencia del recurso: Creative Commons Zero v1.0 Universal) y da un ancho medio de 5, un ascendente de 7, un descendente de 2 y una altura de x de 5. Describe sus caracteres como «uppercase and lowercase letters, including many accented letters, numbers and most common symbols» (mayúsculas y minúsculas, incluidas muchas letras acentuadas, números y los símbolos más comunes).57
m3x6, del mismo autor: «use font size 16, 32, 48, etc» y «free to use with attribution» (de uso libre con atribución); su página no muestra ningún campo de licencia del recurso.58 No se descargó ninguno de los dos archivos, porque ambos están tras una descarga de pago voluntario, así que no se midió ninguno.5758
Esa es la tercera imprecisión del artículo del mundo. Su plan de texto nombra m5x7 como la fuente.23 Según la descripción de su propia página, m5x7 es una fuente latina, y nada en la página dice que tenga kana o kanji; una app que va a mostrar japonés no puede componer en ella el texto de su mundo.57 El encargo cambia la fuente por PixelMplus10, una de las dos fuentes medidas con japonés, cuadrícula limpia y avances de pixeles enteros (la otra es Misaki), y la más grande de las dos (secciones 6 y 12). La propia m5x7 sigue sin medirse.
6. Lo que Core Text hace con una fuente pixelada
El artículo del mundo afirmaba que «Bitmap fonts render at integer multiples only» (las fuentes de mapa de bits solo se renderizan en múltiplos enteros).23 Es la regla que repite toda guía de pixel art, y quería verla, con números, en el motor de texto de la propia Apple.
La medición
Core Text es la capa de Apple para «Create text layouts, optimize font handling, and access font metrics and glyph data» (crear composiciones de texto, optimizar el manejo de fuentes y acceder a métricas de fuente y datos de glifos), disponible desde iOS 3.2 y macOS 10.8.59 measure_coretext.swift carga cada archivo TrueType candidato, dibuja una línea de muestra («Nice card! Which set? 0123» para las fuentes latinas, «カードを見せて! Nice card!» para las japonesas) en un mapa de bits gris de 8 bits a tamaños que son múltiplos enteros y fraccionarios de la cuadrícula de cada fuente, y cuenta los pixeles entintados que son parciales: entre 8 y 247 de 255, a más de un 3 % de lleno o de vacío. Dibuja cada tamaño de tres maneras: con el antialiasing predeterminado de Core Text, con el antialiasing desactivado, y con el posicionamiento de subpixel activado y la cuantización desactivada, para que los glifos caigan exactamente donde los ponen sus avances.7
Hay dos límites que importan antes de cualquier número. La ejecución es en macOS 27.0, compilación 26A428, en mi Mac, no en iOS, y dibuja con Core Text en un contexto de mapa de bits, no con el Text de SwiftUI; lo que dibuja un iPhone es una predicción hasta que las comprobaciones de captura del encargo se ejecuten en uno (sección 11).7 Y el script dibuja con el suavizado de fuentes desactivado (setAllowsFontSmoothing(false)). Cuando dibujé la figura de abajo con el valor predeterminado del contexto de mapa de bits, 178 de los 272 pixeles entintados de «Nice card!» en PixelMplus10 a 10 pixeles salieron parciales, frente a 0 de 94 con el suavizado desactivado.9 El suavizado de fuentes es un ajuste de macOS; si algo parecido se aplica en iOS, lo tienen que decidir las comprobaciones de captura.
Los múltiplos enteros salen limpios
En los múltiplos enteros de la cuadrícula, con el antialiasing activado (el valor predeterminado del contexto) y el suavizado de fuentes desactivado, Misaki a 8, 16, 24 y 32 pixeles, PixelMplus10 Regular y Bold a 10, 20, 30 y 40, y Press Start 2P a 8, 16, 24 y 32 se renderizan con un 0,0 % de pixeles parciales.7 Cada pixel es tinta o papel. Eso depende del ajuste de suavizado: con el suavizado predeterminado del contexto de mapa de bits, PixelMplus10 a sus propios 10 pixeles dibujó parciales 178 de los 272 pixeles entintados de «Nice card!», así que en el Mac un múltiplo entero por sí solo no hizo nítido el texto.9
PixelMplus10 Regular dibujada por Core Text en macOS 27.0 a un pixel de dispositivo por pixel de fuente, mostrada con el antialiasing desactivado. Con el antialiasing activado y el suavizado de fuentes desactivado, 0 de los 94 pixeles entintados de «Nice card!» son parciales; con el suavizado predeterminado del contexto de mapa de bits, lo son 178 de 272. La fuente está bajo la M+ FONT LICENSE, que permite copiarla y distribuirla; dibujado por figures/dump_glyphs.swift y figures/make_figures.py.
Entre ellos, se emborronan
Entre los múltiplos enteros, las mismas fuentes se emborronan, con el suavizado desactivado como en toda la sonda. Misaki tiene un 57,7 % de pixeles parciales a 12 pixeles (1,5 veces su cuadrícula), un 39,9 % a 20 (2,5 veces) y un 82,2 % a 10 (1,25 veces). PixelMplus10 tiene un 60,1 % a 15 pixeles. Press Start 2P, un 44,0 % a 12 pixeles, un 29,1 % a 20 y un 21,7 % a 28.7 En los 40 renderizados a 1,25, 1,5, 1,75, 2,5 y 3,5 veces la cuadrícula de las ocho fuentes cuya cuadrícula se apoya en la línea base (las dos Misaki, k8x12 y k8x12S, PixelMplus10 Regular y Bold, Press Start 2P y Silkscreen), la proporción de parciales va del 19,4 %, PixelMplus10 Bold a 35 pixeles, al 82,2 %, Misaki a 10.7 El emborronado no baja de forma constante con el tamaño: en cada una de las ocho, 1,75 veces la cuadrícula emborrona más que 1,5 veces (Misaki, 65,7 % a 14 pixeles frente a 57,7 % a 12). A la misma fracción sí baja: a 1,5, 2,5 y 3,5 veces la cuadrícula, cada una de las ocho es más baja en cada paso (Misaki, 57,7 %, 39,9 % y 30,4 %). En ningún renderizado medido entre múltiplos enteros llega a cero; según mi lectura, la bajada a fracción fija se debe a que un error de medio pixel en el borde de un glifo es una parte menor de un glifo más grande.7
Desactivar el antialiasing (setShouldAntialias(false)) deja cada pixel lleno o vacío en cualquier tamaño, pero las formas se remuestrean de manera desigual. Los 191 pixeles entintados de Misaki a 8 pixeles pasan a ser 377 a 10; una escala uniforme de 1,25 en cada dirección daría unos 298.733 Algunas filas y columnas se duplican y otras no, así que trazos que tenían un pixel de ancho salen con uno o con dos.
Pixeles parciales por tamaño, Core Text en macOS 27.0 con el suavizado de fuentes desactivado, no iOS; dibujado por figures/make_figures.py a partir de measure_coretext.out.
Un tamaño limpio no basta: el archivo tiene que estar limpio
Dos fallos más discretos importan más que los múltiplos a la hora de elegir una fuente.
Una cuadrícula desplazada de la línea base se emborrona en todos los tamaños. Los contornos de PixelMplus12 quedan 0,39 pixeles por debajo de la cuadrícula de la línea base, y se renderiza con un 66,6 % de parciales a sus propios 12 pixeles, un 40,0 % a 24 y un 29,8 % a 36. Mover la línea base según el desplazamiento, en la transformación del contexto con el posicionamiento de subpixel activado, lleva 12 pixeles al 0,0 %, pero deja un 14,3 % a 24 y un 19,0 % a 36, aunque el desplazamiento se escaló con el tamaño (0,78 pixeles a 24, 1,17 a 36).7 Por qué el desplazamiento escalado no limpia los tamaños mayores es algo que la salida no dice, y no lo he rastreado.
Un avance fuera de la cuadrícula se emborrona en cuanto los glifos se colocan con exactitud. El avance de kana de k8x12 es de 8,01 pixeles, no de 8. Con los ajustes predeterminados del contexto de mapa de bits, que colocan cada glifo en un pixel entero, se renderiza con un 0,0 % de parciales a 12, 24 y 36 pixeles. Con el posicionamiento de subpixel activado y la cuantización desactivada, los mismos tamaños dan un 62,3 %, un 42,8 % y un 32,6 % de parciales.7 Según mi lectura, cada kana cae entonces una centésima de pixel más lejos de la cuadrícula que la anterior.
Los puntos de contorno sueltos dejan un poco. Las diez coordenadas fuera de la cuadrícula de Silkscreen aparecen como un 4,5 % de parciales a 8 pixeles y un 1,2 % a 32.7
Una fuente de puntos nunca se alinea. DotGothic16 no tiene una cuadrícula de la que tomar múltiplos, así que la sonda la dibuja a 16 puntos por em nominales y a entre 1,25 y 4 veces eso (sección 4). Con el antialiasing activado y el suavizado desactivado tiene un 82,3 % de parciales a 16 pixeles, un 52,5 % a 32, un 48,8 % a 48 y un 37,3 % a 64, y es parcial en cada uno de los nueve tamaños de 16 a 64 pixeles, incluidos los múltiplos enteros de 16; sus puntos no están en ninguna cuadrícula de pixeles (sección 4).719
Misaki y k8x12 llevan tablas de mapa de bits incrustadas (EBDT y EBLC, leídas con CTFontCopyAvailableTables). Los resultados medidos arriba son lo que dibujó Core Text; no se determinó si dibujó esos mapas de bits o los contornos (sección 11).7
Misaki, PixelMplus10 y Press Start 2P no tienen ninguno de los dos fallos discretos. La regla que se desprende tiene que ver tanto con el archivo de la fuente como con el tamaño: múltiplos enteros, una cuadrícula en la línea base y avances de pixeles enteros.
Dynamic Type y la cuadrícula
Las Human Interface Guidelines de Apple dan a iOS un tamaño de texto predeterminado de 17 puntos y un mínimo de 11, y una tabla para cada tamaño de Dynamic Type. Body recorre, de xSmall a AX5, 14, 15, 16, 17, 19, 21, 23, 28, 33, 40, 47 y 53 puntos; Caption 1, de 11 a 43.6010
En una pantalla de 3×, un pixel de fuente es un número entero de pixeles de dispositivo solo cuando el tamaño en puntos por 3, dividido entre el em en pixeles de fuente, da un número entero. De los doce tamaños de Body, un em de 12 pixeles cae entero en 3 de ellos (16, 28 y 40 puntos), uno de 8 pixeles en 2 (16 y 40) y uno de 10 pixeles en 1 (40). De los doce tamaños de Caption 1, un em de 12 pixeles cae entero en 3 (12, 16 y 32).760
Qué tamaños de Body caen en pixeles de dispositivo enteros a 3×, y el redondeo del encargo; dibujado por figures/make_figures.py a partir de measure_coretext.out y measure_kiradex_text.out.
Así que una fuente pixelada no puede limitarse a seguir Dynamic Type. Si escala de forma continua con los tamaños del sistema, queda fuera de su cuadrícula en todos los tamaños salvo los pocos enteros: 11 de 12 tamaños de Body para un em de 10 pixeles, 9 de 12 para uno de 12.733 Fuera de la cuadrícula, Core Text en el Mac, con el antialiasing activado, emborronó todas las fuentes medidas; si SwiftUI en un iPhone hace lo mismo depende de su renderizado y su colocación, y eso lo deciden las capturas del encargo. Tiene que tomar el tamaño que pide el sistema y redondearlo a la cuadrícula, algo que la sección 10 convierte en una receta de API y la sección 12 en la regla del encargo.
7. El salto de línea japonés
Una línea predefinida corta nunca se ajusta. Una caja de texto sí, y el japonés tiene reglas sobre dónde.
Las reglas
Los Requirements for Japanese Text Layout del W3C (una Working Group Note del 11 de agosto de 2020) fijan en el 3.1.7 la regla de inicio de línea: «In principle, no line should begin with closing brackets (cl-02), hyphens (cl-03), dividing punctuation marks (cl-04), middle dots (cl-05), full stops (cl-06), commas (cl-07), iteration marks (cl-09), a prolonged sound mark (cl-10), small kana (cl-11) or warichu closing brackets (cl-29)» (en principio, ninguna línea debe empezar por corchetes de cierre, guiones, signos de puntuación divisores, puntos medios, puntos, comas, marcas de iteración, la marca de sonido prolongado, kana pequeñas o corchetes de cierre de warichu). También recoge la práctica más laxa: «Not a small number of books adopt a less strict set of rules which allow IDEOGRAPHIC ITERATION MARK “々” (one of the iteration marks (cl-09)), prolonged sound mark (cl-10) and small kana (cl-11) to start a line.» (no pocos libros adoptan un conjunto de reglas menos estricto que permite empezar una línea con la marca de iteración ideográfica 々, la marca de sonido prolongado y las kana pequeñas).21
El algoritmo de salto de línea de Unicode, UAX #14 (revisión 57, para Unicode 18.0.0, con fecha 2026-09-01), pone las hiragana y katakana pequeñas y la marca de sonido prolongado en su clase CJ, y dice: «Treating characters of class CJ as class NS will give CSS strict line breaking; treating them as class ID will give CSS normal breaking.» (tratar los caracteres de clase CJ como clase NS da el salto de línea estricto de CSS; tratarlos como clase ID da el salto normal de CSS).61
Lo que hizo Core Text
measure_coretext.swift, ejecutado en macOS 27.0 (no en iOS), compone un párrafo japonés de 131 caracteres con CTFramesetter a anchos de 8, 10, 12, 14, 16, 18 y 20 em, y compara el primer carácter de cada línea a partir de la segunda con su propia lista de caracteres prohibidos al inicio de línea: algunos de los corchetes de cierre, la coma y el punto japoneses, el punto medio, los dos puntos y el punto y coma, los signos de interrogación y exclamación, la marca de sonido prolongado, las kana pequeñas y 々.7 Esa lista no es un subconjunto de las clases que nombra la regla de JLREQ, solo se solapa con ellas. Siete de sus 40 caracteres, ,.:;?! y ), son las formas de ancho completo que usa el texto japonés donde JLREQ lista las ASCII; los otros 33 son de JLREQ. De los corchetes de cierre contiene 」』】〉》〕 y el ) de ancho completo, y deja fuera ’ ” ] } » 〟 ⦆ 〙 〗 y el ) ASCII; de las 40 kana pequeñas contiene 22, y deja fuera ゕ, ゖ y de ㇰ a ㇿ; y deja fuera los guiones (cl-03), entre ellos ‐, 〜, ゠ y la semirraya, ‼ ⁇ ⁈ ⁉ de cl-04, y todas las marcas de iteración (cl-09) salvo 々, entre ellas ヽ, ヾ, ゝ, ゞ y 〻.721 Los resultados de abajo son para la lista de la sonda, y el texto del párrafo de prueba decide qué caracteres llegan alguna vez a un inicio de línea.
Sin etiqueta, ninguna línea empezó por un carácter de la lista de la sonda en ningún ancho, ni en Hiragino Sans (la fuente japonesa del sistema, usada como control) ni en ninguna de las ocho fuentes pixeladas: Misaki Gothic, Misaki Gothic 2nd, k8x12, k8x12S, PixelMplus10 Regular y Bold, PixelMplus12, y DotGothic16 a sus 16 puntos nominales.7
Con kCTLanguageAttributeName puesto en ja, la regla se relajó. En Hiragino Sans, las dos Misaki, las dos PixelMplus10, PixelMplus12 y DotGothic16, una línea empezó por una kana pequeña (っ, ョ o ァ) en 6 de los 7 anchos, todos salvo 18 em.7 En k8x12 y k8x12S, una línea empezó por una kana pequeña (っ, ョ o ょ) en 4 de los 7 anchos, y por la marca de sonido prolongado ー en dos, 10 em (junto a ョ) y 18 em, un quinto ancho.7
Según mi lectura de esos recuentos frente a las dos citas, la etiqueta ja da la regla menos estricta que describe JLREQ, la que UAX #14 llama salto normal de CSS, y la ejecución sin etiqueta se comporta de forma estricta.2161 Es lo contrario de lo que esperaba, ya que la etiqueta nombra el idioma, y es la razón por la que el encargo no etiqueta el texto de la caja sin una captura.
Dos notas sobre la propia medición, ambas de leer el script frente a su salida. Los anchos están en em, el tamaño completo de la fuente, así que para k8x12, cuyas kana miden 8 pixeles en un em de 12, cada ancho admite una vez y media las kana que dice su número; el párrafo de k8x12 ocupó 12 líneas a 8 em, donde los demás ocuparon 17.7 Y DotGothic16, que no tiene cuadrícula, se compuso al doble de sus 16 puntos nominales, 32 pixeles por em; a ese tamaño ocupó el mismo número de líneas que Hiragino Sans en cada ancho, de 17 a 8 em a 7 a 20, y las mismas kana pequeñas abrieron sus líneas con la etiqueta.7
8. Los juegos pixelados posteriores: cajas, globos, japonés y chino
Stardew Valley: dos formas de hablar
Stardew Valley tiene las dos formas que Kiradex ya tiene. Su caja de diálogo pasa de página con un comando, $b, que la página de modding sobre el diálogo de la Stardew Valley Wiki (editada por última vez el 20 de mayo de 2026) describe como uno que «Indicates pauses in dialogue, where the player will need to click for the next part to load in a new dialogue box» (indica pausas en el diálogo, donde el jugador tendrá que hacer clic para que la siguiente parte se cargue en una nueva caja de diálogo), y comandos de retrato que «set the portrait shown in the dialogue box for the current line of dialogue» (fijan el retrato que se muestra en la caja de diálogo para la línea actual).62 Y tiene globos de diálogo, Strings\SpeechBubbles, para el «dialogue spoken by NPCs through speech bubbles when the player enters a given location» (diálogo que dicen los NPC mediante globos cuando el jugador entra en un lugar determinado).62 La caja es para las conversaciones, encabezada por una cara; los globos son lo que dice un pueblo cuando entras.
Sus idiomas no latinos usan fuentes de mapa de bits. La página de la wiki sobre idiomas personalizados (editada por última vez el 3 de enero de 2026) hace que un idioma nuevo ponga UseLatinFont en false y aporte un archivo .fnt, tomando como modelo «the Chinese, Japanese, Korean, and Russian fonts in the Fonts folder» (las fuentes china, japonesa, coreana y rusa de la carpeta Fonts). Su FontPixelZoom es «A factor by which to multiply the font size. The recommended baseline is 1.5» (un factor por el que multiplicar el tamaño de la fuente; la base recomendada es 1.5), y FontApplyYOffset fija «Whether to shift the font up by four pixels» (si desplazar la fuente cuatro pixeles hacia arriba), para alinear «languages with larger characters like Chinese and Japanese» (idiomas con caracteres más grandes, como el chino y el japonés).63 Un zoom de 1,5 no es un múltiplo entero, pero la página lo da como punto de partida para un idioma que añade un modder, no como lo que usan las fuentes china, japonesa y coreana que trae el juego, y que un zoom remuestree en pantalla depende también de la escala del juego respecto de los pixeles de dispositivo; así que no dice nada seguro sobre cómo dibuja Stardew su propio japonés.63
Final Fantasy Pixel Remaster: el trabajo era la fuente
La versión para consolas del Pixel Remaster añadió una opción de fuente pixelada, y el productor, Naofumi Takuma, le contó a Siliconera (Jenni Lada, 2 de junio de 2023) cómo se hizo. Para los idiomas occidentales, el equipo encontró datos de fuentes producidos internamente y los usó. Para el japonés: «We didn’t have any alternative data saved on file in-house for the Japanese language font, so we decided to create a new one.» (no teníamos guardados internamente datos alternativos para la fuente del idioma japonés, así que decidimos crear una nueva). Y: «While the Western language font required us to create only a few hundred characters, with the Japanese font, we had to create around 7,500 characters.» (mientras que la fuente de los idiomas occidentales nos exigió crear solo unos cientos de caracteres, con la japonesa tuvimos que crear unos 7.500).8
Esa es la cuarta imprecisión del artículo del mundo. Daba la misma cifra, «about 7,500 Japanese characters» (unos 7.500 caracteres japoneses), y citaba el reportaje de GoNintendo sobre el trabajo; la fuente primaria es la propia entrevista del productor con Siliconera, que dice «around 7,500 characters».238 El mismo número, con una fuente mejor.
Siete mil quinientos es más o menos el tamaño de los 6.879 caracteres de JIS X 0208, el objetivo de cobertura habitual; la comparación es mía.533 Un juego cuyas líneas quedan todas fijadas antes de salir puede dibujar menos, como hizo la ROM japonesa de Final Fantasy VI con 1.248 letras de diálogo (sección 3), y entonces cada cadena hay que comprobarla contra la fuente; una fuente que cubre todo el conjunto no necesita esa comprobación para ninguna cadena que salga de él.4 La lección para una app pequeña es la que enseñan desde el otro lado las fuentes gratuitas de la sección 4: para un texto que va a seguir creciendo, la tipografía pixelada japonesa es un problema resuelto solo si alguien ya ha dibujado los siete mil caracteres y la licencia te deja distribuirlos.
Lo que traen los juegos pixelados modernos
En Steam, el 5 de octubre de 2026, Stardew Valley lista 12 idiomas, entre ellos japonés, chino simplificado y coreano; Celeste, 9, entre ellos japonés y chino simplificado; Sea of Stars, 11, entre ellos japonés, coreano y chino simplificado y tradicional; y Eastward, 7, entre ellos los dos chinos y el japonés.64 Los cuatro traen japonés.
Cómo dibujan Celeste, Sea of Stars y Eastward su texto en japonés y en chino no lo encontré en ninguna fuente de los desarrolladores, así que este artículo no dice nada al respecto más allá de las listas de idiomas (sección 11).
Dos formas de hablar en Kiradex
Kiradex ya tiene las dos formas de Stardew: la caja del WorldHUD en la parte inferior de la pantalla y los globos de la plaza sobre las cabezas.2625 Lo que le falta es la tipografía del canon dentro de ellos, y una manera de que VoiceOver oiga cualquiera de las dos. El propio comentario del globo en el código dice a qué aspiraba: «A line said, as the old games drew it: a cream box with a dark border.» (una línea dicha, tal como la dibujaban los juegos antiguos: una caja crema con un borde oscuro).25
9. El oficio, como reglas con números
Estas son las reglas que respaldan las mediciones, cada una con su origen. Donde una regla convierte un hecho medido en una recomendación, la recomendación es mía y la regla lo indica con su verbo.
| Elemento | Regla | Fuente |
|---|---|---|
| Caja | La caja es el tercio inferior de la pantalla y dos líneas. Ponla abajo; deja que un juego que necesite la parte inferior la mueva arriba. | El marco de Emerald, de 30 por 6 tiles, todo el ancho y el 30 % de la altura, alrededor de una ventana de 27 por 4 tiles con dos líneas de 16 pixeles; el de Crystal, de 20 por 6, el 33 %, dos líneas de 18, y el de Red, el mismo de 20 por 6; la ventana de Final Fantasy VI en la fila 1 o la 18 |
| Glifos latinos | De 4 a 12 pixeles de ancho en una celda de 8 a 16 pixeles de alto. | La celda de 6 por 16 de Emerald, a 5,25 pixeles por carácter en texto real; los 4 a 12 de Final Fantasy VI en una celda de 16 por 11; los 8 por 8 fijos de Crystal |
| Glifos japoneses | De 8 a 12 pixeles, aproximadamente el doble de una letra latina en la misma fuente. | Misaki, 8 por 8 con tinta de 7 por 7; Emerald, 8 de ancho en una línea de 16; la hoja de FireRed y PixelMplus10, 10; Final Fantasy VI y PixelMplus12, 12; 8 frente a 4, 10 frente a 5 y 12 frente a 6 en todas las fuentes con japonés medidas |
| Longitud de línea | De 18 a 41 caracteres por línea; escribe a la medida del ancho en lugar de llenarlo. | Crystal, 18; la ventana de 216 pixeles de Emerald admite 41 a 5,25 pixeles, y sus guionistas se quedaron en 38 en el 95 % de las líneas; la línea de 220 pixeles de Final Fantasy VI admite 18 caracteres japoneses de 12 pixeles |
| Cortes | O quien escribe corta cada línea, o el código ajusta por palabras; nunca las dos cosas. | Las 24.100 líneas cortadas a mano de Emerald, ninguna de más de 208 pixeles; CalcTextWidth y NewLine de Final Fantasy VI |
| Velocidad | Cuenta los caracteres en tiempo: 60 por segundo como techo (el ajuste rápido de Emerald y de Crystal, y la letra por fotograma de Final Fantasy VI), de 15 a 20 para un ajuste medio, de 7,5 a 12 para el lento. | Emerald, 7,5, 15 y 60, y 60 con el botón mantenido; Crystal y Red, 12, 20 y 60; Final Fantasy VI, 60 |
| Marca de avance | Mueve la marca con un reloj lento: un paso cada 150 milisegundos, un ciclo de unos 0,6 segundos. | Los 0, 1, 2 y 1 pixeles de Emerald, un paso cada 9 fotogramas, 36 fotogramas por ciclo; el ▼ de Crystal que parpadea contra el tile del borde |
| Marcos | Los marcos son tiles, no dibujos: una esquina, un borde y un centro, repetidos. Deja que el jugador elija entre unos pocos. | Los 20 marcos de menú seleccionables de 24 por 24 de Emerald y su tira de diálogo de 14 tiles con el borde inferior reflejado; los 8 marcos de Crystal de 6 tiles de un bit; los 8 estilos de 28 tiles de Final Fantasy VI con 7 colores editables |
| Tipografía nítida | Una fuente pixelada es nítida solo con pixeles de dispositivo enteros por pixel de fuente y, en el Mac, solo con el suavizado de fuentes desactivado; captura un iPhone para ver cuál de las dos cosas se cumple ahí. | Core Text en macOS 27.0 con el suavizado de fuentes desactivado: 0,0 % de pixeles parciales en los múltiplos enteros de una cuadrícula en la línea base con avances de pixeles enteros (Misaki, PixelMplus10, Press Start 2P), del 19,4 % al 82,2 % entre ellos; con el suavizado predeterminado del contexto, PixelMplus10 a sus propios 10 pixeles, 178 de 272 pixeles entintados parciales |
| Archivos limpios | Comprueba la cuadrícula de una fuente, su desplazamiento respecto de la línea base y sus avances antes de elegirla. | Core Text en macOS 27.0: la cuadrícula de PixelMplus12, 0,39 pixeles fuera de la línea base, emborronada en todos los tamaños; el avance de kana de 8,01 pixeles de k8x12, emborronado en cuanto los glifos se colocan con exactitud; los 10 puntos sueltos de Silkscreen, del 1,2 % al 4,5 % |
| Dynamic Type | Respeta el tamaño del usuario redondeándolo a la cuadrícula, nunca escalando de forma continua, y nunca por debajo de 11 puntos. | Un em de 10 pixeles es entero en 1 de los 12 tamaños de Body a 3×, uno de 12 pixeles en 3 y uno de 8 pixeles en 2; el mínimo de 11 puntos de las HIG |
| Cortes en japonés | Mantén la regla estricta de inicio de línea para el texto de la caja; mantén las líneas predefinidas lo bastante cortas para que nunca se ajusten. | JLREQ 3.1.7; Core Text en macOS 27.0, sin etiqueta, mantuvo la regla estricta para la lista parcial de inicio de línea de la sonda en todos los anchos medidos, y con la etiqueta ja dejó que las kana pequeñas empezaran líneas en 6 de 7 anchos en la mayoría de las fuentes (4 de 7 en k8x12 y k8x12S) |
| Hablantes | Nombra al hablante dentro de la línea, no en un campo aparte ni sobre la cabeza. | La caja de Emerald no tiene campo de nombre y el 6,5 % de sus párrafos empiezan con un nombre y dos puntos |
| Cobertura | Cubre el conjunto estándar, unos siete mil caracteres, antes de que pueda salir texto japonés que los guionistas no hayan fijado; un guion fijo puede salir con menos, comprobado cadena por cadena. | Los 6.879 de JIS X 0208; los «around 7,500» del Pixel Remaster; las 1.248 letras de diálogo de la ROM japonesa de Final Fantasy VI; Misaki, k8x12 y DotGothic16 dibujan todo JIS X 0208, PixelMplus todo salvo tres puntos de código |
| Licencias | Distribuye una fuente solo con el texto de su licencia en la mano y sus términos leídos. | La licencia de tres frases de Misaki, k8x12 y PixelMplus; la SIL Open Font License de DotGothic16, Press Start 2P y Silkscreen, con el Reserved Font Name de Press Start 2P |
| Dos formas | Conserva las dos formas, una caja y un globo. Qué dice cada una es decisión de cada juego; la de Kiradex, mía, es la caja para lo que dice un lugar y el globo para lo que dice una persona. | Stardew Valley tiene las dos: su caja para las conversaciones, sus globos para lo que dicen los NPC cuando el jugador entra en un lugar |
Cada número de la tabla sale de las secciones 1 a 8 y lleva allí su nota.1467921862
10. A la manera de Apple: tipografía, tamaños, saltos de línea y VoiceOver
Kiradex World es una escena de RealityKit que se usa como renderizador 2D, con una cámara ortográfica a un número entero de pixeles de dispositivo por texel y SwiftUI encima para todo lo que una persona lee.23 El artículo del mundo decidió que el texto del diálogo «lives in SwiftUI at UI scale rather than in the world» (vive en SwiftUI a escala de interfaz y no en el mundo), y esta sección mantiene esa decisión y completa las API: qué pide Apple a la tipografía personalizada, cómo entra una fuente pixelada incluida en la app, cómo se puede respetar Dynamic Type redondeando, cómo se corta el japonés y cómo puede VoiceOver leer un escenario que es una única vista de RealityKit. Cada disponibilidad que aparece abajo sale de las páginas de documentación de Apple, guardadas el 5 de octubre de 2026; nada del código se ha compilado, y ningún coste de esta sección está medido en un teléfono.65
Lo que Apple pide al texto
La página Typography de las Human Interface Guidelines da a iOS y iPadOS un tamaño de texto predeterminado de 17 puntos y un mínimo de 11, y pide a las apps «Follow the recommended default and minimum text sizes for each platform» (seguir los tamaños de texto predeterminados y mínimos recomendados para cada plataforma), tanto para fuentes personalizadas como del sistema.1060 Las fuentes del sistema admiten por sí solas Dynamic Type y funciones de accesibilidad como Texto en negrita; para el resto, la página dice: «If you use a custom font, make sure it implements the same behaviors.» (si usas una fuente personalizada, asegúrate de que implementa los mismos comportamientos).10
La página Accessibility fija el tamaño del trabajo: «Ideally, give people the option to enlarge text by at least 200 percent (or 140 percent in watchOS apps).» (idealmente, da a las personas la opción de ampliar el texto al menos un 200 por ciento, o un 140 por ciento en las apps de watchOS).20 La página sobre juegos añade la legibilidad: «To keep text comfortably legible on each device, ensure that it contrasts well with the background and uses at least the recommended minimum text size in each platform.» (para que el texto sea cómodamente legible en cada dispositivo, asegúrate de que contrasta bien con el fondo y usa al menos el tamaño de texto mínimo recomendado en cada plataforma).66
El rango de Body, de 14 a 53 puntos, va de alrededor del 82 % a alrededor del 312 % de su valor predeterminado de 17; los tamaños redondeados de la caja a 3×, de 13,33 a 53,33 puntos, van del 80 % al 320 % de su propio valor predeterminado de 16,67, por encima del 200 % que pide la página Accessibility.601133
Escalar una fuente personalizada
Apple tiene tres maneras de escalar un valor con Dynamic Type, y una para impedirlo.
UIFontMetrics, «A utility object for obtaining custom fonts that scale to support Dynamic Type» (un objeto utilitario para obtener fuentes personalizadas que escalan para admitir Dynamic Type), disponible desde iOS 11.0, conscaledFont(for:),scaledFont(for:maximumPointSize:)yscaledValue(for:), que «Scales an arbitrary layout value based on the current Dynamic Type settings» (escala un valor de diseño arbitrario según los ajustes actuales de Dynamic Type).67Font.custom(_:size:relativeTo:), en SwiftUI, crea una fuente personalizada «that scales relative to the giventextStyle» (que escala en relación con eltextStyledado), desde iOS 14.0.68ScaledMetric, «A dynamic property that scales a numeric value» (una propiedad dinámica que escala un valor numérico), desde iOS 14.0.69Font.custom(_:fixedSize:)crea una fuente personalizada «that does not scale with Dynamic Type» (que no escala con Dynamic Type), desde iOS 14.0.68
Una fuente pixelada necesita la primera o la tercera junto con la última: leer el tamaño que usaría el sistema, redondearlo a la cuadrícula de la fuente y aplicar el tamaño redondeado como tamaño fijo para que el sistema no lo vuelva a escalar. El redondeo en sí es aritmética, y está en el encargo de la sección 12: un pixel de fuente pasa a ser m pixeles de dispositivo, m = max(m₀, ⌊size × displayScale / 10 + 0.5⌋) para un em de 10 pixeles, el número entero más cercano con la mitad redondeando hacia arriba, donde m₀, el menor m de al menos 11 puntos, vale 4 a 3× y 3 a 2×, y el tamaño en puntos es 10 × m / displayScale. A 3× eso lleva los doce tamaños de Body a valores de m de 4, 5, 5, 5, 6, 6, 7, 8, 10, 12, 14 y 16 (Small, de 15 puntos, es la única mitad exacta: 4,5 redondea a 5): 16,67 puntos en el tamaño predeterminado y 53,33 en AX5.11
Para limitar el tamaño dentro de una vista, dynamicTypeSize(_:) (iOS 15.0) fija o acota el tamaño de Dynamic Type, y su página aconseja: «When limiting the Dynamic Type size, consider if adding a large content view with accessibilityShowsLargeContentViewer() would be appropriate.» (al limitar el tamaño de Dynamic Type, considera si sería adecuado añadir una vista de contenido grande con accessibilityShowsLargeContentViewer()).70 Ese modificador, también de iOS 15.0, lleva su propia advertencia: «Don’t use the large content viewer as a replacement for proper Dynamic Type support.» (no uses el visor de contenido grande como sustituto de una compatibilidad adecuada con Dynamic Type).71 El encargo limita solo los globos, que deben seguir siendo de una línea, y nunca la caja.
Incluir la fuente
Una fuente se distribuye en el paquete de la app y se nombra en UIAppFonts, «App-specific font files located in the bundle and that the system loads at runtime» (archivos de fuente propios de la app, ubicados en el paquete, que el sistema carga en tiempo de ejecución) (iOS 3.2), o se registra en código con CTFontManagerRegisterFontsForURL(_:_:_:) (iOS 4.1).7273
Dibujar el marco y colocar la línea base
Un marco dibujado a partir de unos pocos tiles es una imagen redimensionada sin suavizado. Image.interpolation(_:), de SwiftUI, fija la calidad de interpolación desde iOS 13.0, e Image.resizable(capInsets:resizingMode:), que «Sets the mode by which SwiftUI resizes an image to fit its space» (fija el modo en que SwiftUI redimensiona una imagen para que quepa en su espacio), estira o repite en mosaico todo salvo las esquinas, también desde iOS 13.0.7475 El encargo dibuja su marco en un Canvas, para que cada pixel de origen sea exactamente m por m pixeles de dispositivo; según mi lectura, resizable(capInsets:) con .tile serviría igual solo si su mosaico cae en pixeles de dispositivo enteros, algo que nadie ha medido.
Text.baselineOffset(_:), que «Sets the vertical offset for the text relative to its baseline» (fija el desplazamiento vertical del texto respecto de su línea base) (iOS 13.0), es la herramienta para una fuente cuya cuadrícula queda fuera de la línea base, como la de PixelMplus12; la sección 6 midió que un desplazamiento arregla una fuente así en un solo tamaño, que es una de las razones por las que el encargo no la usa.767
El salto de línea japonés en SwiftUI y UIKit
typesettingLanguage(_:isEnabled:) (iOS 17.0) es para un Text que «may contain text of a particular language which doesn’t match the device UI language. In that case it’s useful to specify a language so line height, line breaking and spacing will respect the script used for that language» (puede contener texto de un idioma concreto que no coincide con el idioma de la interfaz del dispositivo; en ese caso conviene especificar un idioma para que la altura de línea, el salto de línea y el espaciado respeten la escritura de ese idioma). Su página añade: «this language does not affect text localization.» (este idioma no afecta a la localización del texto).77
NSParagraphStyle.LineBreakStrategy de UIKit (iOS 9.0) tiene tres estrategias con nombre. standard (iOS 14.0) «uses the same configuration of line-break strategies that it uses for standard UI labels» (usa la misma configuración de estrategias de salto de línea que usa para las etiquetas estándar de la interfaz) y «may be unsuitable for large amounts of text» (puede no ser adecuada para grandes cantidades de texto); pushOut (iOS 9.0) está para evitar «an orphan word on the last line» (una palabra huérfana en la última línea); hangulWordPriority (iOS 14.0) es para el coreano.78
La sección 7 midió que Core Text en macOS, con la etiqueta ja, dejó que las kana pequeñas empezaran líneas en 6 de 7 anchos en la mayoría de las fuentes (4 de 7 en k8x12 y k8x12S), y sin etiqueta no.7 Qué hace el Text de SwiftUI con el japonés cuando el idioma del dispositivo es japonés, y si typesettingLanguage fija el mismo atributo que fijó la medición, no se midió (sección 11). Por eso el encargo deja sin etiquetar el texto de la caja salvo que una captura muestre que la regla estricta se mantiene con la etiqueta.
VoiceOver sobre un escenario
Los modificadores de accesibilidad de SwiftUI describen una vista: accessibilityLabel(_:) la nombra y accessibilityValue(_:) añade su valor, con una regla en su documentación: «Use this method to describe the value represented by a view, but only if that’s different than the view’s label.» (usa este método para describir el valor que representa una vista, pero solo si es distinto de la etiqueta de la vista). Los dos son de iOS 16.0 en la forma con LocalizedStringResource que listan las páginas.79
El escenario de un juego necesita más que una etiqueta. accessibilityDirectTouch(_:options:) (iOS 17.0) crea una zona donde «Direct touch areas passthrough touch events to the app rather than being handled through an assistive technology, such as VoiceOver» (las zonas de toque directo pasan los eventos táctiles a la app en lugar de que los gestione una tecnología de asistencia como VoiceOver), después de que el usuario la active.80 AccessibilityTraits.updatesFrequently (iOS 13.0) es para un elemento que cambia: «Use this trait when you want an assistive technology to poll for changes when it needs updated information.» (usa este rasgo cuando quieras que una tecnología de asistencia consulte los cambios cuando necesite información actualizada).81 AccessibilityNotification.Announcement (iOS 17.0) publica un anuncio hablado, con un atributo accessibilitySpeechAnnouncementPriority que fija cómo se encola frente a otras locuciones.82 Y accessibilityReduceMotion (iOS 13.0) informa del ajuste Reducir movimiento (Reduce Motion), que, según su página, significa que la «UI should avoid large animations» (la interfaz debe evitar animaciones grandes).83
RealityKit puede describir las propias entidades. AccessibilityComponent (iOS 17.0) es «A component that stores accessibility information for an entity» (un componente que guarda la información de accesibilidad de una entidad), cuyo nombre «VoiceOver says aloud when it describes the entity» (VoiceOver dice en voz alta cuando describe la entidad).84 El artículo de Apple «Improving the Accessibility of RealityKit Apps» dice que hay que «set the properties on each visible Entity in your scene» (fijar las propiedades en cada Entity visible de la escena): las propiedades de accesibilidad de la propia Entity, isAccessibilityElement, accessibilityLabel y accessibilityDescription, que el artículo fecha en iOS 14 y cuyas páginas están ahora marcadas como obsoletas, todas salvo isAccessibilityElement (la página también lista accessibilityLabelKey, una etiqueta como clave de cadena localizada), una vía más antigua junto al componente.85 RealityView, la vista de SwiftUI que usa el escenario de Kiradex, es de iOS 18.0.86 Si una RealityView con una cámara ortográfica virtual, como la configura Kiradex, expone esas entidades a VoiceOver no está documentado en esas páginas y no se probó (sección 11).
Probarlo ya se puede automatizar. XCUIVoiceOverService «Provides programmatic control of VoiceOver for UI testing» (ofrece control programático de VoiceOver para las pruebas de interfaz), disponible desde iOS 27.0, y se alcanza mediante la propiedad voiceOverService de XCUIDevice.87
Kiradex hoy
Leído en el repositorio el 5 de octubre de 2026, en el commit 334fbfe con las ediciones sin confirmar de ese día, sin que yo lo ejecutara ni lo cambiara; la app se estaba editando mientras la leía (sección 11):11
- Una sola fuente, la del sistema. La familia tipográfica del tema es
.systemDesign(.monospaced), y las vistas del mundo usan los roles del kit: caption en 10 llamadas repartidas en cuatro archivos, label en 3, body en 3 y title en 3.2411 - Una vía de fuente personalizada que escala de forma continua. El
Kit941.FontFamily.custom(named:)del kit compartido se resuelve enFont.custom(_:size:relativeTo:)a 34, 22, 17, 13 y 12 puntos para display, title, body, label y caption.88 Con una fuente pixelada, eso escalaría por cada tamaño de Dynamic Type, y la sección 6 cuenta que así queda fuera de su cuadrícula en 9 de 12 tamaños de Body para un em de 12 pixeles y en 11 de 12 para uno de 10.7 - El globo.
Text(text).kit941Font(.caption, weight: .bold), tinta sobreWorldInk.paper(una superficie artística con dos colores fijos), con el espaciado pequeño del kit como relleno a lo ancho y el extrapequeño a lo alto, un borde de tinta de 2 puntos y.fixedSize(), así que una línea. Se coloca un paso de espaciado grande por encima derig.headPoint, se muestra mientras la línea tiene menos de 4 segundos y se etiqueta"Said: \(text)"dentro de una superposición con la detección de toques desactivada. Esa superposición está dentro del escenario, bajo las dos superposiciones que el escenario pone sobre toda la escena: líneas de barrido, una línea negra al 16 % de opacidad cada 3 puntos, y una viñeta.2511 - La caja.
WorldHUDpone el título del lugar (caption, negrita, en mayúsculas) y su estado (caption, seminegrita) en una caja crema con el mismo borde de 2 puntos en la parte inferior de la pantalla; con el Duo medio abierto, se queda en el lado más ancho del pliegue. No recibe toques (.allowsHitTesting(false), «Taps go through to the ground under it», los toques pasan al suelo que hay debajo), y está superpuesta a todo el escenario, por encima de las líneas de barrido y de la viñeta.26 - Lo que se dice. 23 líneas predefinidas en el servidor, de 3 a 40 caracteres, con una mediana de 16; la más larga es «Anyone have a card from the first years?» (¿alguien tiene una carta de los primeros años?). Los alias son dos palabras de listas de 20 y 20 y cuatro dígitos, de 20 caracteres como máximo («Glacier Shuffle 0000»). Sobre la cabeza de un coleccionista no se dibuja nada salvo el globo; el alias aparece en el panel que abre un toque.288911 El artículo de esta serie sobre la vida propia del pueblo contó las mismas 23 líneas y un límite del servidor de una línea cada 2,0 segundos por jugador.9091
- Ninguna fuente, un solo idioma. No se incluye ningún archivo de fuente (el único
.ttfdel repositorio esscripts/screenshots/MartianMono-latin.ttf, para la herramienta de capturas); lasknownRegionsdel proyecto sonBaseyen, y no hay ningún archivo.xcstringsni.lproj.1127 - VoiceOver oye coordenadas. El escenario es un solo elemento,
.accessibilityLabel("The plaza")y.accessibilityValue(stepTrace), dondestepTracees el último paso como «x,y facing» (x,y orientación), que se mantiene porque «the walks read it, since nothing else the simulator logs reaches them» (las caminatas lo leen, ya que nada más de lo que registra el simulador les llega). NiAccessibilityComponent, niaccessibilityDirectTouch, niAccessibilityNotification, nitypesettingLanguage, niUIFontMetrics, niScaledMetric, nidynamicTypeSizeaparecen en ninguna parte del código de la app.2511 - Letreros sin letras. El
sign()de la forja es «A hanging sign on a bracket, 12 × 11» (un letrero colgado de un soporte, de 12 × 11) cuya cara son dos filas de marcas de tinta, no letras; el mapa de la plaza tiene un tile de letrero,S. Un dedo en el suelo lleva al jugador al instante hasta el tile que hay debajo y se le sigue de tile en tile; un toque en un coleccionista abre su panel al levantar el dedo, y uno en el quiosco, el tablón del pueblo; un tile de letrero es suelo como cualquier otro, sin toque propio.2992 - La escala del mundo. Según la regla de
PlazaRig.fit, la parte entera de la altura en pixeles de la vista entre 320, un texel son 8 pixeles de dispositivo en el iPhone 18 Pro Max (440 por 956 puntos) y en la pantalla interior del Duo en vertical, 6 en la pantalla exterior del Duo en vertical y en la interior en horizontal, y 4 en la exterior en horizontal: 2,67, 2,00 o 1,33 puntos.9311
Por qué el texto se queda fuera del mundo
La aritmética del artículo del mundo sobre esto es correcta: «At k = 8 on a 3× display a five-texel font is 13.3 points and at k = 6 it is 10 points, under the HIG’s 11-point minimum» (con k = 8 en una pantalla de 3×, una fuente de cinco texels mide 13,3 puntos y con k = 6 mide 10 puntos, por debajo del mínimo de 11 puntos de las HIG).23 Solo afecta a fuentes de menos de 5,5 texels con k = 6 (11 puntos a 2 puntos por texel); un em de 8 texels con k = 6 mide 16 puntos.1133 La conclusión, texto a escala de interfaz en SwiftUI, se sostiene por otra razón: a la densidad del mundo, un em de 10 pixeles mide 26,67 puntos en un teléfono a 8 pixeles de dispositivo por texel, lo que deja 29 caracteres latinos por línea de la caja en el 18 Pro Max.11 Medida en tiles, la caja del canon es estrecha. Una caja de 16 tiles de hardware de ancho, 128 pixeles, admite 16 caracteres de una fuente de 8 por 8, unos 24 de los latinos de Emerald con su media de 5,25 pixeles (21 en el peor caso, de 6), 16 de los japoneses de 8 pixeles de Emerald y 10 de los japoneses de 12 pixeles de Final Fantasy VI. Dieciséis de los tiles de 16 texels de Kiradex son 256 texels, que a la densidad propia del mundo admiten 42 caracteres latinos y 21 kana de PixelMplus12, o 64 y 32 de Misaki.11 Y una caja medida en los propios tiles de Kiradex no cabe en tres de las cinco vistas medidas: 16 tiles de 16 texels son 683 puntos a 8 pixeles de dispositivo por texel, más que el ancho del iPhone 18 Pro Max (440 puntos) y de la pantalla interior del Duo en vertical (669), y 512 puntos a 6, más que la pantalla exterior del Duo en vertical (466). Solo cabe en las dos vistas horizontales: 512 puntos en los 951 de la pantalla interior, y 341 puntos a 4 pixeles de dispositivo por texel en los 678 de la exterior.11 Una caja de Kiradex se dimensiona en puntos, no en tiles.
La misma aritmética al tamaño del encargo: PixelMplus10 con m = 5, 16,67 puntos, admite 47 caracteres latinos o 23 japoneses por línea en la caja de un 18 Pro Max en vertical, después del margen actual de 48 puntos, 16 puntos de margen y 8 de relleno por lado, contados desde el ancho completo, sin márgenes laterales (supuesto, no medido). La caja va dentro del área segura, así que en la pantalla exterior del Duo en vertical el recuento depende de su margen lateral: 50 o 25 sin margen, y 40 o 20 con el margen final de 84 puntos, el riel lateral, que esta serie midió en la pantalla cerrada (sección 11). Con el marco del encargo (sección 12, punto 3), que ocupa 8 pixeles de fuente por lado en lugar del relleno y redondea la caja hacia abajo a pixeles de fuente enteros, las mismas líneas admiten 45 o 22 en el 18 Pro Max, y 48 o 24, o 38 o 19 con el riel, en el Duo.119495
Costes
Nada de esto se ha medido en un dispositivo. Incluir una fuente de 7.253 glifos añade su archivo a la app;7 dibujar texto con SwiftUI y una fuente personalizada cuesta lo que cuesta cualquier Text; y el marco del encargo es un Canvas que se vuelve a dibujar cuando cambia su tamaño. Según mi lectura, nada de esto es grande al lado de una escena de RealityKit, pero es una lectura, y las capturas del encargo son donde se comprueba.
11. Qué está medido y qué no
Todo lo que lleva número en este artículo sale de scripts que se vuelven a ejecutar contra fuentes guardadas, de páginas guardadas el 5 de octubre de 2026 o de lecturas fechadas del código de Kiradex; las notas dicen cuál. Esta sección es la lista de lo que eso no cubre.30
Medido en el código, repetible. measure_gen_text.py sobre las cuatro descompilaciones de pret: la tabla de fuentes de Emerald (diez entradas, siete fuentes); la velocidad del texto en fotogramas y caracteres por segundo; el desplazamiento; la flecha de avance; la ventana de 27 por 4 y el marco de 30 por 6; los 20 marcos seleccionables; los anchos de los glifos latinos; 24.100 líneas de guion en caracteres y pixeles; 934 de 14.412 párrafos que nombran a un hablante; las hojas de glifos japoneses; los retardos y la ventana de FireRed; las pantallas, cajas, retardos, marcos y hojas de fuente de Crystal y Red.1 measure_ff6.py sobre el desensamblado de ff6: los estilos y paletas de ventana, la celda y los anchos de la fuente de diálogo, el tamaño y las series de anchos de la fuente japonesa, la línea de 220 pixeles, una letra por fotograma, el título de 100 fotogramas, el ajuste por palabras, la pantalla de configuración y la tabla del degradado de la ventana.4 measure_bdf.py sobre los archivos BDF de Misaki y k8x12.6 measure_coretext.swift y measure_outline_coords.swift, compilados y ejecutados en macOS 27.0, sobre diez archivos TrueType y Hiragino Sans.719 measure_kiradex_text.py sobre Kiradex tal como estaba en disco en el commit 334fbfe (vuelto a ejecutar el 15 de octubre contra el árbol vivo, con sus líneas anteriores sin cambios), y measure_figure_width.py sobre su hoja de cuerpo.1196 measure_hig.py, measure_steam_languages.py y measure_apple_docs.py sobre las páginas guardadas.606465 measure_ios27_iphones.py sobre la lista de iPhone del runtime del simulador de iOS 27.0, y probe_line_start_glyphs.swift, compilado y ejecutado en macOS 27.0, sobre las tablas de clases de JLREQ y PixelMplus10.9798 measure_cell_masks.py sobre las hojas de pret guardadas: la referencia de máscaras de celda del encargo.99 Son trece scripts; un decimocuarto, dump_glyphs.swift, guardado con las figuras de este artículo, dibujó PixelMplus10 a su propio tamaño con el suavizado de fuentes activado y desactivado.9
No medido, o más débil de lo que parece.
- Core Text en macOS hace las veces de iOS. Cada número de renderizado y de salto de línea de las secciones 6 y 7 sale de Core Text de macOS 27.0 dibujando en un contexto de mapa de bits, con el suavizado de fuentes desactivado, no de SwiftUI en un iPhone. Las comprobaciones de captura del encargo son la medición que cuenta; hasta que se ejecuten, lo que dibuja un iPhone es una predicción.79
- Mapas de bits incrustados. Misaki y k8x12 llevan tablas
EBDTyEBLC; no se determinó si Core Text dibujó esos mapas de bits o los contornos a 8 y 12 pixeles.7 - La colocación propia de SwiftUI. No se midió si SwiftUI coloca los orígenes de
Texten pixeles de dispositivo enteros, ni qué regla de salto de línea aplica al japonés cuando el idioma del dispositivo es japonés. - Pesos. PixelMplus10 Bold es la única negrita medida; la negrita sintética en cualquier fuente pixelada, no.7
- Legibilidad. Las cuadrículas y la cobertura están medidas; si los kanji de 10 por 10 se leen bien para un lector japonés a 16,67 puntos, no, y hace falta un lector japonés con un dispositivo.
- ROM japonesas. pret compila los juegos en inglés. No se leyó la caja, las velocidades ni la fuente propias del Emerald japonés; las hojas japonesas de la sección 1 son las que la ROM en inglés lleva para los nombres. No se leyeron Crystal ni Red en japonés.30
- Los gráficos de Final Fantasy VI. El desensamblado tiene rangos y código, no pixeles; no se vio la disposición de los tiles de la ventana ni cómo se ve el degradado. El rango de la fuente grande en inglés, 5.120 bytes, no es un número entero de letras de 22 bytes, sin explicación. Que la tabla del degradado se consume a un valor por línea de barrido sale de los comentarios, no se rastreó.4
- El periodo del parpadeo de Crystal no se dedujo; sus dos estados se leyeron en el código.16
- Chrono Trigger no se midió en absoluto. No se clonó ningún desensamblado público, y el mapa de la ROM de Data Crystal devolvió HTTP 403.49
- Celeste, Sea of Stars y Eastward. Solo sus listas de idiomas en Steam; cómo dibujan el texto en japonés y en chino no se encontró en ninguna fuente de los desarrolladores.64
- Pixel Operator, m5x7 y m3x6 no se descargaron ni se midieron, y el repositorio propio de Pixel Operator devolvió HTTP 404; sus licencias son las que indican sus páginas, la de Pixel Operator solo según DaFont.565758
- Los tres puntos de código de JIS que PixelMplus no asigna no se comprobaron en sus puntos de código alternativos.7
- El tamaño de DotGothic16. No tiene cuadrícula de pixeles, así que se dibujó y se compuso a 16 puntos por em nominales y a múltiplos de eso, elección mía a partir de su nombre y su paso de puntos; no se probó ningún otro tamaño nominal, y sus números de las secciones 6 y 7 son solo a esos tamaños.719
- Suavizado de fuentes. Todos los renderizados de la sección 6 impiden el suavizado de fuentes; con el valor predeterminado del contexto de mapa de bits, solo se dibujó una fuente a un tamaño, PixelMplus10 a 10 pixeles, con 178 de 272 pixeles entintados parciales. Las demás fuentes y tamaños no se dibujaron con el suavizado activado.9
- La app cambió mientras la leía. Kiradex se estaba editando el 5 de octubre mientras se escribía este artículo. Ese mismo día, más temprano, se reescribió el manejo de toques del escenario y sus líneas se desplazaron entre 30 y 144, y tres de los archivos Swift del mundo aún no estaban en ningún commit; catorce minutos después de mi lectura, el escenario y el rig habían vuelto a cambiar. El artículo lee el commit
334fbfecon las ediciones sin confirmar de ese día tal como estaban cuando las leí: los archivos de la app a las 12:28 hora del Pacífico (los coleccionistas del servidor y el mapa del pueblo a las 12:33), los scripts que la miden a las 12:34 y 12:36. Las notas dan las líneas de cada archivo en esa lectura; el encargo nombra símbolos en lugar de líneas, y a las 12:42 comprobé que cada símbolo que nombra seguía ahí.11 - Los iPhone en los que funciona la app. La lista de 33 iPhone, tres de ellos de 2×, es la del runtime del simulador de iOS 27.0, leída de Xcode en mi Mac; no se consultó la página de Apple de los iPhone compatibles con iOS 27.97
- Márgenes del área segura. El artículo de esta serie sobre el simulador del iPhone Duo midió la pantalla exterior cerrada, de 466 puntos de ancho, con su contenido de 382 puntos de ancho dentro de un margen final de 84 puntos, el riel lateral, en una sonda que mostraba la barra de estado, una barra de herramientas y una barra de pestañas.95 El mundo de Kiradex oculta la barra de estado y el indicador de inicio y no muestra barras; el código pone los controles del mundo dentro del área segura y dice que eso los mantiene lejos de las cámaras y del riel lateral, pero ni el código ni esa medición dicen qué ancho tiene el margen con la barra de estado oculta, así que los números del Duo de las secciones 10 y 12 se dan de las dos maneras, sin margen lateral y con los 84 puntos medidos. Los márgenes laterales de los demás iPhone en vertical no se midieron; los números del encargo para ellos suponen que no hay ninguno.94
- La accesibilidad de RealityKit en la configuración de Kiradex.
AccessibilityComponentestá documentado para iOS 17.0; no está verificado si unaRealityViewcon una cámara ortográfica virtual expone elementos de entidad a VoiceOver.84 - Los números del encargo. El redondeo de
m, el globo un paso más pequeño que la caja y sujeto a un techo que fija cada vista, el margen de 32 puntos, la cola de la caja y sus tres líneas, los 8 pixeles de fuente del marco en lugar del relleno de la caja, los pasos de 150 milisegundos de la marca, cuatro marcos y seis celdas para los anuncios son propuestas, no hechos.
En qué se aparta este artículo del artículo del mundo. Las secciones 1, 2, 5 y 8 corrigen cada una una afirmación de aquel, con la medición; su aritmética de tamaños es correcta (sección 10). Tres datos que este artículo toma de los otros artículos de la serie se comprobaron contra la app: las 23 líneas predefinidas del pueblo coinciden con lines.py; la nota del artículo de los personajes de que el globo todavía toma su posición de la altura de la celda coincide con PlazaRig.headPoint, que suma la mitad de la altura de fotograma de la hoja y 4 a la posición del caminante; y la figura bajo el globo es la que describe la actualización de ese artículo, de 30 texels de alto en una celda de 32 por 40, algo que confirman el manifiesto de la app, rig.py y la hoja de cuerpo. Ese artículo solo da un ancho para su figura anterior de 26 texels, unos 14 a la altura de los hombros; la sección 12 mide el ancho de la figura actual en la hoja.90100289396
Fuentes que no se alcanzaron. El mapa de la ROM de Chrono Trigger en Data Crystal (HTTP 403); el repositorio de Pixel Operator en NotABug (HTTP 404); los archivos de fuente de m5x7 y m3x6 (tras una descarga de pago voluntario, no se intentó); y una fuente de los desarrolladores sobre el texto en japonés y en chino de Celeste, Sea of Stars o Eastward (no se encontró).49565758
12. El encargo: qué construye Kiradex y qué comprobaciones debe pasar
La app ha avanzado desde entonces. En el commit fc9d4876 del 15 de octubre, la etiqueta y el valor del escenario se fijan en un modificador de vista StageAccessibility (PlazaStage.swift, aplicado en la línea 373, definido a partir de la línea 520), todavía «The plaza» con la traza de pasos como valor, y el elemento desaparece mientras un lugar cubre el escenario. Las comprobaciones de abajo leen la compilación del 5 de octubre, y cada «hoy» se refiere a esa compilación; el punto 8 se aplica a las dos.101
Síntesis del autor. Lo que sigue es mi propuesta, derivada de las secciones 1 a 11 y escrita como un diff contra Kiradex tal como estaba el 5 de octubre de 2026, en el commit 334fbfe con las ediciones sin confirmar de ese día en su árbol de trabajo (sección 11): texto monoespaciado del sistema en cada vista del mundo, un globo de una línea en caption negrita, la caja del WorldHUD abajo, una app solo en inglés con líneas predefinidas en inglés en el servidor, un sprite de letrero sin letras y un escenario que VoiceOver lee como coordenadas.2211 La dirección del artículo del mundo se mantiene: el texto es arte; el diálogo vive en SwiftUI a escala de interfaz, no en los texels del mundo; una caja construida con tiles; dos líneas; una máquina de escribir; una marca de avance.23 Lo que cambia es la fuente, por la razón que da la sección 5, y la aritmética, porque Dynamic Type hay que redondearlo a la cuadrícula de la fuente.7 Nada de esto dibuja un glifo, un marco, una marca ni una palabra de una franquicia; todo lo dibuja la forja o se compone en una fuente cuya licencia se cita en la sección 4. Las notas legales son lecturas mías, no asesoramiento legal. Nada de esto se ha construido.
Cada comprobación de abajo es una que un script, una línea de registro de una prueba o una captura pueden aprobar o suspender, salvo una comprobación manual fechada en un dispositivo, en el punto 8. Donde el resultado de una comprobación depende del dispositivo, del tamaño del texto, de la línea que elige o de qué más muestra la caja, la comprobación los nombra. El encargo nombra el código de la app por sus símbolos, no por sus números de línea, porque el código se movió mientras lo leía; las notas dan las líneas tal como las leí, con el commit y la hora. Donde la evidencia detrás de un punto es una medición en mi Mac y la comprobación se ejecuta en un iPhone o en su simulador, decide la comprobación, no el Mac.
1. Una fuente para los dos idiomas: PixelMplus10
Qué. Incluir PixelMplus10-Regular.ttf y PixelMplus10-Bold.ttf (de itouhiro, a partir de las M+ BITMAP FONTS del M+ FONTS PROJECT; licencia: M+ FONT LICENSE, https://github.com/itouhiro/PixelMplus/blob/master/misc/mplus_bitmap_fonts/LICENSE_E) mediante UIAppFonts, con LICENSE_E en el paquete, y añadir a Configuración una sección de agradecimientos, que hoy no tiene, que nombre a itouhiro y al M+ FONTS PROJECT.1872 Usarla para cada palabra dibujada sobre el mundo: los globos, la caja del WorldHUD, el texto de los letreros, el tablón de misiones y las placas de exposición. El resto de la app, la Dex, el escáner y Configuración, conserva la fuente del sistema.
Por qué esta. Dos fuentes medidas tienen las tres cosas que piden las reglas de la sección 9: japonés, una cuadrícula limpia y avances de pixeles enteros. Misaki Gothic y Misaki Gothic 2nd dibujan los 6.879 caracteres de JIS X 0208 sobre una cuadrícula de 8 pixeles en la línea base, con 0 de 848 y 0 de 860 coordenadas de contorno muestreadas fuera de ella y avances de 4 y 8. PixelMplus10 dibuja 6.876 de los 6.879, todos los kanji de los dos niveles, sobre una cuadrícula de 10 pixeles en la línea base, con 0 de 1.032 coordenadas de contorno muestreadas fuera de ella en la Regular y 0 de 1.000 en la Bold, y avances de 5 para el latín y de 10 para las kana.7 El encargo elige PixelMplus10, elección mía: es la mayor de las dos, 10 pixeles frente a los 8 de Misaki, y los kanji de 8 por 8 de Misaki son aquellos cuya legibilidad para un lector japonés está más en duda (sección 11); y viene con una Bold que se midió, así que el texto en negrita no necesita síntesis. Descartadas, cada una con la medición que la descarta:
- PixelMplus12 (M+ FONT LICENSE): su cuadrícula queda 0,39 pixeles por debajo de la línea base, y Core Text en macOS 27.0 la emborronó en todos los tamaños.7
- k8x12 (la licencia de tres frases en littlelimit.net, https://littlelimit.net/font.htm#license): su avance de kana es de 8,01 pixeles, y sus letras latinas miden 4 pixeles de ancho.717
- Misaki (la misma licencia, https://littlelimit.net/font.htm#license): tiene las tres cosas, pero sus kanji son los más pequeños medidos, de 8 por 8, y los de legibilidad más dudosa para un lector japonés (sección 11).617
- DotGothic16 (SIL Open Font License 1.1, https://github.com/google/fonts/blob/main/ofl/dotgothic16/OFL.txt): sus puntos no están en ninguna cuadrícula, y Core Text en macOS 27.0 la dibujó con entre un 37,3 % y un 82,3 % de parciales de 16 a 64 pixeles.753
- Press Start 2P (SIL Open Font License 1.1 con un Reserved Font Name, https://github.com/google/fonts/blob/main/ofl/pressstart2p/OFL.txt) y Silkscreen (SIL Open Font License 1.1, https://github.com/google/fonts/blob/main/ofl/silkscreen/OFL.txt): sin japonés.75455
- m5x7 (su página: «Creative Commons Zero v1.0 Universal», https://managore.itch.io/m5x7) y m3x6 (su página: «free to use with attribution», de uso libre con atribución, sin campo de licencia, https://managore.itch.io/m3x6): no medidas; latinas según las descripciones de sus propias páginas; tras una descarga de pago voluntario.5758
- Pixel Operator (CC0 1.0 según las notas de su autor en DaFont, https://www.dafont.com/pixel-operator.font): no medida; 241 glifos en DaFont, demasiado pocos para el japonés.56
El kit. El kit compartido de mis apps encamina cada estilo de texto por .kit941Font(role), y su vía de fuente personalizada escala una fuente de forma continua, lo que dejaría esta fuente fuera de su cuadrícula en 11 de 12 tamaños de Body, la condición en la que Core Text en el Mac la emborronó.887 El mundo ya es una superficie artística declarada, WorldInk, con sus propios dos colores.25 Añadir un modificador PixelText local de Kiradex, declarado con un comentario como la excepción de esa superficie artística, que tome un rol del kit y aplique el redondeo del punto 2; proponerlo para el kit como un caso de familia solo después de que salga.
Sin pesos sintéticos. El texto en negrita usa PixelMplus10-Bold; nada de .weight(_:) sobre la fuente pixelada, porque no se midió qué hace Core Text con un peso que tiene que sintetizar (sección 11).
Comprobaciones.
- Una prueba unitaria, ya que Core Text está en iOS, carga los dos archivos incluidos y afirma: 1.000 unidades por em; cada glifo que usan las cadenas del mundo y las líneas predefinidas, en los dos idiomas, tiene un avance múltiplo de 100 unidades; los puntos de contorno de los glifos de muestra quedan a menos de 4 unidades de la cuadrícula de 100 (0,04 de pixel de fuente, la tolerancia que usó la sonda de la sección 4). Una fuente que falle no puede salir.
- Una prueba de que cada cadena que el mundo puede mostrar (líneas predefinidas, las claves del mundo del String Catalog, los textos de los letreros) se corresponde con glifos de la fuente, sin fuente de respaldo.
- Un script de fase de compilación que encuentre LICENSE_E en el paquete de la app compilada, y una prueba de interfaz que encuentre el nombre de la fuente, su autor y su licencia en la nueva sección de agradecimientos de Configuración.
2. Tamaños: Dynamic Type, redondeado a la cuadrícula
Qué. Un pixel de fuente es siempre un número entero m de pixeles de dispositivo. Para un rol, leer el tamaño de Dynamic Type que usaría el sistema (UIFontMetrics(forTextStyle:).scaledValue(for:), o @ScaledMetric(relativeTo:) sobre el tamaño base del rol), redondear ese tamaño a la centésima de punto, para que un valor escalado apenas por debajo de un tamaño de la tabla, 14,999… para 15, redondee como el tamaño de la tabla, y luego fijar m = max(m₀, ⌊size × displayScale / 10 + 0.5⌋), el número entero más cercano con la mitad redondeando hacia arriba, donde m₀ = ⌈11 × displayScale / 10⌉ es el menor m de al menos 11 puntos, y pointSize = 10 × m / displayScale, y aplicarlo con Font.custom(_:fixedSize:) para que el sistema no lo vuelva a escalar.676968 El título y el texto de la caja pasan del rol caption que usan hoy al rol body, para que a 3× la caja lleve los doce tamaños de Body a m = 4, 5, 5, 5, 6, 6, 7, 8, 10, 12, 14 y 16: 16,67 puntos en el tamaño predeterminado y 53,33 en AX5.2611 El menor, m₀ = 4 a 3×, son 13,33 puntos, por encima del mínimo de 11.1033 A 2×, que el simulador de iOS 27.0 lista para tres iPhone (punto 4), m₀ vale 3, 15 puntos, y los doce tamaños de Body dan 3, 3, 3, 3, 4, 4, 5, 6, 7, 8, 9 y 11: 15 puntos en el tamaño predeterminado.9711 Los globos usan un paso menos, nunca por debajo de m₀ y nunca por encima de un techo que fija cada vista (punto 4).
Colocación. Una fuente pixelada es nítida solo si su línea base cae en un pixel de dispositivo (sección 6). Redondear cada origen calculado en la superposición del mundo a la cuadrícula de pixeles de dispositivo, (x × scale).rounded() / scale, incluida la .position de PlazaStage.bubbles, y dar a las vistas de texto anchos en pixeles de dispositivo enteros, y a la caja un ancho y una altura en pixeles de fuente enteros (punto 3).
Interlineado. PixelMplus10 tiene 9 pixeles de fuente hacia arriba y 2 hacia abajo; fijar el paso de línea en 12 pixeles de fuente, una fila en blanco entre líneas, como los glifos japoneses de 15 pixeles y la celda latina de 16 de Emerald caben en una línea de 16.71 Con m = 5, eso son 20 puntos por línea.33
Comprobaciones.
- Una prueba de función pura del redondeo para cada DynamicTypeSize a escalas de pantalla 2 y 3: el resultado es un número entero de pixeles de dispositivo por pixel de fuente, nunca por debajo de 11 puntos y nunca menor para un tamaño mayor. La prueba alimenta la función directamente con los tamaños de Body de la tabla de las HIG, no con valores leídos de scaledValue(for:), cuya salida exacta no he visto: a 3× los doce dan los doce valores de arriba, con el 4,5 de Small redondeando a 5, y a 2× los doce valores de 2×; cada tamaño menos una milmillonésima de punto da el mismo m, gracias al redondeo a la centésima.11
- Capturas de la plaza con un globo y la caja en Large, xxxLarge y AX3 en el simulador del iPhone 18 Pro Max, y en Large en el simulador del iPhone SE (3.ª generación) a 2×, con la superposición de los globos movida por encima de las superposiciones de líneas de barrido y viñeta del escenario (punto 4), y un script que recorta el texto y cuenta los pixeles parciales frente a los dos colores, tinta y papel: 0 dentro de las cajas de los glifos, en el globo y en la caja. Cada captura necesita el servidor de la plaza en marcha (KIRADEX_PLAZA=1) y se toma en los 4 segundos posteriores a que el jugador diga la línea más larga de hoy desde el menú Say, porque cada línea vuelve desde la sala102 y un globo solo se muestra mientras su línea tiene menos de 4 segundos.25103 El mismo script, ejecutado sobre la compilación actual, registra la línea de base a la que sustituye. El 0,0 % de la sección 6 es el Core Text de un Mac con el suavizado de fuentes desactivado; esta captura es la comprobación que decide si un iPhone dibuja lo mismo.
3. La caja: un marco dibujado por la forja, dos líneas, páginas
Qué. La caja del WorldHUD conserva su sitio: abajo, dentro del área segura, y en el lado más ancho del pliegue cuando el Duo está medio abierto.26 Su rectángulo trazado de 2 puntos pasa a ser un marco que dibuja la forja: frame-paper.png, de 24 por 24 pixeles de fuente, tres por tres tiles de 8 (una esquina, un borde y un centro), en los dos colores de WorldInk más un tono, original de Kiradex. Una vista PixelFrame lo dibuja en un Canvas, cada pixel de origen un cuadrado de m por m pixeles de dispositivo: los tiles de esquina en las cuatro esquinas, y los de borde y centro repetidos hacia fuera desde la esquina superior izquierda, con el último tile cortado donde llega al lado opuesto, de modo que los pixeles del marco son los pixeles del texto. Para que cada pixel de origen sea un cuadrado entero, el ancho de la caja es el ancho del área segura, donde la dispone hoy WorldHUD, menos 16 puntos por lado, redondeado hacia abajo a pixeles de fuente enteros, un múltiplo de m pixeles de dispositivo, y su altura también es de pixeles de fuente enteros: en el 18 Pro Max en vertical con m = 5, sin márgenes laterales (supuesto, no medido), 1.224 pixeles de dispositivo, que son 244,8 pixeles de fuente, redondeados hacia abajo a 1.220, 244 pixeles de fuente.1194 El texto va dentro del marco, a 8 pixeles de fuente del borde de la caja por cada lado, en lugar de los 8 puntos de relleno de hoy (elección mía), lo que deja ahí 228 pixeles de fuente por línea, 45 caracteres latinos o 22 de ancho completo.11 El título del lugar va en su propia línea arriba de cada página; debajo, el texto muestra dos líneas a la vez, como en Emerald y Crystal.1 El texto de más de dos líneas pasa de página, y cada página espera bajo la marca de avance (punto 6); donde una página termina en un espacio, el espacio se descarta. La box de WorldHUD (en WorldHUD.swift) recibe las páginas en lugar de su única cadena de estado.
La cola. Reglas mías, para que lo que muestra la caja nunca dependa de lo largo que sea el estado:
- Las páginas del estado son las propias de la caja. Cuando el estado cambia (en la plaza, cuando cambia cualquier cosa de él: el estado de la conexión, el recuento de quién está aquí, la hora del día, la estación, las cintas ganadas), sus páginas se sustituyen y la caja muestra el nuevo estado desde su primera página, salvo que se esté mostrando una página de la regla siguiente.
- El texto de un letrero (punto 5) y una línea dicha cerca a tamaños grandes (punto 4) son páginas por delante del estado: se muestran al instante, cada una después de cualquier página así que ya esté esperando, en el orden en que llegaron, y, después de la última, de nuevo el estado desde su primera página. La caja guarda las páginas de como máximo las tres líneas más recientes; cuando llega una cuarta, se descarta la más antigua que siga esperando y que no sea del propio jugador (la más antigua de las del jugador solo cuando todas las que esperan son suyas), así que un jugador que dice una línea nunca la pierde. Un letrero nuevo sustituye las páginas de un letrero que sigan esperando.
- El texto del estado conserva el estado completo como etiqueta de accesibilidad, se muestre la página que se muestre, como hoy, para que VoiceOver lo lea entero, y las pruebas de interfaz existentes que leen
plaza-status,room-statusyhall-status(una frase de apertura, un recuento de quién está aquí, las primeras palabras de una sala) leen lo mismo que leen ahora. La página mostrada, hasta donde se haya revelado, es el valor de un elemento oculto,plaza-pageen la plaza (<name>-page, el nombre es mío). Contiene las líneas de texto de la página sin el título del lugar, y solo existe con el argumento de lanzamiento de las pruebas de caminata,-worldTrace(punto 8); las comprobaciones de abajo lo leen, y cada una pasa-worldTrace.103
Los marcos como elección. Emerald deja que el jugador elija el marco de sus menús entre 20 (su caja de diálogo conserva un solo marco), y Final Fantasy VI el de su ventana entre 8 con colores editables.14 Ofrecer en Configuración cuatro marcos dibujados por la forja, todos gratuitos, los tres primeros desde el principio y el cuarto al alcanzar un nivel; ningún marco se vende nunca. Si algún marco llega a ser una recompensa para quienes apoyan la app es una decisión que no he tomado.
Comprobaciones. Una comprobación de la forja de que frame-paper.png y cada alternativo miden 24 por 24, usan solo índices de la paleta y tienen bordes opuestos idénticos donde el diseño lo indica; en el simulador del iPhone 18 Pro Max, una captura de la caja con m = 4 (xSmall) y m = 5 (el tamaño predeterminado), en la que un script encuentra que el ancho y la altura de la caja en pixeles de dispositivo son múltiplos de m y compara su marco, los 8 pixeles de fuente exteriores de cada lado, pixel a pixel con un marco que compone él mismo a partir del PNG al tamaño de la caja capturada con la misma regla (esquinas en las esquinas, tiles de borde y centro repetidos desde la esquina superior izquierda y cortados en el lado opuesto), cada pixel de origen un cuadrado de m por m, dejando fuera cualquier pixel que el PNG deje transparente, donde se ve el mundo; y una prueba de interfaz en el mismo simulador en el tamaño predeterminado, sin el servidor de la plaza, para que no se diga ninguna línea, lanzada con -worldTrace y -worldBoxSample y un estado de tres líneas de 30 a 40 caracteres unidas por saltos de línea, cada una dentro de los 45 caracteres por línea que caben ahí, que espera a que plaza-page sea igual a las dos primeras líneas, sin contar los espacios en blanco, y solo entonces, con la primera página completa, toca la caja y encuentra la tercera, con una captura de la primera página en la que un script encuentra la marca abajo a la derecha de la caja.11 -worldBoxSample es un argumento de prueba con nombre mío, leído en PlazaView como se lee -plazaTell (su tellOnArrival) y entregado al WorldHUD como su estado en lugar del de la plaza.92
4. Globos: una línea, sin nombre, los dos idiomas
Qué. Conservar la forma del globo: crema, un borde de tinta, sobre la cabeza, menos de 4 segundos.25 Componerlo en la fuente pixelada con el m del globo, con los pixeles de esquina del marco en lugar de un rectángulo trazado, dibujados dentro de los 8 puntos de relleno por lado del globo, para que, como el borde de hoy, no añadan ancho. Ningún nombre dentro ni encima del globo: el hablante es la cabeza sobre la que está, y VoiceOver lo nombra (punto 8). Una línea predefinida nunca se ajusta; .fixedSize() se queda.
Por encima de las líneas de barrido. Hoy los globos son una superposición dentro del escenario, bajo sus líneas de barrido, una línea negra al 16 % de opacidad cada 3 puntos (a 3×, una banda de 3 pixeles de dispositivo de cada 9), y bajo su viñeta, mientras que la caja está superpuesta a todo el escenario.2526 Bajo esas capas, el papel de un globo se oscurece en bandas que atraviesan sus glifos, así que su texto no es tinta y papel en ningún tamaño. El encargo mueve la superposición de los globos por encima de las de líneas de barrido y viñeta, donde ya está la caja, en lugar de limitar a la caja la comprobación del punto 2: elección mía, a partir de la regla de la sección 6 de que una fuente pixelada solo es nítida como pixeles de dispositivo enteros de tinta y papel, aplicada por igual a las dos formas de hablar. En PlazaStage.swift, el .overlay de los globos, el último modificador dentro del GeometryReader del escenario, pasa a ir después del .overlay de la viñeta (el RadialGradient), con un GeometryReader propio para el tamaño de la vista.25
En pantalla. Hoy un globo va centrado sobre la cabeza de su hablante, sin nada que lo mantenga dentro de la pantalla, así que un hablante cerca de un borde empuja parte del globo fuera.25 Limitar el marco del globo al área segura menos 16 puntos por cada lado, el margen que deja la regla de ancho de abajo, desplazándolo desde el centro sobre la cabeza solo lo que exija el límite. El área segura, no la vista: el escenario ignora el área segura (.ignoresSafeArea()), así que su propia geometría se extiende bajo todo lo que el área segura mantiene libre, que en el Duo son las cámaras y el riel lateral, como dice el comentario del WorldHUD sobre su propio lugar dentro del área segura.94 Hoy nada le pasa al escenario sus márgenes. PlazaView los lee fuera del escenario y se los pasa, como ya hace CardViewer con su carta (proxy.safeAreaInsets hacia CardStage); el límite es una función pura, BubblePlacement.frame(head:size:view:insets:), llamada desde PlazaStage.bubbles(of:in:), y los mismos márgenes fijan el techo del globo que se describe abajo (los nombres son míos). El mundo oculta la barra de estado y el indicador de inicio (.statusBarHidden() y .persistentSystemOverlays(.hidden) en su vista raíz); si eso estrecha los márgenes no está en el código, así que la app los lee en lugar de suponerlos.94
La regla de ancho. Cada línea, en los dos idiomas, cabe como globo de una línea en cada iPhone en el que puede funcionar la app cuando el área segura no tiene márgenes laterales; eso es lo que garantiza el límite del servidor que se describe abajo. Un margen puede dejar demasiado poco espacio incluso para m₀. Para la línea más larga de hoy, de todos los anchos que lista el simulador de iOS 27.0, eso ocurre en cada ancho de 3× hasta 393 puntos y en los dos anchos de 2× con el margen de 84 puntos del Duo, y en los teléfonos de 2× de 375 puntos con 16 puntos por lado. Una línea en el límite del servidor falla en más casos: una japonesa también en los teléfonos de 402 puntos con el margen del Duo (286 puntos de espacio frente a 296 con m₀), y una latina ahí (302,67), en el teléfono de 3× de 414 puntos con el margen (298) y en los teléfonos de 360 puntos con 16 puntos por lado (296): de los 36 casos de doce anchos y tres márgenes, 7 para la línea de hoy, 8 para una línea japonesa en el límite y 10 para una latina. Ahí esa línea no tiene globo y pasa a la caja, mientras que las líneas más cortas conservan el suyo (abajo).11 La app está hecha solo para iPhone, desde iOS 27.0, y el runtime del simulador de iOS 27.0 instalado con Xcode en mi Mac lista 33 iPhone: el más estrecho a 3× mide 360 puntos de ancho (el iPhone 12 mini y el 13 mini), y tres son de 2×, el iPhone SE de 2.ª y 3.ª generación, de 375 puntos, y el iPhone 11, de 414.97 Esa es la lista del SDK de los dispositivos que simula; no consulté la lista de Apple de los iPhone compatibles con iOS 27. El espacio para un globo es el ancho del área segura menos 32 puntos, los 16 por lado que mantiene el límite. En los teléfonos en vertical, sin márgenes laterales (supuesto; no se midió ninguno), eso son 408 en el iPhone 18 Pro Max, la más estrecha de las cinco vistas que midió esta serie, pero 328 en un teléfono de 360 puntos y 343 en los teléfonos de 2× de 375 puntos. En la pantalla exterior del Duo en vertical son 434 sin margen lateral, y 350 si el mundo conserva el margen final de 84 puntos, el riel lateral, que esta serie midió en la pantalla cerrada (sección 11).11979533 La línea más larga de hoy, «Anyone have a card from the first years?», de 40 caracteres, mide 283 puntos de ancho como globo con m = 4, 349 con 5, 416 con 6 y 549 con 8 a 3×, sus glifos más los 8 puntos de relleno por lado de hoy; el borde de 2 puntos se dibuja dentro del globo y no añade ancho. A 2×, la misma línea mide 316 puntos con m = 3 y 416 con 4.1125 Así que el m del globo tiene un techo en cada vista, el mayor con el que la línea predefinida más larga, en cualquiera de los dos idiomas, cabe en el espacio. Para las líneas de hoy, todas en inglés, es 5 en el 18 Pro Max (349 en 408) y en cada iPhone de 3× listado de 390 a 440 puntos, 4 en los teléfonos de 3× de 360 y 375 puntos, y 3, el menor que permite el 2×, en los teléfonos de 2×; en la pantalla exterior del Duo en vertical es 6 sin margen lateral (416 en 434) y 5 con el riel medido (349,33 en 350). Una línea japonesa en el límite del servidor que se describe abajo, 21 caracteres de ancho completo, 210 pixeles de fuente de avances, bajaría el del Duo a 5 y 4 y el de los teléfonos de 390 y 393 puntos a 4 (siete de los iPhone listados miden 390 puntos de ancho y cuatro, 393), y dejaría los demás como están.1197 La app calcula el techo a partir del ancho seguro que le pasa PlazaView y de las líneas que envía el servidor, así que un área segura más estrecha o una línea más larga, japonesa entre ellas, puede bajarlo. El techo es un solo valor para todas las líneas; lo que pasa donde no hay ninguno se decide línea por línea, elección mía: donde ni siquiera m₀ admite la línea más larga, una línea que cabe con m₀ conserva su globo con m₀, y una que no cabe no tiene globo y pasa a la caja, como páginas propias, igual que a tamaños grandes (abajo). Conservar con m₀ el globo de esa línea rompería el límite: en una vista de 360 puntos con un margen final de 84 puntos, el espacio es de 244 puntos, y la línea más larga de hoy con m₀ mide 282,67.11 El servidor, a su vez, limita cada línea a lo que cabe en el teléfono más estrecho de cada escala en el tamaño más pequeño, sin márgenes laterales: como máximo 218 pixeles de fuente de avances, 43 caracteres latinos o 21 de ancho completo, el menor de (360 − 48) × 3 ÷ 4 = 234 a 3× y (375 − 48) × 2 ÷ 3 = 218 a 2×. Una línea japonesa en ese límite mide 296 puntos como globo con m = 4 a 3×, y 331 con m = 3 a 2×; una latina, 302,67 y 338,50; las dos caben en los 350 del Duo con el riel.1133 Los márgenes laterales de los teléfonos en vertical no se midieron; las capturas de abajo, que afirman que el globo queda dentro del área segura, son donde aparecería alguno.
La línea predefinida más larga como globo, por tamaño, a 3×, frente al espacio de cada vista; dibujado por figures/make_figures.py a partir de measure_kiradex_text.out.
Texto más grande. El m del globo sigue al de la caja, un paso menos, nunca por debajo de m₀ y nunca por encima del techo de la vista: en el 18 Pro Max llega a 5 cuando la caja está en xLarge (m = 6), y de xxxLarge en adelante, donde el m de la caja es 7 o más, se queda en 5. Allí donde el techo deja el globo dos o más pasos por debajo de la caja (en el 18 Pro Max de xxxLarge en adelante, en un teléfono de 360 puntos de xLarge en adelante), quien lee recibe también en la caja cada línea dicha a menos de seis celdas del jugador, como páginas propias al tamaño de la caja: el alias del hablante, dos puntos y la línea, igual que Emerald nombra al hablante dentro de la línea (el punto 3 la pagina; el punto 8 la anuncia). PlazaView, que guarda las líneas de la sala y compone hoy el estado de la caja, compone esas páginas y las pone por delante del estado, según la cola del punto 3: se muestran al instante, después de las páginas de cualquier línea que ya estén esperando, con un máximo de tres líneas guardadas. Pone las páginas de una línea en la cola de la caja en la misma actualización que añade su globo, así que el globo de una línea así en pantalla significa que sus páginas están en la cola. No siempre son una página. Un alias va de 14 a 20 caracteres, así que «alias: línea» va de 19 a 62, y con el marco del punto 3 una línea de la caja en el 18 Pro Max admite 31 caracteres latinos en xxxLarge, 17 en AX3 y 12 en AX5: sobre cada alias que puede generar names.py y cada línea predefinida, una o dos páginas de xxxLarge a AX3 y hasta tres en AX4 y AX5, y hasta cuatro en los teléfonos de 360 puntos y de 2× a los tamaños más grandes y en la pantalla exterior del Duo, con el riel medido, en AX4 y AX5.1189 La caja en sí nunca se limita; se ajusta y pasa de página. La página de dynamicTypeSize(_:) sugiere una vista de contenido grande para un tamaño limitado; el encargo no depende de ella, porque la propia página de ese visor advierte contra usarlo «as a replacement for proper Dynamic Type support» (como sustituto de una compatibilidad adecuada con Dynamic Type), y ninguna de las dos páginas dice si se abre desde una superposición con la detección de toques desactivada, como la de los globos.707125 Mis notas de investigación habían propuesto detener el globo en m = 8, pero la línea más larga con 8 mide 549 puntos de ancho (las notas dan 553, contando el borde que va dentro del globo), más que el iPhone 18 Pro Max (440 puntos) y que la pantalla exterior del Duo en vertical (466), y las notas midieron el límite contra la pantalla exterior del Duo cuando la más estrecha es el 18 Pro Max, de 440; el encargo sigue aquí los anchos.2211
Comprobaciones.
- La prueba de la fuente de la app (punto 1) también afirma que una tabla de los avances de PixelMplus10 incluida en el repositorio, con una entrada por cada carácter que usan las líneas predefinidas en cualquiera de los dos idiomas, coincide con la fuente incluida. El conjunto de pruebas del servidor, que no tiene analizador de fuentes (sus dependencias son FastAPI, uvicorn, websockets, httpx y pytest), lee esa tabla, rechaza una línea que contenga un carácter que la tabla no tenga y rechaza una línea, en cualquiera de los dos idiomas, cuyos avances sumen más de 218 pixeles de fuente, el límite de arriba.10411
- Una prueba unitaria del techo, una función pura del ancho seguro, la escala de pantalla y los avances de las líneas: a 3× da, con la línea más larga de hoy, 5 para cada ancho listado de 390 a 440 puntos, 4 para 360 y 375, 6 para 466 y 5 para 382 (la pantalla exterior del Duo, sin y con el riel medido), y a 2× 3 para 375 y 414; con una línea japonesa de 210 pixeles de fuente entre las líneas, 5 para 466, 4 para 382 y 4 para 390 y 393; y ninguno para un espacio de 244 puntos (360 puntos menos el margen de 84 y 32) a 3× con la línea más larga de hoy; y una prueba del compositor de PlazaView que, en ese espacio, no dibuja ningún globo para la línea más larga de hoy y pone sus páginas en la caja, y dibuja «Hi!» como globo con m₀ (36 puntos de ancho, en 244).11
- Una prueba unitaria de BubblePlacement pone la cabeza de un hablante en cada borde, cada esquina y el centro de vistas de 360, 375, 440 y 466 puntos de ancho, cada una sin márgenes del área segura, con 16 puntos en los lados inicial y final, y con el margen final de 84 puntos del Duo, y globos de varios anchos hasta el ancho seguro de ese caso menos 32 (de 244 puntos, 360 menos 84 y 32, a 434), y encuentra cada globo dentro del área segura menos 16 puntos por cada lado y, siempre que la x de la cabeza quede dentro de esa franja, abarcando la x de la cabeza.11
- En los simuladores del iPhone 18 Pro Max, el iPhone 13 mini y el iPhone SE (3.ª generación), y en la pantalla exterior del iPhone Duo en su simulador, cuatro capturas en cada uno (inglés y japonés, cada uno en el tamaño predeterminado y en AX3), con el servidor de la plaza en marcha (KIRADEX_PLAZA=1) y la app lanzada con -worldTrace, cada una con la línea más larga de ese idioma dicha por el jugador; en cada una, un script encuentra el borde de tinta del globo y afirma que mide una línea de texto de alto, no más que el ancho del área segura menos 32 puntos, y que queda dentro del área segura menos 16 puntos por cada lado. El script toma los márgenes de la prueba de interfaz que hace la captura, que los lee de un elemento oculto que activa -worldTrace (punto 8), donde PlazaView escribe los márgenes que leyó (propuesta mía); el script también encuentra el m del globo a partir de los pixeles de sus glifos y afirma que es el menor entre el m de la caja menos uno (nunca por debajo de m₀) y el techo para ese ancho seguro, calculado a partir de las líneas de la compilación en los dos idiomas, de modo que es igual al techo solo donde el techo lo limita. En el tamaño predeterminado eso es 4 en los teléfonos de 3× y en el Duo, sea cual sea el techo, y 3 en el teléfono de 2×; en AX3 es el techo, y en el Duo lo deciden los márgenes: con las líneas en inglés de hoy, 6 sin margen lateral y 5 con el riel, y con una línea japonesa en el límite del servidor, 5 y 4.119597
- Una prueba de interfaz en el simulador del iPhone 18 Pro Max en AX3, donde el m de la caja es 12 y una línea admite 17 caracteres latinos, necesita el servidor de la plaza (KIRADEX_PLAZA=1) y ningún otro jugador, y se lanza con -worldTrace y la velocidad del texto en Instantánea (punto 6) mediante la clave world.textSpeed que nombra el punto 5, para que cada página se muestre entera en cuanto se abre y un toque en la caja pase exactamente una página. Lee el alias del jugador en la pestaña Me, elige «Hi!» en el menú Say y espera, dentro de los 5 segundos que permite la prueba de compañía existente, al globo Said: Hi!, de modo que la línea ha vuelto desde la sala y, según la regla del punto 4, sus páginas están en la cola de la caja, por delante del estado, sea cual sea la longitud del estado. Puede haber por delante una línea de los cuatro coleccionistas del pueblo, que dicen cada uno como mucho una cada 20 segundos; la cola guarda como máximo tres líneas y nunca descarta la única línea de un jugador (punto 3), así que como mucho hay dos líneas por delante, de como mucho dos páginas cada una ahí, y las líneas dichas después esperan detrás. La prueba lee plaza-page antes de cada toque y toca la caja solo mientras la página no sea el alias, dos puntos, un espacio y «Hi!», con un segundo entre toques y como máximo cuatro veces, y aprueba si una lectura encuentra esa página, la última lectura un segundo después del cuarto toque. Nombra esa línea porque «alias: Hi!» es una sola página ahí para cada alias que puede generar names.py, mientras que la línea más larga puede ocupar dos. Registra cada página que leyó.11103102
5. Letreros y nombres
Letreros. El arte de los letreros sigue sin letras, tal como lo dibuja kit.py, para que un solo atlas sirva a los dos idiomas.29 Un toque en un tile de letrero abre la caja del WorldHUD con el texto del letrero, como páginas por delante del estado (punto 3), en lugar de llevar allí al jugador como hace hoy. Hoy el escenario lee los toques mediante un DragGesture: touched(_:in:) lleva al jugador al instante al suelo que hay bajo el dedo, salvo sobre un coleccionista o el quiosco, que esperan a que se levante el dedo, y lifted(_:in:) interpreta ese levantamiento como un toque. Un tile de letrero se une al coleccionista y al quiosco en los dos: espera a que se levante el dedo, y lifted(_:in:) llama para él a un cierre onSign igual que llama a onKiosk para el quiosco (el nombre es mío).92 Los textos de los letreros viven con el mapa: town.json gana signs: { "7,10": { "en": ..., "ja": ... } }, con la celda como clave, y las comprobaciones de la forja rechazan una celda de letrero sin los dos idiomas.
Nombres. Nada de etiquetas de nombre permanentes sobre las cabezas. La caja del canon nombra al hablante dentro de la línea, Emerald en el 6,5 % de sus párrafos.1 Los alias de Kiradex llegan a 20 caracteres; al tamaño más pequeño del globo, m = 4 a 3× y 3 a 2×, un alias de 20 caracteres mide 133 puntos de ancho a 3× y 150 a 2×; a 3× eso queda sobre una figura de 16 texels de ancho de frente a la cámara y 13 de perfil (30 de alto, en una celda de 32 por 40), que son 42,7 puntos, o 34,7, en el 18 Pro Max.119610033 El alias aparece en el panel que abre un toque, como ahora, y VoiceOver lo lee (punto 8).
Comprobaciones. Una prueba de interfaz no puede saber dónde se dibuja en pantalla la celda del letrero, porque la cámara sigue al jugador, así que la prueba lanza la plaza con -worldTrace y -plazaTapCell 7,10, un argumento de prueba con nombre mío leído en el cuerpo de PlazaStage igual que -plazaFacingDemo (en un .task), que envía la celda por el mismo manejo, extraído de lifted(_:in:) a un único método. En el simulador del iPhone 18 Pro Max en el tamaño predeterminado, sin el servidor de la plaza, para que no se diga ninguna línea, la prueba también pasa el -worldBoxSample del punto 3 con un estado de una página, «Sample.», y la velocidad del texto en Instantánea (punto 6) mediante su clave de Configuración en los argumentos de lanzamiento (la clave, world.textSpeed, es mía, junto a la world.stick del joystick). Espera hasta 5 segundos a que plaza-page cambie de «Sample.» a la primera página del letrero, luego la lee, toca la caja y vuelve a leer, como máximo un toque por cada palabra del texto del letrero (cada carácter, en japonés), más uno, hasta que plaza-page diga «Sample.», y comprueba que las páginas anteriores, unidas en orden, son iguales al texto en inglés del letrero, sin contar los espacios en blanco, así que un texto de letrero lo bastante largo para pasar de página aprueba igual que uno corto; relanzada con el japonés como idioma de la app, el texto en japonés.92 La comprobación de la forja rechaza un town.json con una celda S a la que le falte cualquiera de los dos idiomas.
6. Velocidad del texto y marca de avance
Qué. Un revelado de máquina de escribir cuyo recuento es tiempo, no fotogramas: shown = floor(elapsed × cps), una función pura del tiempo transcurrido, la velocidad y dos ajustes, Reducir movimiento y VoiceOver en marcha, para que 60 y 120 hercios revelen a la misma velocidad. Configuración ofrece Lenta, 12 caracteres por segundo, la lenta de Crystal; Normal, 30, la predeterminada, elección mía entre los ajustes medios del canon (los 15 de Emerald, los 20 de Crystal) y su ajuste rápido de 60; e Instantánea. Un toque durante el revelado completa la página; un toque en una página completa la pasa.1 Para eso, la caja recibe toques mientras está revelando o tiene una página después de la que se muestra; en su última página, mostrada entera, deja pasar los toques al suelo, como hace todo el tiempo hoy.26 La misma velocidad en los dos idiomas, igual que Final Fantasy VI imprime los dos a una letra por fotograma.4 Con Reducir movimiento activado, o con VoiceOver en marcha, la función devuelve la página entera de una vez; es elección mía, a partir de la frase de la documentación de que con Reducir movimiento la «UI should avoid large animations».83
La marca. Una marca propia de Kiradex dibujada por la forja, una cuña hacia abajo de 5 por 3 pixeles de fuente, abajo a la derecha de la caja, que baja 0, 1, 2 y 1 pixeles de fuente (la dirección es elección mía; la de Emerald, según mi lectura, sube) cada 150 milisegundos, en un ciclo de 600 milisegundos: el paso de 9 fotogramas de Emerald a 60 hercios.133
Comprobaciones. Una prueba unitaria de la función de revelado a 30 caracteres por segundo: 0 caracteres en t = 0 y 30 en 1,000 segundos, con el tiempo transcurrido calculado a partir de un recuento de ticks, los ticks divididos entre la frecuencia, a 60 y a 120 ticks simulados por segundo, no sumado a partir de deltas por tick (120 deltas de 1/120 sumados en doble precisión dan 0,9999999999999989, que, por 30, es 29,999999999999968 y se trunca a 29); la misma función con Reducir movimiento activado, y por separado con VoiceOver en marcha, devuelve la página entera en t = 0; una prueba de interfaz en el simulador del iPhone 18 Pro Max en el tamaño predeterminado y en Lenta, sin el servidor de la plaza, lanzada con -worldTrace y el estado -worldBoxSample del punto 3, cuya primera página son dos líneas de 30 a 40 caracteres, al menos 60 caracteres y por tanto al menos 5 segundos de revelado a 12 por segundo, que comprueba que un toque en la caja un segundo después de empezar el revelado hace que plaza-page sea la página entera en medio segundo, cuando el revelado por sí solo mostraría 18 caracteres (12 en el momento del toque); una prueba unitaria del desplazamiento de la marca como función del tiempo transcurrido, 0, 1, 2, 1 y 0 pixeles de fuente a 0, 150, 300, 450 y 600 milisegundos; y una grabación de pantalla de dos segundos de la marca en el simulador en la que sus desplazamientos, sin repeticiones, siguen 0, 1, 2, 1 en orden cíclico.33
7. Japonés
Qué. Japonés primero para el texto del mundo, el resto de la app más adelante. server/app/lines.py conserva el orden de sus índices, como dice su comentario, «add at the end only» (añadir solo al final), y cada línea pasa a ser una cadena en inglés y otra en japonés; el servidor envía las dos, y cada cliente muestra el idioma que lee su usuario, así que una línea dicha en una plaza mixta se lee en dos idiomas a partir de un solo índice.28 Ese es, según mi lectura, el mejor argumento a favor de las líneas predefinidas en esta app. Las cadenas del mundo, los títulos y estados del WorldHUD y los títulos de las misiones, pasan a un String Catalog con ja; los textos de los letreros se quedan con el mapa (punto 5). Cada cadena en japonés la escribe o la revisa un hablante de japonés; ninguna sale traducida automáticamente y sin revisar.
Salto de línea. Las líneas predefinidas nunca se ajustan (punto 4). El texto de la caja se escribe para caber en dos líneas por página en el tamaño predeterminado, igual que el guion de Emerald se cortó a mano.1 Donde tenga que ajustarse, mantener la regla estricta: no etiquetar el texto de la caja con un idioma de composición ja salvo que una captura muestre que la regla estricta se mantiene con él, porque Core Text en macOS, con la etiqueta ja, dejó que las kana pequeñas empezaran líneas en 6 de 7 anchos en la mayoría de las fuentes (4 de 7 en k8x12 y k8x12S).777 Si un valor predeterminado del sistema aplica de todos modos la regla relajada, la corrección escrita es un U+2060 WORD JOINER antes de la kana pequeña en las pocas cadenas que lo necesiten.
Comprobaciones. Una prueba de que cada línea y cada clave del mundo en el String Catalog tienen los dos idiomas; la prueba del servidor del punto 4, que rechaza una línea predefinida en japonés por encima del límite de 218 pixeles de fuente, 21 caracteres de ancho completo; y, en el simulador del iPhone 18 Pro Max en el tamaño predeterminado con el idioma del dispositivo en japonés, sin el servidor de la plaza y a velocidad Instantánea, lanzada con -worldTrace, una captura de cada página de un párrafo de prueba en la caja, pasado como el estado -worldBoxSample del punto 3 y escrito de modo que, con los 22 caracteres de ancho completo por línea que caben ahí, un corte caería antes de una kana pequeña, en la que ninguna línea a partir de la segunda del párrafo empieza por un carácter de la lista de inicio de línea de JLREQ o por una forma de compatibilidad de uno de ellos.11 Esa lista es la completa, las 83 entradas de las diez clases que nombra la regla del 3.1.7 (tres caracteres están en dos clases), incluida en el target de pruebas; la sonda de la sección 7 usó una lista parcial (sección 7). El software de composición japonés suele poner en su lugar las formas de compatibilidad que Unicode codifica para el viaje de ida y vuelta con estándares anteriores, como señala JLREQ sobre el paréntesis de apertura: «the compatibility counterpart U+FF08 FULLWIDTH LEFT PARENTHESIS is used in the Japanese context in most Japanese text layout software» (la contraparte de compatibilidad U+FF08 FULLWIDTH LEFT PARENTHESIS es la que se usa en contexto japonés en la mayoría del software de composición de texto japonés).21 Así que la lista añade cada carácter del bloque Halfwidth and Fullwidth Forms de Unicode cuya normalización de compatibilidad (NFKC) es una de las 83, 24 en total, entre ellos ! (U+FF01), ? (U+FF1F), ) (U+FF09), :, ;, , y ., y los de medio ancho 。, 、, ー y las katakana pequeñas desde ァ (U+FF67); y ~ (U+FF5E), la tilde de ancho completo, junto al guion ondulado 〜 de la misma clase, añadido mío, ya que su normalización es la tilde ASCII, que la lista no contiene: 25 en total.98 PixelMplus10 asigna 54 de las 83 entradas y 24 de las 25 formas. No dibuja las otras 29 entradas, entre ellas 〜 (U+301C), ゠, la semirraya, ‼ y las katakana pequeñas desde U+31F0, ni el ⦆ de ancho completo (U+FF60), y la prueba de cobertura del punto 1 mantiene cada una de ellas fuera de las cadenas del mundo, así que una captura solo puede mostrar los 75 caracteres que dibuja (las 54 entradas, tres de las cuales, ), 〕 y ], están listadas en dos clases, lo que da 51 caracteres, y las 24 formas).98 Un script compara la primera celda de glifo de cada línea, pixel a pixel, con los glifos de la fuente para esos 75 al m de la captura, dibujados a partir de la fuente incluida con CTFontGetGlyphsForCharacters, y no encuentra ninguna coincidencia. Los pixeles solo pueden distinguir un carácter de la lista de los demás del párrafo donde la fuente los dibuja de forma distinta. Dibujados a 10 pixeles, dos de los 75 tienen un gemelo idéntico pixel a pixel en la fuente: ‐ (U+2010), idéntico al guion no separable U+2011, y los dos puntos, idénticos a la letra modificadora de dos puntos U+A789; ninguna de las 24 formas tiene uno. Así que el párrafo de prueba no usa ninguno de los dos gemelos; ー (U+30FC) y el kanji 一 (U+4E00) son distintos, 200 pixeles de dispositivo entintados frente a 250 con m = 5, así que 一 puede ir en cualquier parte del párrafo.9821 El resultado de la sección 7 es el Core Text de un Mac; esta captura decide lo que hace SwiftUI en iOS.
8. VoiceOver sobre el escenario
Hoy. VoiceOver oye «The plaza» y después la traza de las pruebas de caminata, como «12,4 down» (12,4 abajo).25 Ese valor es para las pruebas, no para las personas.
Qué.
1. La etiqueta del escenario sigue siendo «The plaza», o el nombre de la sala, y su valor pasa a ser una frase que una persona pueda usar: dónde está el coleccionista, por puntos de referencia, quién está cerca y qué sostiene en alto (por ejemplo, Junto al estanque. Tres coleccionistas cerca. Sostiene en alto una carta.), según la regla de accessibilityValue de que un valor dice lo que no dice la etiqueta.79 Todo lo que hoy viaja en stepTrace hasta el valor del escenario se traslada, sea quien sea quien lo escriba: cuando leí PlazaStage.swift, la traza de pasos desde rig.onStep, el mensaje de fallo de compilación desde el cierre make de la RealityView y el informe de la sonda del aire desde el .task que lee -airProbe, y minutos después una cuarta escritura, de una demo de caminata añadida ese día. Se traslada a un elemento oculto que solo existe cuando la app se lanza con -worldTrace (el nombre es mío), que pasan las pruebas de caminata, junto a la página de la caja (punto 3) y los márgenes que leyó PlazaView (punto 4), y las pruebas que leen el valor del escenario, entre ellas testTheCollectorFacesTheWayItWalks y testTheChimneysSmoke, que espera value CONTAINS 'smoke 18 ', pasan a leer ese elemento.25103
2. accessibilityDirectTouch(_:options:) en el escenario, para que un usuario de VoiceOver pueda tocar para caminar después de activarlo (iOS 17.0).80
3. La entidad de cada coleccionista recibe un AccessibilityComponent con el alias como etiqueta y lo que sostiene como valor, para que VoiceOver pueda describirlo (iOS 17.0).84
4. Una línea dicha a menos de seis celdas del jugador se publica como AccessibilityNotification.Announcement (por ejemplo, Glacier Shuffle 4471: Nice card!) con prioridad baja, como máximo una cada dos segundos, la propia frecuencia del servidor para una línea.8291
5. Una página de la caja que se abre se anuncia entera, salvo que repita una línea que el punto 4 ya haya anunciado, como hacen las páginas de texto grande del punto 4.
Comprobaciones. Una prueba de interfaz de que el valor del escenario no contiene coordenadas sin -worldTrace; en un simulador de iOS 27, una prueba con XCUIVoiceOverService que activa VoiceOver, lo lleva al escenario y afirma que lo que devuelve currentSpeech() contiene la etiqueta del escenario y ningún par de números con la forma x,y de la traza de pasos;87 una comprobación manual en un dispositivo con VoiceOver activado, fechada y con el número de compilación, de que se puede llegar a una entidad de coleccionista y que se pronuncia, porque no está verificado si una RealityView con una cámara virtual expone elementos de AccessibilityComponent (sección 11); y una prueba unitaria del limitador de anuncios, en la que dos líneas en menos de 2 segundos producen un solo anuncio.
9. Nunca, en tipografía y ventanas
- Ningún glifo, marco, flecha ni gráfico de ventana de la ROM o la descompilación de ningún juego en la app ni en la forja. Las hojas de pret y de ff6 se miden aquí y nunca se copian. El marco, la marca y el letrero de Kiradex los dibuja la forja; su tipografía es una fuente con licencia.
- Ni personajes ni ligaduras de la franquicia. El charmap de Emerald lleva glifos especiales para palabras de la franquicia; no se dibuja nada parecido, y ninguna cadena usa los nombres que la franquicia da a las cosas.31
- Ninguna fuente sin su archivo de licencia en la mano: una fuente solo sale con el texto de su licencia citado en la sección 4 o 5 y guardado junto a la evidencia.
- Ninguna fuente OFL modificada bajo su Reserved Font Name. Press Start 2P declara uno; si alguna vez se modifica una fuente OFL, se le cambia el nombre.54
- Ningún texto integrado en el arte del mundo: los letreros, las fachadas de las tiendas y los tablones siguen sin letras, para que ningún atlas sea nunca por idioma.
Comprobación. Un script calcula dos resúmenes SHA-256 de cada imagen que escribe la forja y que contiene el catálogo de recursos, uno de los bytes del archivo y otro de sus pixeles decodificados, y los compara con los mismos dos resúmenes de cada PNG medido aquí (graphics/fonts y graphics/text_window de pret, los marcos de Crystal y los gfx/font/font.png de Crystal y Red). La lista de esos resúmenes, no las imágenes, se incluye en el repositorio como scripts/forge/canon_digests.txt (un nombre que elegí, junto al kit.py de la forja), para que la comprobación funcione sin la carpeta de evidencias, y cualquier coincidencia hace fallar la compilación. Su propia prueba es un control negativo que no necesita ningún archivo de juego: añade los resúmenes de una salida de la forja a una copia de la lista y afirma que entonces el script falla. El mismo script lista para revisión, sin fallar, cualquier celda de 8 por 8 de una salida de la forja cuya máscara de un bit, o su inversa, coincida con una celda de esas hojas. Los resúmenes de imagen completa no pueden reconstruir esas celdas, así que la lista también contiene el resumen SHA-256 de cada máscara de celda distinta de las hojas, bajo una sola regla (mía), aplicada igual a las salidas de la forja: un pixel está activo donde su color difiere del pixel superior izquierdo de la imagen; las celdas van de 8 en 8 desde la esquina superior izquierda, descartando una celda parcial en un borde; una celda vacía o sólida se deja fuera en los dos lados, ya que las hojas tienen muchas (solo japanese_normal.png tiene 430 celdas vacías de 1.024); y una máscara son sus 64 bits fila a fila, 8 bytes. En las 50 hojas, eso son 7.746 celdas conservadas y 1.484 resúmenes distintos.99 Una copia recoloreada, reescalada o redibujada pasa los resúmenes; la regla 1 descansa en que la forja dibuja cada recurso desde código y en esa revisión, no solo en la comprobación. Y la comprobación de cadenas que proponen los encargos anteriores de esta serie se amplía con las abreviaturas de la franquicia del charmap de Emerald.105
Fuera de este encargo
- Una fuente pixelada para toda la app. La Dex, el escáner y Configuración conservan la fuente del sistema; la tipografía pixelada es para el mundo.
- Chino y coreano. Los cuatro juegos pixelados modernos revisados traen chino, y dos de ellos, Stardew Valley y Sea of Stars, traen coreano, pero aquí no se midió ninguna fuente pixelada para ninguno de los dos.64
- Misaki o cualquier fuente de 8 puntos para leer texto. Sus kanji son los más pequeños medidos; la legibilidad a ese tamaño para un lector japonés no está medida.6
- Etiquetas de nombre sobre las cabezas y un campo de nombre en la caja.1
- Japonés traducido automáticamente que nadie revisó.
- Negrita o cursiva sintéticas en la fuente pixelada.
- Marcos a la venta. Cada marco es gratuito; un marco para quienes apoyan la app espera una decisión.
- Texto dibujado en la escena de RealityKit. La razón del artículo del mundo y la aritmética de la sección 10 lo mantienen en SwiftUI.2311
Conclusiones clave
Si dibujas el arte
- Construye los marcos con tiles: una esquina, un borde y un centro. Los menús de Emerald eligen entre 20 marcos de 24 por 24 pixeles, tres por tres tiles; su caja de diálogo se dibuja a partir de una tira de 14 tiles con el borde inferior reflejado; los marcos de Crystal son de 6 tiles de un bit cada uno.1
- Dale a la marca de avance un reloj lento. La flecha de Emerald se desplaza 0, 1, 2 y 1 pixeles desde el reposo, un paso cada 9 fotogramas, 0,6 segundos por ciclo.1
- Mantén las palabras fuera del arte del mundo. Un letrero sin letras sirve a todos los idiomas desde un solo atlas; las palabras van en la caja.29
- Dibuja el japonés a 8 a 12 pixeles y cuenta con que una kana mida el doble que una letra latina: 8 frente a 4, 10 frente a 5 y 12 frente a 6 en todas las fuentes pixeladas con japonés medidas.7
Si construyes el motor
- Elige una fuente pixelada por su archivo, no por su nombre: comprueba la cuadrícula, el desplazamiento respecto de la línea base y los avances. La cuadrícula de PixelMplus12, 0,39 pixeles fuera de la línea base, se emborronó en todos los tamaños en Core Text sobre macOS; el avance de kana de 8,01 pixeles de k8x12 se emborronó en cuanto los glifos se colocaron con exactitud.7
- Dibuja solo con pixeles de dispositivo enteros por pixel de fuente: 0,0 % de pixeles parciales en los múltiplos enteros de una cuadrícula en la línea base con avances de pixeles enteros (Misaki, PixelMplus10, Press Start 2P), del 19,4 % al 82,2 % entre ellos, en el Core Text de un Mac con el suavizado de fuentes desactivado. Con el suavizado predeterminado del contexto, PixelMplus10 a su propio tamaño dio 178 de 272 pixeles entintados parciales, así que un múltiplo entero es necesario, no suficiente; captura un iPhone antes de fiarte de cualquiera de los dos resultados ahí.79
- Respeta Dynamic Type redondeando a la cuadrícula. Un em de 10 pixeles es entero en 1 de los 12 tamaños de Body a 3×; redondea el tamaño escalado a pixeles de dispositivo enteros por pixel de fuente y aplícalo como tamaño fijo.768
- Cuenta la velocidad del texto en tiempo, no en fotogramas, para que 60 y 120 hercios revelen igual; 60 caracteres por segundo es la cadencia más rápida en todos los juegos medidos, y de 15 a 20 el ajuste medio donde un juego lo tiene.14
- Dale a VoiceOver una frase, no una traza.
accessibilityValuees para lo que no dice la etiqueta,AccessibilityComponentdescribe una entidad yXCUIVoiceOverServicepuede probar lo que dice VoiceOver desde iOS 27.0.798487
Si diseñas el bucle
- Dos líneas a la vez, abajo. La caja de Emerald ocupa el 30 % de la pantalla y la de Crystal el 33 %, cada una con dos líneas.1
- Escribe a la medida del ancho. Los guionistas de Emerald mantuvieron el 95 % de 24.100 líneas en 38 caracteres en una ventana que admite 41, y ninguna más allá de la ventana.1
- Nombra al hablante dentro de la línea, no sobre la cabeza; la caja de Emerald no tiene campo de nombre.1
- Planifica el japonés desde el principio: cuatro de cuatro juegos pixelados modernos revisados lo traen. Una fuente que cubre JIS X 0208 dibuja unos siete mil caracteres; un juego con un guion fijo puede salir con menos, como hizo la ROM japonesa de Final Fantasy VI con 1.248 letras, y entonces cada cadena nueva hay que comprobarla contra la fuente.64584
Preguntas frecuentes
¿Qué tamaño debe tener una caja de texto en un juego de pixel art?
En los Pokémon de portátil, el tercio inferior de la pantalla y dos líneas. El marco de diálogo de Emerald mide 30 por 6 tiles, 240 por 48 pixeles, el 30 % de la altura de la pantalla de la Game Boy Advance, alrededor de una ventana de texto de 27 por 4 tiles que contiene dos líneas de una fuente de 16 pixeles. La caja de Crystal mide 20 por 6 tiles, el 33 % de la pantalla de la Game Boy, dos líneas de 18 caracteres, y la de Red es la misma de 20 por 6. Final Fantasy VI abre su ventana en la parte superior o inferior de la pantalla.12345
¿A qué velocidad debe ir un efecto de texto de máquina de escribir?
El canon cuenta fotogramas. Emerald y FireRed imprimen un carácter cada 8, 4 o 1 fotogramas, 7,5, 15 o 60 por segundo a 60 hercios, y uno por fotograma mientras se mantiene A o B tras una pulsación durante la impresión; Crystal y Red imprimen a 12, 20 o 60 por segundo; Final Fantasy VI imprime el diálogo de campo a una letra por fotograma, 60 por segundo, sin ajuste para ello (su velocidad de mensajes de seis pasos fija cuánto espera un mensaje de combate). En un teléfono moderno, cuenta los caracteres en tiempo y no en fotogramas, para que la velocidad no cambie a 120 hercios. Todos los juegos medidos llegan como máximo a 60 por segundo, y los ajustes medios de Emerald y Crystal son 15 y 20; el encargo de abajo propone 30 como valor predeterminado, que es mi elección entre esos ajustes medios y el rápido de 60, no un ajuste medido.1144
¿Qué fuentes pixeladas admiten japonés?
De las medidas, Misaki (8 por 8 puntos), k8x12 (8 por 12) y DotGothic16 dibujan los 6.879 caracteres de JIS X 0208, y PixelMplus10 y PixelMplus12, todos salvo tres puntos de código. Misaki, k8x12 y PixelMplus están bajo una licencia libre de tres frases que permite el uso, la copia y la distribución «either commercially or noncommercially» (con fines comerciales o no comerciales); DotGothic16 está bajo la SIL Open Font License 1.1. Medidas con Core Text en macOS 27.0, Misaki y PixelMplus10 son las dos con una cuadrícula limpia en la línea base y avances de pixeles enteros, a 8 y 10 pixeles; la cuadrícula de PixelMplus12 queda 0,39 pixeles por debajo de la línea base, el avance de kana de k8x12 es de 8,01 pixeles, y los puntos de DotGothic16 no están en ninguna cuadrícula de pixeles.67171853
¿Por qué mi fuente pixelada se ve borrosa en el iPhone?
Normalmente porque un pixel de fuente no es un número entero de pixeles de dispositivo. En Core Text sobre macOS 27.0 con el suavizado de fuentes desactivado, las fuentes pixeladas TrueType con una cuadrícula limpia en la línea base y avances de pixeles enteros (Misaki, PixelMplus10 y Press Start 2P) se dibujaron sin pixeles parciales en los múltiplos enteros de su cuadrícula y con entre el 19,4 % y el 82,2 % de los pixeles entintados emborronados entre ellos. Con el suavizado predeterminado del contexto de dibujo, incluso un múltiplo entero salió borroso: PixelMplus10 a sus propios 10 pixeles dio 178 de 272 pixeles entintados parciales.9 Dos fallos en el archivo de la fuente causan borrosidad en todos los tamaños: una cuadrícula desplazada de la línea base, como la de PixelMplus12, en 0,39 pixeles, y un avance que no es entero, como el avance de kana de 8,01 pixeles de k8x12 en cuanto los glifos se colocan con exactitud. La medición se hizo en un Mac; una captura en el iPhone es la comprobación que lo resuelve ahí.7
¿Puede una fuente pixelada admitir Dynamic Type?
Solo redondeando. De los doce tamaños de Body de iOS, de 14 a 53 puntos, un em de 10 pixeles cae en pixeles de dispositivo enteros a 3× solo en 40 puntos, así que una fuente pixelada que escala de forma continua con Font.custom(_:size:relativeTo:) queda fuera de su cuadrícula en los otros once; en el Core Text del Mac, fuera de la cuadrícula significó emborronada, y una captura en el iPhone decide lo que dibuja SwiftUI ahí. Lee el tamaño escalado con UIFontMetrics o ScaledMetric, redondéalo a un número entero de pixeles de dispositivo por pixel de fuente y aplícalo con Font.custom(_:fixedSize:). Apple pide que una fuente personalizada implemente los comportamientos que tienen las fuentes del sistema, entre ellos Dynamic Type, y que una app idealmente deje ampliar su texto al menos un 200 por ciento.710206768
¿Sigue Core Text las reglas japonesas de salto de línea?
En mi medición en macOS 27.0, sí, de forma estricta, cuando el texto no llevaba etiqueta de idioma: un párrafo de 131 caracteres se cortó a siete anchos sin que ninguna línea empezara por un carácter de la lista de inicio de línea de la sonda (una lista parcial, en su mayoría caracteres de JLREQ, con siete en sus formas de ancho completo), en Hiragino Sans y en ocho fuentes pixeladas. Con la etiqueta ja, se relajó a la regla más laxa que describen los requisitos de composición japonesa del W3C, y una kana pequeña empezó una línea en 6 de 7 anchos en la mayoría de las fuentes. Qué hace SwiftUI en un iPhone con el idioma del dispositivo en japonés no se midió.721
¿Cuántos caracteres necesita una fuente pixelada japonesa?
JIS X 0208, el objetivo de cobertura habitual, tiene 6.879: 524 que no son kanji, 2.965 kanji de nivel 1 y 3.390 de nivel 2. El productor de Final Fantasy Pixel Remaster le contó a Siliconera que su fuente pixelada japonesa llevó «around 7,500 characters» (unos 7.500 caracteres), frente a «a few hundred» (unos cientos) para los idiomas occidentales. Un juego con un guion fijo puede salir con menos: la ROM japonesa de Final Fantasy VI tiene 1.248 letras en su fuente de diálogo.584
Cada número de este artículo sale de un script que se vuelve a ejecutar contra fuentes guardadas, de una página guardada el 5 de octubre de 2026 o de una lectura fechada del código de Kiradex, y las notas dicen cuál; los números de Core Text son de macOS 27.0, no de iOS. El encargo de la sección 12 es mi propuesta y está marcado como tal; nada de él se ha construido.
Relacionado en este sitio: Mundos de pixel art en el iPhone es el primer artículo de esta serie, con la receta de RealityKit y la dirección para el texto que mide este artículo; Personas en pixel art: personajes y un creador en el iPhone es el coleccionista sobre el que van los globos; Estructuras en pixel art: casas, salones e interiores en el iPhone tiene la forja cuyo letrero sigue sin letras; Movimiento en pixel art: caminatas, cámaras y puertas en el iPhone tiene los relojes de 60 y 120 hercios con los que se cronometra el revelado; Un pueblo pixelado vivo cuando no hay nadie conectado tiene las líneas predefinidas y su frecuencia; Habitaciones en pixel art y Rutas en pixel art son los encargos cuyas comprobaciones amplía este; Honrar los viejos juegos de Pokémon sin tomarlos prestados es la razón por la que el canon se mide y nunca se copia; y Xcode 27.1 beta: tu app en el simulador del iPhone Duo trata el simulador en el que se ejecuta la captura del globo.
Fuentes
-
Medición del autor, 5 de octubre de 2026:
measure_gen_text.pyen la carpeta de evidencias del autor para este artículo, salidameasure_gen_text.out. Entradas de pokeemerald de pret en731ad5b:src/text.c(sFontInfos, el casoRENDER_STATE_HANDLE_CHAR,sWindowVerticalScrollSpeeds,sDownArrowYCoords, las funciones de glifos japoneses),src/menu.c(sTextSpeedFrameDelays,sStandardTextBox_WindowTemplates,WindowFunc_DrawDialogueFrameevaluado para la ventana estándar),src/fonts.cycharmap.txt(anchos de glifo),graphics/text_window/*.png(tamaños),include/text_window.h, cada línea dedata/text/*.incydata/maps/*/scripts.inccortada en\n,\ly\py medida mediante la tabla de anchos (504 archivos, 24.100 líneas sin marcador de sustitución, 3.000 con él, 0 omitidas), ygraphics/fonts/japanese_*.png(celdas no vacías). De pokefirered en037335f:src/new_menu_helpers.c. De pokecrystal en5beda23:constants/hardware.inc,constants/text_constants.asm,home/print_text.asm,gfx/font.asm, los PNG de los marcos ygfx/font/font.png. De pokered end2704a6:data/text_boxes.asm,constants/ram_constants.asm,gfx/font/font.png. Los caracteres por segundo son 60 divididos entre los fotogramas por carácter. La lectura de la impresora de Emerald (el retardo guardado menos uno porAddTextPrintery luego descontado, de modo que un carácter tarda el retardo en fotogramas), las condiciones del retardo del desplazamiento automático desrc/battle_message.cysrc/scrcmd.c, y la lectura en dos líneas de las constantes de Crystal las afirma el script, no las ejecuta. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
pret,
pokeemerald/src/menu.cen el commit731ad5b(sTextSpeedFrameDelaysen la línea 77;sStandardTextBox_WindowTemplatesen la línea 84;LoadMessageBoxGfxyLoadUserWindowBorderGfxen las líneas 212 y 213;WindowFunc_DrawDialogueFramellamada en la línea 218, con sus rellenos usandoBG_TILE_V_FLIPa partir de la línea 378), leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/menu.c. ↩↩↩↩↩↩↩ -
pret,
pokecrystal/constants/text_constants.asmen el commit5beda23(líneas 24 a 32:BORDER_WIDTH EQU 2,TEXTBOX_WIDTH EQU SCREEN_WIDTH,TEXTBOX_HEIGHT EQU 6,TEXTBOX_Y EQU SCREEN_HEIGHT - TEXTBOX_HEIGHT,TEXTBOX_INNERY EQU TEXTBOX_Y + 2) yconstants/hardware.inc(líneas 922 y 923,SCREEN_WIDTH20 ySCREEN_HEIGHT18), leído el 5 de octubre de 2026, https://github.com/pret/pokecrystal/blob/master/constants/text_constants.asm. ↩↩↩↩ -
Medición del autor, 5 de octubre de 2026:
measure_ff6.pyen la carpeta de evidencias del autor para este artículo, salidameasure_ff6.out. Entradas de everything8215/ff6 en8130132:tools/rip_list_en.jsonytools/rip_list_jp.json(rangos de bytes de los gráficos de ventana, las paletas y las fuentes),src/menu/config.asm(ConfigWindowNumPos,LoadWindowPal,ConfigColorBarTextList,ChangeConfigOption_02),src/menu/menu_sram.asm,src/btlgfx/gfx_cmd.asm(MsgSpeedTbl,mess_wait), cada archivo bajosrc/que lee$1d4d,src/field/text.asm(LoadLetterGfx, los límites x de la línea,CalcTextWidth,NewLine,UpdateDlgTextOneLine, el título del mapa),src/gfx/font_gfx.asm(FontWidth),src/field/reset.asm(el bucle de campo),src/field/hdma.asm(DlgWindowFixedColorTbl) ytools/char_table/(kanji.json,kana.json). La letra por fotograma y el valor por línea de barrido del degradado son lecturas del código, afirmadas, no ejecutadas. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Unicode Consortium,
JIS0208.TXT, la tabla de correspondencias de JIS X 0208 a Unicode, versión 2.0, archivada en OBSOLETE/EASTASIA, descargada y guardada el 5 de octubre de 2026, https://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/JIS0208.TXT. Contada pormeasure_coretext.swiftymeasure_bdf.py: 6.879 caracteres; 524 que no son kanji, 169 de ellos kana en las filas 4 y 5; 2.965 kanji de nivel 1 en las filas 16 a 47; 3.390 kanji de nivel 2 en las filas 48 a 84. ↩↩↩↩↩↩↩↩ -
Medición del autor, 5 de octubre de 2026:
measure_bdf.pyen la carpeta de evidencias del autor para este artículo, salidameasure_bdf.out. Entradas: los archivos BDF de Misaki Gothic, Misaki Gothic 2nd y Misaki Mincho y de k8x12, k8x12L y k8x12S (versiones 2021-05-05) y elJIS0208.TXTguardado; informa del tamaño en pixeles de cada fuente, su caja delimitadora, ascendente y descendente, su recuento de caracteres, sus anchos de avance, los glifos de ancho completo cuya tinta llena la celda en alguna dirección, lo mismo para los kanji (U+4E00 a U+9FFF), y los caracteres de JIS X 0208 dibujados. ↩↩↩↩↩↩↩↩↩↩↩ -
Medición del autor, 5 de octubre de 2026:
measure_coretext.swiften la carpeta de evidencias del autor para este artículo, compilado conswiftc -Oy ejecutado en macOS 27.0 (compilación 26A428), salidameasure_coretext.out, no en iOS. Entradas: Misaki Gothic, Misaki Gothic 2nd, k8x12 y k8x12S (las versiones TTF 2021-05-05), PixelMplus10 Regular y Bold y PixelMplus12 Regular (PixelMplus end89b95f), DotGothic16, Press Start 2P y Silkscreen (google/fonts en9710da1), Hiragino Sans W3 como control del sistema, y elJIS0208.TXTguardado. Informa del recuento de glifos y las tablas de mapa de bits de cada fuente (CTFontCopyAvailableTables); su cuadrícula de diseño (el menor número de pixeles por em de 4 a 40 en el que el 95 % de los puntos de contorno de los glifos de muestra quedan a menos de 0,04 pixeles, con un desplazamiento constante permitido en cada eje); sus avances latino y kana; su cobertura de ASCII y de JIS X 0208; la proporción de pixeles entintados parciales (8 a 247 de 255) al dibujar una línea de muestra en un mapa de bits gris de 8 bits a entre 1 y 4 veces la cuadrícula, con el antialiasing activado, desactivado, y activado con el posicionamiento de subpixel activado y la cuantización desactivada, sin permitir el suavizado de fuentes; para PixelMplus12, lo mismo con la línea base desplazada según el desplazamiento; los tamaños de Body y Caption 1 de las Human Interface Guidelines en los que un pixel de fuente es entero a 3×; y el primer carácter de cada línea de un párrafo japonés de 131 caracteres compuesto porCTFramesettera entre 8 y 20 em, sin etiqueta y conkCTLanguageAttributeName“ja”, frente a una lista de caracteres prohibidos al inicio de línea. DotGothic16 no tiene cuadrícula de diseño, así que se dibuja a 16 puntos por em nominales (62,5 unidades por punto) y a entre 1,25 y 4 veces eso, y se compone a 32 pixeles por em, un tamaño elegido a partir de su nombre y del paso de puntos demeasure_outline_coords.out, que la salida imprime. Cada renderizado impide el suavizado de fuentes (setAllowsFontSmoothing(false)). ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Jenni Lada, «Interview: Preparing Final Fantasy Pixel Remaster for the Switch and PS4», Siliconera, 2 de junio de 2023, el productor Naofumi Takuma sobre la nueva opción de fuente («We didn’t have any alternative data saved on file in-house for the Japanese language font, so we decided to create a new one»; «around 7,500 characters» frente a «a few hundred»), consultado el 5 de octubre de 2026, https://www.siliconera.com/interview-preparing-final-fantasy-pixel-remaster-for-the-switch-and-ps4/. ↩↩↩↩↩↩
-
Medición del autor, 5 de octubre de 2026:
figures/dump_glyphs.swiften la carpeta del borrador de este artículo, compilado conswiftc -Oy ejecutado en macOS 27.0 (26A428), salidafigures/glyphs.txt: PixelMplus10 Regular a 10 pixeles dibujada por Core Text, «Nice card!» con 0 de 94 pixeles entintados parciales cuando no se permite el suavizado de fuentes (como dibujameasure_coretext.swift) y 178 de 272 con el valor predeterminado del contexto de mapa de bits; la línea de muestra japonesa, 0 de 164 y 287 de 451. ↩↩↩↩↩↩↩↩↩↩ -
Apple, Human Interface Guidelines, «Typography» (los tamaños de texto predeterminado y mínimo, 17 y 11 puntos en iOS y iPadOS; «Follow the recommended default and minimum text sizes for each platform»; «If you use a custom font, make sure it implements the same behaviors»; las tablas de Dynamic Type de iOS), consultado el 5 de octubre de 2026, https://developer.apple.com/design/human-interface-guidelines/typography. ↩↩↩↩↩↩↩
-
Medición del autor, 5 de octubre de 2026:
measure_kiradex_text.pyen la carpeta de evidencias del autor para este artículo, salidameasure_kiradex_text.out, ejecutado a las 12:34 hora del Pacífico sobre Kiradex en el commit334fbfecon las ediciones sin confirmar de ese día, un árbol de trabajo que se estaba editando ese día; el script lee los archivos enteros, por símbolo, no por línea. Entradas, solo leídas del repositorio de Kiradex tal como estaba en disco:server/app/lines.py(23 líneas, de 3 a 40 caracteres, mediana 16),server/app/names.py(alias de dos palabras de listas de 20 y cuatro dígitos, de 20 caracteres como máximo), cada llamada a.kit941FontenKiradex/World/*.swift(caption 10, label 3, body 3, title 3, en cuatro archivos), la familia tipográfica del tema, los modificadores del globo, los modificadores de accesibilidad del escenario, una búsqueda en el código de la app deAccessibilityComponent,accessibilityDirectTouch,updatesFrequently,AccessibilityNotification,typesettingLanguage,UIFontMetrics,ScaledMetricydynamicTypeSize(0 cada uno),knownRegions(Base, en) y el recuento de archivos.xcstringsy.lproj(0); la escala del mundo según la regla dePlazaRig.fitpara los tamaños de dispositivo que esta serie midió en los perfiles del simulador de Xcode 27 (iPhone 18 Pro Max, 440 por 956 puntos; iPhone Duo exterior, 466 por 678; interior, 669 por 951; todos a 3×); y, demeasure_coretext.out, el em y los avances de cada fuente candidata, que dan los caracteres por línea de la caja tras un margen de 48 puntos, los anchos del globo para la línea predefinida más larga conm= 4, 5, 6 y 8 (283, 349, 416 y 549 puntos: sus avances a ese tamaño más los 8 puntos de relleno por lado del globo, ya que el borde se dibuja dentro del globo), y los tamaños de Body redondeados ampara un em de 10 pixeles, con la mitad redondeando hacia arriba. Añadido más tarde el 5 de octubre, con el script y la salida anteriores guardados al lado: el redondeo a 2× con el menormde al menos 11 puntos (4 a 3×, 3 a 2×); la caja con el marco del encargo (el ancho menos 32 puntos redondeado hacia abajo a pixeles de fuente enteros, 8 pixeles de fuente de marco por lado; de 1.224 pixeles de dispositivo a 1.220 en el 18 Pro Max conm= 5, 45 caracteres latinos o 22 de ancho completo por línea); las páginas de «alias: línea» para los 400 pares de palabras denames.pyy las 23 líneas en los doce tamaños de Body en cinco vistas (dos líneas por página, cortes voraces en los espacios, cada carácter ASCII imprimible de 5 pixeles de fuente de ancho segúnprobe_line_start_glyphs.out); el techo del globo en cada iPhone demeasure_ios27_iphones.out; el límite del servidor de 218 pixeles de fuente; y la suma de 120 adiciones de 1/120. Añadido más tarde ese día, con el script y la salida anteriores guardados al lado y cada línea anterior de la salida sin cambios: el espacio y el techo según el ancho seguro, sin márgenes laterales en los teléfonos y, en la pantalla exterior del Duo en vertical, tanto sin margen como con el margen final de 84 puntos que midió el artículo de la serie sobre el Duo, extraído de ese artículo (ancho seguro 382, espacio 350, techo 5 con 349,33 puntos; la caja en el tamaño predeterminado, 38 caracteres latinos o 19 de ancho completo con el marco, 40 o 20 tras el margen de hoy); las páginas de «alias: línea» en ese ancho seguro; los anchos para la prueba de colocación; el límite del servidor en ese espacio (296 y 302,67 puntos conm= 4, en 350); y, deserver/app/npcs.py, los cuatro coleccionistas del pueblo, sus alias, las páginas de sus líneas en AX3 en el 18 Pro Max (como máximo 2) y el límite de toques para la prueba del punto 4, (3 − 1) líneas × 2 páginas, un toque por página en Instantánea: 4. El 15 de octubre esa última línea se volvió a calcular para la prueba tal como está ahora, a partir de las mismas entradas hasta donde muestra la salida (el archivo del escenario de la copia del 5 de octubre leída a las 12:28;lines.py,names.pyynpcs.py, sin cambios desde el 2 y el 3 de octubre; las demás entradas leídas del árbol vivo en el commitfc9d4876, que imprimió las mismas líneas), con el script y la salida anteriores guardados al lado; cada otra línea de la salida se imprime como antes. Añadido más tarde el 15 de octubre, con el script y la salida anteriores guardados al lado y cada línea anterior sin cambios: los casos de la prueba de colocación en los que la línea más larga de hoy no cabe con ningúnmpermitido (360 y 375 puntos a 3× y 375 a 2× con el margen de 84 puntos, y 375 a 2× con 16 por lado: en el primero, un espacio de 244 puntos frente a 282,67 puntos conm₀); el techo con una línea japonesa en el límite del servidor, 21 × 10 = 210 pixeles de fuente (5 en el 18 Pro Max, 5 y 4 en el Duo sin y con el riel, 4 a 360 puntos a 3×, 3 a 2×); y elmdel globo que deberían encontrar las capturas, el menor entre elmde la caja menos uno, nunca por debajo dem₀, y el techo sobre los dos idiomas (4 en el tamaño predeterminado en las vistas de 3×, 3 en la de 2×; en AX3, el techo). Añadido esa misma noche, de la misma manera: cada ancho que listameasure_ios27_iphones.out, sin márgenes laterales, con 16 puntos por lado y con el margen final de 84 puntos, con el techo en inglés de hoy, el techo con una línea japonesa en el límite y ambos (sin márgenes: 4 a 360 y 375, 4 a 390 y 393 con la línea japonesa, 5 de 402 a 440, 3 a 2×); dónde la línea más larga de hoy no cabe con ningúnmpermitido (con el margen de 84 puntos a 360, 375, 390 y 393 puntos a 3× y a 375 y 414 a 2×; con 16 por lado a 375 a 2×); y «Hi!» conm₀, 36 puntos a 3× y 38,50 a 2×, que cabe en todos los casos. Añadido después: la misma tabla con una línea latina en el límite, 43 × 5 = 215 pixeles de fuente, junto a la línea de hoy y la japonesa, y los casos en los que cada una no cabe con ningúnmpermitido: 7, 8 y 10 de los 36. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
pret,
pokered/data/text_boxes.asmen el commitd2704a6, línea 10 (db MESSAGE_BOX, 0, 12, 19, 17), leído el 5 de octubre de 2026, https://github.com/pret/pokered/blob/master/data/text_boxes.asm. ↩↩ -
pret,
pokeemerald/src/text.cen el commit731ad5b(sFontInfosa partir de la línea 119;sDownArrowYCoords{ 0, 1, 2, 1 }en la línea 75 ysWindowVerticalScrollSpeedsen la línea 76;AddTextPrinter, que fijatextSpeed = speeden la línea 281 y--sTempTextPrinter.textSpeed;en la línea 296; eldownArrowDelay = 8de la flecha en la línea 832; en el casoRENDER_STATE_HANDLE_CHAR,if (JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp)en la línea 944, la cuenta atrásif (textPrinter->delayCounter && textPrinter->textSpeed)en la línea 947,canABSpeedUpPrinty una nueva pulsación de A o B que activahasPrintBeenSpedUpen las líneas 950 a 953, yif (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED) && gTextFlags.autoScroll)que pone el contador en 3, y si no entextSpeed, en las líneas 958 a 961;EXT_CTRL_CODE_JPNen la línea 1094;DecompressGlyph_Normala partir de la línea 1853 yGetGlyphWidth_Normala partir de la línea 1887), leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/text.c. ↩↩↩↩↩↩↩↩↩↩↩ -
pret,
pokefirered/src/text.cen el commit037335f, líneas 639 a 647 (en el casoRENDER_STATE_HANDLE_CHAR,if (JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp)que pone el contador en 0, ygTextFlags.canABSpeedUpPrint && JOY_NEW(A_BUTTON | B_BUTTON)que activahasPrintBeenSpedUpmientras se descuenta un retardo), leído el 5 de octubre de 2026, https://github.com/pret/pokefirered/blob/master/src/text.c. ↩↩↩ -
pret,
pokecrystal/home/print_text.asmen el commit5beda23(línea 4, «The text speed setting in wOptions is actually a frame count», yPrintLetterDelay, que espera un fotograma por letra mientras se mantiene A o B) ypokered/constants/ram_constants.asmend2704a6(líneas 38 a 40:TEXT_DELAY_FAST1,TEXT_DELAY_MEDIUM3,TEXT_DELAY_SLOW5), leído el 5 de octubre de 2026, https://github.com/pret/pokecrystal/blob/master/home/print_text.asm. ↩↩ -
pret,
pokecrystal/home/joypad.asmen el commit5beda23(WaitPressAorB_BlinkCursoren la línea 342;BlinkCursoren la línea 442, que alterna el tile dehlcoord 18, 17entre'▼'y'─'), leído el 5 de octubre de 2026, https://github.com/pret/pokecrystal/blob/master/home/joypad.asm. El periodo del parpadeo no se dedujo. ↩↩↩ -
Num Kadoma, littlelimit.net, «font», la sección de licencia de Misaki, k8x12 y las demás fuentes del autor («These fonts are free software. Unlimited permission is granted to use, copy, and distribute them, with or without modification, either commercially or noncommercially.»), consultado el 5 de octubre de 2026, https://littlelimit.net/font.htm#license. ↩↩↩↩↩
-
itouhiro, PixelMplus,
README.md(TrueType solo de contornos, «埋め込みビットマップは なし»; «JIS第1・第2水準のすべての漢字を収録» e ISO-8859-1; PixelMplus12 y PixelMplus10; construida a partir de las M+ BITMAP FONTS; licencia M+ FONT LICENSE) ymisc/mplus_bitmap_fonts/LICENSE_E(las tres frases de la M+ FONT LICENSE), en el commitd89b95f, leído el 5 de octubre de 2026, https://github.com/itouhiro/PixelMplus/blob/master/misc/mplus_bitmap_fonts/LICENSE_E. ↩↩↩↩↩ -
Medición del autor, 5 de octubre de 2026:
measure_outline_coords.swiften la carpeta de evidencias del autor para este artículo, compilado y ejecutado en macOS 27.0, salidameasure_outline_coords.out: las coordenadas x e y en bruto del contorno deH,A,oyあen PixelMplus12 Regular y DotGothic16 y deH,Ayoen Silkscreen, en unidades de 1.000 por em. ↩↩↩↩↩↩↩ -
Apple, Human Interface Guidelines, «Accessibility» («Ideally, give people the option to enlarge text by at least 200 percent (or 140 percent in watchOS apps).»), consultado el 5 de octubre de 2026, https://developer.apple.com/design/human-interface-guidelines/accessibility. ↩↩↩
-
W3C, «Requirements for Japanese Text Layout», Working Group Note, 11 de agosto de 2020, sección 3.1.7 (la regla de prohibición al inicio de línea y la nota sobre el conjunto de reglas menos estricto), consultado el 5 de octubre de 2026, https://www.w3.org/TR/jlreq/. ↩↩↩↩↩↩↩↩
-
Expediente de investigación del autor para este artículo, 5 de octubre de 2026 (privado): las mediciones anteriores, los casos de estudio y un primer borrador del encargo para Kiradex. ↩↩↩
-
Blake Crosley, «Pixel-Art Worlds on iPhone: What the 16-Bit Masters Knew», blakecrosley.com, 3 de octubre de 2026: la regla 10 («Text is art», el «use font size 16, 32, 48, etc» de la página de m5x7 y la frase sobre el marco de ventana de texto de 24 por 24 de Emerald), la aritmética de tamaños del texto con k = 8 y k = 6, el párrafo sobre el Pixel Remaster que cita a GoNintendo para unos 7.500 caracteres japoneses, y el plan de texto («m5x7 at integer multiples in a 24-by-24 nine-slice box, two lines, typewriter reveal, a two-frame advance arrow»), leído el 5 de octubre de 2026, https://blakecrosley.com/blog/pixel-art-world-on-iphone. Ese artículo se cita aquí y no se modifica. ↩↩↩↩↩↩↩↩↩↩
-
Código de Kiradex,
Kiradex/KiradexTheme.swift, línea 12 (let fontFamily: Kit941.FontFamily = .systemDesign(.monospaced)), leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado). ↩↩ -
Código de Kiradex,
Kiradex/World/PlazaStage.swift, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado): líneas 146, 155 y 189 (stepTracefijado a un fallo de compilación en el cierre make de laRealityView, a cada paso enrig.onStepy, con-airProbe, al informe del aire en un.task; una lectura del mismo archivo a las 12:42 mostró una cuarta,stepTrace = "lap done", con un nuevo-plazaLapDemo), líneas 58 a 61 (stepTrace, «The player’s last step, “x,y facing”, as the stage’s accessibility value: the walks read it, since nothing else the simulator logs reaches them.»), líneas 313 a 315 (.accessibilityElement(),.accessibilityLabel("The plaza"),.accessibilityValue(stepTrace)), líneas 289 a 293 (los globos, el último.overlaydentro delGeometryReaderdel escenario de las líneas 121 a 294), líneas 295 a 309 (las dos superposiciones del escenario por encima: líneas de barrido,.black.opacity(0.16)de un punto de alto cada 3 puntos, y una viñetaRadialGradient), líneas 402 a 418 (bubbles(of:in:): una línea mostrada mientrastimeline.date.timeIntervalSince(said.at) < 4, colocada en el punto de la cabeza en la vista menosKit941.Spacing.lgsin ningún límite, con la detección de toques desactivada), y líneas 444 a 459 (la vistaBubble,.padding(.horizontal, Kit941.Spacing.sm)y luego.overlay(Rectangle().strokeBorder(...)), su comentario «A line said, as the old games drew it: a cream box with a dark border.», caption negrita,WorldInk.paper, un borde de tinta deKit941.Spacing.xxs,.fixedSize(),.accessibilityLabel("Said: \(text)")). ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Código de Kiradex,
Kiradex/World/WorldHUD.swift, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado); el archivo tenía fecha del 4 de octubre y no cambió durante la lectura: líneas 31 a 38 (WorldInk, «The world’s own colours, as the old games drew a text box: cream paper», y su color de papel), líneas 40 a 44 (la línea del lugar «in a text box at the bottom. Half open, the box keeps to the wider side of the fold.»), líneas 61 a 79 (los controles en unGeometryReader, con un margen de.padding(Kit941.Spacing.md), la caja a lo largo de ese ancho o, medio abierto, el ancho del panel más ancho menosKit941.Spacing.mdpor lado), y líneas 84 a 101 (la caja: título en caption negrita, en mayúsculas; estado en caption seminegrita, identificador<name>-status,plaza-statusen la plaza; fondo de papel; un borde de tinta deKit941.Spacing.xxs;.allowsHitTesting(false)bajo el comentario «Taps go through to the ground under it.»); yKiradex/World/PlazaStage.swift, líneas 581 y 582, dondePlazaViewsuperpone elWorldHUDa todo el escenario conwordscomo su estado, y líneas 725 a 736 (words: la frase de la hora del día, el recuento de quién está aquí y una línea de consejo, las cintas ganadas y la frase de la estación). El espaciado del kit,Sources/Kit941/Tokens/Spacing.swiften 941Kit:xxs2,xs4,sm8,md16,lg24 puntos en iPhone. ↩↩↩↩↩↩↩ -
Código de Kiradex,
Kiradex.xcodeproj/project.pbxproj, líneas 1138 a 1141 (knownRegions = (Base, en)), leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado); el archivo había ganado líneas a las 12:42. ↩↩ -
Código de Kiradex,
server/app/lines.py, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado): el docstring, «The preset lines: everything anyone can say in the plaza.», las 23 entradas deLINES(a partir de la línea 5), y el comentario de la línea 20, antes del índice 14, «Indices are fixed; add at the end only, the app shows them by number.» ↩↩↩↩ -
Código de Kiradex, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit
334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado):scripts/forge/kit.py, líneas 529 y 530 (def sign():, «A hanging sign on a bracket, 12 × 11.»),Kiradex/World/TileMap.swift, línea 52 (la letra de mapa"S": .sign), yKiradex/Resources/World/town.json(una celdaS, en la x 7, fila 10, leída con el módulojsonde Python a las 12:33). ↩↩↩↩ -
Método. Descompilaciones de pret, clones superficiales leídos en pokeemerald
731ad5b(1 de octubre de 2026), pokefirered037335f(26 de septiembre de 2026), pokecrystal5beda23(29 de septiembre de 2026) y pokeredd2704a6(22 de septiembre de 2026), https://github.com/pret. Final Fantasy VI, del desensamblado everything8215/ff6 en813013276c952fdd27edcf7b8b86f17291542cbf(14 de septiembre de 2026), que contiene código y listas de extracción, no los gráficos de la ROM, https://github.com/everything8215/ff6. PixelMplus, clonado superficialmente end89b95f04eeb95bf98bb09cb9234a2f99d186df5(2 de junio de 2013); Misaki y k8x12, las versiones 2021-05-05 en TTF y BDF, descargadas del sitio del autor; Press Start 2P, Silkscreen y DotGothic16 (archivos de fuente,OFL.txtyMETADATA.pb) degoogle/fontsen9710da1(30 de septiembre de 2026). Páginas web descargadas y guardadas el 5 de octubre de 2026. Trece scripts en la carpeta de evidencias del autor para este artículo, diez en Python y tres en Swift, y un script de Swift más con las figuras de este artículo,dump_glyphs.swift, producen cada número medido, cada uno con su salida guardada al lado. pret compila los juegos en inglés; no se leyó ninguna ROM japonesa. ↩↩↩↩↩↩ -
pret,
pokeemerald/src/fonts.c(gFontNormalLatinGlyphWidthsa partir de la línea 148) ypokeemerald/charmap.txt(líneas 50 a 52, glifos especiales para palabras de la franquicia) en el commit731ad5b, leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/fonts.c. ↩↩ -
Martin Korth, GBATEK, «LCD Dimensions and Timings» («Total 228 lines, 16.743 ms, 280896 cycles - ca. 59.737 Hz»; 160 líneas visibles; 240 puntos por línea visible), consultado el 5 de octubre de 2026, https://problemkaputt.de/gbatek-lcd-dimensions-and-timings.htm. ↩
-
Aritmética del autor sobre los números medidos: 216 ÷ 5,25 = 41 caracteres; 59,737 ÷ 1 = 59,7 caracteres por segundo; 191 × 1,25² = 298 pixeles; −33 unidades de PixelMplus12 ÷ 83,33 unidades por pixel = −0,396 pixeles (la sonda informa −0,39, el centro de su intervalo); 7.500 frente a 6.879; 11 de 12 y 9 de 12 tamaños de Body fuera de la cuadrícula, por complemento de 1 y 3 enteros; 14 ÷ 17 = 82 % y 53 ÷ 17 = 312 %; 13,33 ÷ 16,67 = 80 % y 53,33 ÷ 16,67 = 320 %; 11 puntos ÷ 2 puntos por texel = 5,5 texels; 4 × 10 ÷ 3 = 13,33 puntos; 12 pixeles de fuente × 5 ÷ 3 = 20 puntos; 440 − 32 = 408, 360 − 32 = 328 y 375 − 32 = 343 puntos; 40 × 5 × 3 ÷ 2 + 16 = 316 puntos a 2×; ⌈11 × 3 ÷ 10⌉ = 4 y ⌈11 × 2 ÷ 10⌉ = 3, y 10 × 3 ÷ 2 = 15 puntos; (360 − 48) × 3 ÷ 4 = 234 y (375 − 48) × 2 ÷ 3 = 218 pixeles de fuente, y 218 ÷ 5 = 43 caracteres latinos y 218 ÷ 10 = 21 de ancho completo; 21 × 10 × 4 ÷ 3 + 16 = 296 y 21 × 10 × 3 ÷ 2 + 16 = 331 puntos; (440 − 32) × 3 = 1.224 pixeles de dispositivo, ÷ 5 = 244,8, así que 244 pixeles de fuente (1.220 pixeles de dispositivo), menos 2 × 8 = 228, ÷ 5 = 45 caracteres latinos y ÷ 10 = 22 de ancho completo; 15 × 3 ÷ 10 = 4,5, redondeado hacia arriba a 5; 120 adiciones de 1/120 en doble precisión = 0,9999999999999989, × 30 = 29,999999999999968, truncado a 29; 1,5 segundos × 12 = 18 caracteres; 20 × 5 × 4 ÷ 3 = 133 puntos y 20 × 5 × 3 ÷ 2 = 150 puntos a 2×; 466 − 84 = 382 y 382 − 32 = 350 puntos, 466 − 32 = 434; 40 × 5 × 5 ÷ 3 + 16 = 349,33 puntos; (382 − 32) × 3 ÷ 5 = 210 pixeles de fuente, menos 2 × 8 = 194, ÷ 5 = 38 caracteres latinos y ÷ 10 = 19 de ancho completo; (382 − 48) ÷ (5 × 5 ÷ 3) = 40,08 y ÷ (10 × 5 ÷ 3) = 20,04; 43 × 5 × 4 ÷ 3 + 16 = 302,67 puntos; 360 − 84 − 32 = 244 puntos; (3 − 1) × 2 × 1 = 4 toques; 16 texels × 2,67 puntos = 42,7 puntos y 13 × 2,67 = 34,7; 9 fotogramas ÷ 60 = 150 milisegundos, cuatro pasos 600 milisegundos; 3 puntos × 3 = 9 pixeles de dispositivo entre líneas de barrido, cada una de 1 punto × 3 = 3 pixeles de dispositivo de alto. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩
-
pret,
pokeemerald/src/battle_message.cen el commit731ad5b(líneas 3002 y 3003: desplazamiento automático activo cuandogBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED); línea 3010,speed = 1para la ventana de mensajes en los combates por cable; línea 3012, elspeed = sRecordedBattleTextSpeeds[GetTextSpeedInRecordedBattle()]de un combate grabado, con la tabla{8, 4, 1, 0}en la línea 1957) ypokeemerald/src/scrcmd.c(ScrCmd_messageautoscrolla partir de la línea 1286, que fijaautoScrollyforceMidTextSpeeden las líneas 1292 y 1293), leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/battle_message.c. ↩↩↩ -
pret,
pokeemerald/charmap.txten el commit731ad5b, líneas 1087 a 1089 ('\l' = FA @ scroll up window text,'\p' = FB @ new paragraph,'\n' = FE @ new line), einclude/constants/characters.h, líneas 175 y 176 (CHAR_PROMPT_SCROLL, «waits for button press and scrolls dialog»;CHAR_PROMPT_CLEAR, «waits for button press and clears dialog»), consrc/text.c, líneas 968 a 971 (CHAR_NEWLINE, que bajacurrentYuna línea) y 1102 a 1109 (las dos indicaciones que entran enRENDER_STATE_CLEARyRENDER_STATE_SCROLL_START), leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/charmap.txt. ↩ -
pret,
pokeemerald/src/text_window.c(message_box.pngen la línea 53;LoadMessageBoxGfxen la línea 93;LoadUserWindowBorderGfxen la línea 110),pokeemerald/include/text_window.h(#define WINDOW_FRAMES_COUNT 20en la línea 4),pokeemerald/src/option_menu.c(la opción FRAME) ypokeemerald/graphics/text_window/en el commit731ad5b, leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/text_window.c. ↩↩↩ -
pret,
pokeemerald/data/text/y elscripts.incde cada mapa en el commit731ad5b, entre ellosdata/maps/LittlerootTown/scripts.inc, línea 854 (.string "MOM: {PLAYER}, we're here, honey!\p"), leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/data/maps/LittlerootTown/scripts.inc. ↩↩ -
pret,
pokeemerald/src/international_string_util.c,src/contest.cysrc/battle_tower.c(los códigosEXT_CTRL_CODE_JPNyEXT_CTRL_CODE_ENGen los nombres) ygraphics/fonts/(japanese_normal.png,japanese_small.png,japanese_bold.png,japanese_frlg_male.png) en el commit731ad5b, leído el 5 de octubre de 2026, https://github.com/pret/pokeemerald/blob/master/src/international_string_util.c. ↩↩ -
pret,
pokefirered/src/new_menu_helpers.cen el commit037335f(sStandardTextBox_WindowTemplatesa partir de la línea 34,.width = 26en la línea 40, y los retardos de velocidad del texto) ypokefirered/src/text_printer.c(AddTextPrinter,textSpeed = speeden la línea 78 y--sTempTextPrinter.textSpeed;en la línea 93) en el commit037335f, leído el 5 de octubre de 2026, https://github.com/pret/pokefirered/blob/master/src/new_menu_helpers.c. ↩ -
Pan Docs, «Rendering» («One frame: 70224 dots @ 59.7 fps»; un fotograma «takes ~16.74 ms instead of ~16.67»), gbdev.io, consultado el 5 de octubre de 2026, https://gbdev.io/pandocs/Rendering.html. ↩
-
pret,
pokecrystal/gfx/font.asmen el commit5beda23(los marcosFRAME_1aFRAME_8,TEXTBOX_FRAME_TILES6 tiles de 1 bit cada uno, un noveno marco sin usar) ygfx/font/font.png, leído el 5 de octubre de 2026, https://github.com/pret/pokecrystal/blob/master/gfx/font.asm. ↩ -
everything8215, ff6,
tools/rip_list_en.jsonytools/rip_list_jp.jsonen el commit8130132(assets/gfx/window/window_%s.4bppen0xED0000a0xED1BFF;window_%s.palen0xED1C00a0xED1CFF), leído el 5 de octubre de 2026, https://github.com/everything8215/ff6/blob/master/tools/rip_list_en.json. ↩ -
everything8215, ff6,
src/menu/config.asm(ConfigWindowNumPos,LoadWindowPalleyendo de$1d57, el color de la fuente en$1d55,ConfigColorBarTextList,ChangeConfigOption_02) ysrc/menu/menu_sram.asm(línea 102, «message speed = 3, battle speed = 3») en el commit8130132, leído el 5 de octubre de 2026, https://github.com/everything8215/ff6/blob/master/src/menu/config.asm. ↩↩↩ -
everything8215, ff6, en el commit
8130132:src/btlgfx/gfx_cmd.asm, líneas 1101 a 1103 (MsgSpeedTbl, «wait duration for each battle message speed»,$20,$30,$40,$50,$60,$70,$80,$90) y líneas 1151 a 1165 (mess_wait, que lee los bits 4 a 6 de$1d4dcomo índice y llama aWaitFrameesa cantidad de veces);src/menu/config.asm, línea 1499 («battle speed, battle message speed, magic order, and window pattern») yChangeConfigOption_02a partir de la línea 933;src/menu/menu_text.en.inc, línea 346 (los ajustes dibujados como 1 a 6). Archivos cuyo código toca$1d4d:src/battle/init.asm(el ajuste de comandos, el modo de combate y la velocidad de combate),src/btlgfx/gfx_cmd.asm,src/menu/config.asm,src/menu/field_menu.asmysrc/menu/menu_sram.asm; ninguno bajosrc/field/. Leído el 5 de octubre de 2026, https://github.com/everything8215/ff6/blob/master/src/btlgfx/gfx_cmd.asm. ↩ -
everything8215, ff6,
src/field/hdma.asm(DlgWindowFixedColorTbl) ysrc/field/event.asm(línea 1591, «dialog window y position (1 or 18)») en el commit8130132, leído el 5 de octubre de 2026, https://github.com/everything8215/ff6/blob/master/src/field/hdma.asm. ↩↩↩ -
everything8215, ff6,
src/field/text.asm(LoadLetterGfx, la línea de diálogo de la x 4 a$e0,CalcTextWidth,NewLine,UpdateDlgTextOneLine, el título del mapa centrado y mostrado durante 100 fotogramas) ysrc/gfx/font_gfx.asm(FontWidth) en el commit8130132, leído el 5 de octubre de 2026, https://github.com/everything8215/ff6/blob/master/src/field/text.asm. ↩↩↩↩↩ -
everything8215, ff6,
tools/rip_list_jp.json(large_font.jp.1bppen0xC494C0a0xC4FFFF) ytools/char_table/en el commit8130132, leído el 5 de octubre de 2026, https://github.com/everything8215/ff6/tree/master/tools/char_table. ↩ -
everything8215, ff6,
src/field/reset.asm(el bucle de campo: espera el borrado vertical y llama aUpdateDlgTextuna vez por pasada) en el commit8130132, leído el 5 de octubre de 2026, https://github.com/everything8215/ff6/blob/master/src/field/reset.asm. El desensamblado genera la ROM en inglés y la japonesa a partir de una sola fuente. ↩↩ -
Data Crystal, «Chrono Trigger/ROM map», datacrystal.tcrf.net, consultado el 5 de octubre de 2026: HTTP 403, no leído, https://datacrystal.tcrf.net/wiki/Chrono_Trigger/ROM_map. ↩↩↩
-
Kiradex,
docs/TestFlight.md, paso 5 (líneas 192 a 194: en la Dex, elegir japonés muestra los sets y las cartas con sus nombres japoneses y el inglés debajo), leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado). ↩ -
Num Kadoma, littlelimit.net, «8×8ドット日本語フォント「美咲フォント」» (la celda de 8 por 8 de la presentación, los niveles 1 y 2 de JIS y la tinta de 7 por 7; las descripciones de Misaki Mincho y Misaki Gothic 2nd; la nota sobre la licencia de M+ FONTS; el relato de su creación para el controlador de pantalla japonés del PC-E500), consultado el 5 de octubre de 2026, https://littlelimit.net/misaki.htm. ↩↩↩↩
-
Num Kadoma, littlelimit.net, «8×12ドット日本語フォント「k8x12」» (la celda de 8 por 12, los niveles 1 y 2 de JIS, las variantes L y S, la nota de la variante S sobre los gráficos de 8 por 8 de las consolas antiguas), consultado el 5 de octubre de 2026, https://littlelimit.net/k8x12.htm. ↩
-
Google Fonts,
ofl/dotgothic16/OFL.txt(SIL Open Font License 1.1, Copyright 2020 The DotGothic16 Project Authors, sin Reserved Font Name) yMETADATA.pb(diseñadora Fontworks Inc.; subconjuntos cyrillic, japanese, latin, latin-ext; añadida el 2020-12-15) en9710da1, leído el 5 de octubre de 2026, https://github.com/google/fonts/blob/main/ofl/dotgothic16/OFL.txt. ↩↩↩↩ -
Google Fonts,
ofl/pressstart2p/OFL.txt(SIL Open Font License 1.1, «with Reserved Font Name “Press Start 2P”») yMETADATA.pb(diseñador CodeMan38) en9710da1, leído el 5 de octubre de 2026, https://github.com/google/fonts/blob/main/ofl/pressstart2p/OFL.txt. ↩↩↩ -
Google Fonts,
ofl/silkscreen/OFL.txt(SIL Open Font License 1.1, sin Reserved Font Name) yMETADATA.pb(diseñador Jason Kottke) en9710da1, leído el 5 de octubre de 2026, https://github.com/google/fonts/blob/main/ofl/silkscreen/OFL.txt. ↩↩ -
DaFont, «Pixel Operator Font» (de Jayvee Enaguas; «Bitmap (16 px)»; 15 archivos de fuente; 241 glifos; las notas del autor, «Changed licence to Creative Commons Zero (CC0) 1.0» y «licensed under a Creative Commons Zero (CC0) 1.0»), consultado el 5 de octubre de 2026, https://www.dafont.com/pixel-operator.font. El repositorio que nombran las notas, https://notabug.org/HarvettFox96/ttf-pixeloperator, devolvió HTTP 404 el 5 de octubre de 2026. Fuente única. ↩↩↩↩
-
Daniel Linssen, «m5x7», itch.io («use font size 16, 32, 48, etc»; «free to use but attribution appreciated»; «Asset license Creative Commons Zero v1.0 Universal»; ancho medio 5, ascendente 7, descendente 2, altura de x 5; sus caracteres descritos como «uppercase and lowercase letters, including many accented letters, numbers and most common symbols»; una descarga de pago voluntario), consultado el 5 de octubre de 2026, https://managore.itch.io/m5x7. No se descargó el archivo de la fuente. ↩↩↩↩↩↩
-
Daniel Linssen, «m3x6», itch.io («use font size 16, 32, 48, etc»; «free to use with attribution»; sin campo de licencia del recurso; una descarga de pago voluntario), consultado el 5 de octubre de 2026, https://managore.itch.io/m3x6. No se descargó el archivo de la fuente. ↩↩↩↩↩
-
Apple Developer Documentation, «Core Text» («Create text layouts, optimize font handling, and access font metrics and glyph data»; iOS 3.2, macOS 10.8), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/coretext. ↩
-
Medición del autor, 5 de octubre de 2026:
measure_hig.pyen la carpeta de evidencias del autor para este artículo, salidameasure_hig.out: las tablas de la página Typography guardada, los tamaños predeterminado y mínimo y cada tabla de Dynamic Type de iOS de xSmall a AX5 (Body 14, 15, 16, 17, 19, 21, 23, 28, 33, 40, 47 y 53 puntos; Caption 1 11, 11, 11, 12, 14, 16, 18, 22, 26, 32, 37 y 43). ↩↩↩↩↩ -
Unicode Consortium, «Unicode Standard Annex #14: Unicode Line Breaking Algorithm», revisión 57, Unicode 18.0.0, 2026-09-01 (la clase CJ y «Treating characters of class CJ as class NS will give CSS strict line breaking; treating them as class ID will give CSS normal breaking.»), consultado el 5 de octubre de 2026, https://www.unicode.org/reports/tr14/. ↩↩
-
Stardew Valley Wiki, «Modding:Dialogue», editada por última vez el 20 de mayo de 2026 (
$b; los comandos de retrato;Strings\SpeechBubbles), consultado el 5 de octubre de 2026, https://stardewvalleywiki.com/Modding:Dialogue. ↩↩↩ -
Stardew Valley Wiki, «Modding:Custom languages», editada por última vez el 3 de enero de 2026 (
UseLatinFont, el archivo.fnt,FontPixelZoomcon una base recomendada de 1.5,FontApplyYOffset), consultado el 5 de octubre de 2026, https://stardewvalleywiki.com/Modding:Custom_languages. ↩↩ -
Medición del autor, 5 de octubre de 2026:
measure_steam_languages.pyen la carpeta de evidencias del autor para este artículo, salidameasure_steam_languages.out, que lee las tablas de idiomas de las páginas de tienda de Steam guardadas de Stardew Valley (https://store.steampowered.com/app/413150/), Celeste (https://store.steampowered.com/app/504230/), Sea of Stars (https://store.steampowered.com/app/1244090/) y Eastward (https://store.steampowered.com/app/977880/), descargadas el 5 de octubre de 2026. ↩↩↩↩↩ -
Medición del autor, 5 de octubre de 2026:
measure_apple_docs.pyen la carpeta de evidencias del autor para este artículo, salidameasure_apple_docs.out: el título, la declaración, el resumen, las plataformas y los primeros párrafos de cada página de documentación de Apple guardada que se cita en la sección 10. ↩↩ -
Apple, Human Interface Guidelines, «Designing for games» («To keep text comfortably legible on each device, ensure that it contrasts well with the background and uses at least the recommended minimum text size in each platform.»), consultado el 5 de octubre de 2026, https://developer.apple.com/design/human-interface-guidelines/designing-for-games. ↩
-
Apple Developer Documentation, «UIFontMetrics» («A utility object for obtaining custom fonts that scale to support Dynamic Type»; iOS 11.0), «scaledFont(for:)», «scaledFont(for:maximumPointSize:)» y «scaledValue(for:)» («Scales an arbitrary layout value based on the current Dynamic Type settings»; iOS 11.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/uikit/uifontmetrics. ↩↩↩
-
Apple Developer Documentation, «custom(:size:relativeTo:)» (una fuente personalizada «that scales relative to the given
textStyle»; iOS 14.0), https://developer.apple.com/documentation/swiftui/font/custom(:size:relativeto:), y «custom(:fixedSize:)» (una fuente personalizada «that does not scale with Dynamic Type»; iOS 14.0), https://developer.apple.com/documentation/swiftui/font/custom(:fixedsize:), consultados el 5 de octubre de 2026. ↩↩↩↩↩ -
Apple Developer Documentation, «ScaledMetric» («A dynamic property that scales a numeric value»; iOS 14.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/scaledmetric. ↩↩
-
Apple Developer Documentation, «dynamicTypeSize(:)» (iOS 15.0; «When limiting the Dynamic Type size, consider if adding a large content view with
accessibilityShowsLargeContentViewer()would be appropriate.»), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/view/dynamictypesize(:). ↩↩ -
Apple Developer Documentation, «accessibilityShowsLargeContentViewer()» (iOS 15.0; «Don’t use the large content viewer as a replacement for proper Dynamic Type support.»), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/view/accessibilityshowslargecontentviewer(). ↩↩
-
Apple Developer Documentation, «UIAppFonts» («App-specific font files located in the bundle and that the system loads at runtime»; iOS 3.2), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/bundleresources/information-property-list/uiappfonts. ↩↩
-
Apple Developer Documentation, «CTFontManagerRegisterFontsForURL(:::)» (iOS 4.1), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/coretext/ctfontmanagerregisterfontsforurl(:::). ↩
-
Apple Developer Documentation, «interpolation(:)» (Image; iOS 13.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/image/interpolation(:). ↩
-
Apple Developer Documentation, «resizable(capInsets:resizingMode:)» («Sets the mode by which SwiftUI resizes an image to fit its space»; iOS 13.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/image/resizable(capinsets:resizingmode:). ↩
-
Apple Developer Documentation, «baselineOffset(:)» (Text; «Sets the vertical offset for the text relative to its baseline»; iOS 13.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/text/baselineoffset(:). ↩
-
Apple Developer Documentation, «typesettingLanguage(:isEnabled:)» (iOS 17.0; el pasaje sobre el texto en un idioma que no coincide con el idioma de la interfaz del dispositivo; «this language does not affect text localization.»), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/view/typesettinglanguage(:isenabled:). ↩↩
-
Apple Developer Documentation, «NSParagraphStyle.LineBreakStrategy» (iOS 9.0) y sus propiedades
standard(iOS 14.0),pushOut(iOS 9.0) yhangulWordPriority(iOS 14.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/uikit/nsparagraphstyle/linebreakstrategy-swift.struct. ↩ -
Apple Developer Documentation, «accessibilityValue(:)» («Use this method to describe the value represented by a view, but only if that’s different than the view’s label.»; iOS 16.0 en la forma con
LocalizedStringResource), https://developer.apple.com/documentation/swiftui/view/accessibilityvalue(:), y «accessibilityLabel(:)» (iOS 16.0), https://developer.apple.com/documentation/swiftui/view/accessibilitylabel(:), consultados el 5 de octubre de 2026. ↩↩↩ -
Apple Developer Documentation, «accessibilityDirectTouch(:options:)» (iOS 17.0; «Direct touch areas passthrough touch events to the app rather than being handled through an assistive technology, such as VoiceOver.»; la zona debe activarse primero), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/view/accessibilitydirecttouch(:options:). ↩↩
-
Apple Developer Documentation, «updatesFrequently» (AccessibilityTraits; iOS 13.0; «Use this trait when you want an assistive technology to poll for changes when it needs updated information.»), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/accessibilitytraits/updatesfrequently. ↩
-
Apple Developer Documentation, «AccessibilityNotification.Announcement» (iOS 17.0; el atributo
accessibilitySpeechAnnouncementPriority), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/accessibility/accessibilitynotification/announcement. ↩↩ -
Apple Developer Documentation, «accessibilityReduceMotion» (iOS 13.0; «If this property’s value is true, UI should avoid large animations»), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/swiftui/environmentvalues/accessibilityreducemotion. ↩↩
-
Apple Developer Documentation, «AccessibilityComponent» (RealityKit; «A component that stores accessibility information for an entity»; el nombre que «VoiceOver says aloud when it describes the entity»; iOS 17.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/realitykit/accessibilitycomponent. ↩↩↩↩
-
Apple Developer Documentation, «Improving the Accessibility of RealityKit Apps» («set the properties on each visible
Entityin your scene»), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/realitykit/improving-the-accessibility-of-realitykit-apps. ↩ -
Apple Developer Documentation, «RealityView» (iOS 18.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/realitykit/realityview. ↩
-
Apple Developer Documentation, «XCUIVoiceOverService» («Provides programmatic control of VoiceOver for UI testing»; iOS 27.0), consultado el 5 de octubre de 2026, https://developer.apple.com/documentation/xcuiautomation/xcuivoiceoverservice. ↩↩↩
-
Código de 941Kit,
Sources/Kit941/Tokens/Typography/FontFamily.swiften el commit50bc657(28 de septiembre de 2026), líneas 21 a 63 (case custom(named: String), renderizado medianteFont.custom(_:size:relativeTo:)a tamaños intrínsecos de 34, 22, 17, 13 y 12 puntos para display, title, body, label y caption), leído el 5 de octubre de 2026; repositorio privado. ↩↩ -
Código de Kiradex,
server/app/names.py(líneas 7 a 14,FIRSTSySECONDS, de 20 palabras cada una, y el patrón de alias de dos palabras con mayúscula inicial y cuatro dígitos), leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado). ↩↩ -
Blake Crosley, «A Pixel Town Alive When Nobody Is Online: NPCs and Ghosts», blakecrosley.com, 5 de octubre de 2026 (las 23 líneas predefinidas, 14 para los jugadores y 9 para los propios coleccionistas del pueblo, y una línea cada 2,0 segundos por jugador), https://blakecrosley.com/blog/pixel-art-town-alive-when-nobody-is-online. ↩↩
-
Kiradex,
docs/WORLD.md, sección 5, «The stack», líneas 524 y 525 (límites de frecuencia: «eight moves a second, a line every two seconds»), leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado). ↩↩ -
Código de Kiradex, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit
334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado):Kiradex/World/PlazaStage.swift, líneas 199 a 203 (el.gesture(DragGesture(minimumDistance: 0))del escenario, que llama atouchedmientras cambia y aliftedcuando termina), líneas 329 a 359 (touched(_:in:): sin el joystick, se camina al instante al suelo bajo el dedo y se le sigue de tile en tile, mientras que un toque en un coleccionista o en los tiles del quiosco vuelve y espera a que se levante el dedo), líneas 364 a 380 (lifted(_:in:): un toque que no caminó ni dirigió es un toque simple; sobre otro coleccionista fijatapped, sobre los tiles del quiosco llama aonKiosky, si no, ejecutarig.walk(to: tile)), líneas 31 y 32 (onKiosk, «The kiosk tapped: the town’s board.»), línea 82 (stickKey,"world.stick"), el argumento de lanzamiento de prueba-plazaFacingDemo(el.taskde las líneas 255 a 270), y eltellOnArrivaldePlazaView, que lee-plazaTell(líneas 515 a 522);KiradexUITests/KiradexUITests.swift, líneas 384 y 387, donde la prueba de caminata toca el escenario en fracciones de su marco. ↩↩↩↩ -
Código de Kiradex,
Kiradex/World/PlazaRig.swift, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado):fit(viewSize:displayScale:tilesTall:fitsWhole:)en la línea 432 (pixelScale, la parte entera de la altura en pixeles de la vista entretilesTall × TileMap.tileSize, 20 × 16 = 320, línea 439;TileMap.tileSizevale 16 en la línea 60 deTileMap.swift) yheadPoint(of:)en la línea 479 (la posición del caminante más la mitad de la altura de fotograma de la hoja, más 4, líneas 482 y 483). El archivo volvió a cambiar a las 12:42; las dos funciones seguían sin cambios entonces. ↩↩ -
Código de Kiradex, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit
334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado):Kiradex/World/PlazaStage.swift, línea 311 (.ignoresSafeArea()en el escenario, cuyoGeometryReader, líneas 121 a 294, contiene la superposición de los globos), y ninguna lectura de los márgenes del área segura en todo el archivo;Kiradex/World/WorldHUD.swift, líneas 26 y 27 (.statusBarHidden()y.persistentSystemOverlays(.hidden)enWorldView, la raíz del mundo) y líneas 40 a 42 (los controles están «over its stage and inside the safe area, which on the Duo keeps it clear of the cameras and the side rail»); yKiradex/Views/Card/CardViewer.swift, líneas 19 a 24, donde unGeometryReaderfuera del escenario de la carta pasaproxy.safeAreaInsetsaCardStage, que ignora el área segura, para que «the card rests inside the safe area, clear of the Duo’s outer camera and side rail», con los mismos dos modificadores en las líneas 56 y 57. Una búsqueda desafeAreaInsetsenKiradex/solo encontró la línea deCardViewer. ↩↩↩↩↩ -
Blake Crosley, «Xcode 27.1 Beta: Your App in the iPhone Duo Simulator», blakecrosley.com, 21 de septiembre de 2026, actualizado el 2 de octubre de 2026 (ejecutar una app en el simulador del iPhone Duo, pantallas exterior e interior; cerrado, enlazado contra el SDK 27.1, una ventana de 466 por 678 puntos cuyo contenido dentro de una pila de navegación midió 382 por 562 puntos, con márgenes del área segura de 82 arriba, 34 abajo y 84 en el lado final, el riel, en una sonda con una barra de herramientas y una barra de pestañas en ese borde y la barra de estado visible), https://blakecrosley.com/blog/xcode-27-1-beta-iphone-duo-simulator. ↩↩↩↩
-
Medición del autor, 5 de octubre de 2026:
measure_figure_width.pyen la carpeta de evidencias del autor para este artículo, salidameasure_figure_width.out, vuelto a ejecutar a las 12:36 hora del Pacífico sobre Kiradex en el commit334fbfecon las ediciones sin confirmar de ese día, con la salida sin cambios. Entradas, solo leídas de Kiradex:Kiradex/Resources/World/characters.json("cell": [32, 40], los fotogramas y las orientaciones),scripts/forge/rig.py(línea 53,CELL_W, CELL_H = 32, 40) y la hoja de cuerpofig-body.png(1.376 por 160 pixeles, 43 fotogramas por 4 orientaciones). En el fotograma de reposoidle_a, la figura mide 30 texels de alto en cada orientación, 16 de ancho en su fila más ancha mirando hacia abajo o hacia arriba, y 13 mirando a la izquierda o a la derecha. ↩↩↩ -
Medición del autor, 5 de octubre de 2026:
measure_ios27_iphones.pyen la carpeta de evidencias del autor para este artículo, salidameasure_ios27_iphones.out, vuelto a ejecutar a las 12:36 hora del Pacífico, con la salida sin cambios. Leexcrun simctl list runtimes -jpara el runtime del simulador de iOS 27.0 (24A434) instalado con Xcode 27.0 en el Mac del autor, y elcapabilities.plistde cada tipo de dispositivo iPhone (main-screen-width,main-screen-height,main-screen-scale): 33 iPhone, del iPhone 12 mini y el 13 mini (1.080 por 2.340 pixeles a 3×, 360 por 780 puntos) al iPhone 16, 17 y 18 Pro Max (440 por 956 puntos), con tres a 2×, el iPhone SE (2.ª y 3.ª generación, 375 por 667 puntos) y el iPhone 11 (414 por 896). Es la lista de dispositivos del simulador, no la página de compatibilidad de Apple, que no se consultó. También del archivo de proyecto de Kiradex en el commit334fbfe, solo leído: elTARGETED_DEVICE_FAMILY = 1(iPhone) del target de la app en sus dos configuraciones (líneas 1559 y 1705 en la lectura de las 12:28) y elIPHONEOS_DEPLOYMENT_TARGET = 27.0en las dos configuraciones del proyecto (líneas 1608 y 1670), que el target de la app no sobrescribe. ↩↩↩↩↩↩↩ -
Medición del autor, 5 de octubre de 2026:
probe_line_start_glyphs.swiften la carpeta de evidencias del autor para este artículo, compilado conswiftc -Oy ejecutado en macOS 27.0 (compilación 26A428), no en iOS, salidaprobe_line_start_glyphs.out. Lee las diez clases de inicio de línea de JLREQ 3.1.7 de las tablas del apéndice de la especificación guardada (83 entradas: cl-02 16, cl-03 4, cl-04 6, cl-05 3, cl-06 2, cl-07 2, cl-09 6, cl-10 1, cl-11 40, cl-29 3), pregunta a Core Text cuáles asigna PixelMplus10 Regular (CTFontGetGlyphsForCharacters, sin respaldo): 54, con 〜 U+301C, ゠ U+30A0 y la semirraya de cl-03, ⦆, 〙 y 〗 de cl-02, ‼ ⁇ ⁈ ⁉ de cl-04, 〻 de cl-09 y 18 kana pequeñas de cl-11 (ゕ, ゖ y U+31F0 a U+31FF) sin asignar. Dibuja los 7.223 puntos de código que asigna la fuente a 10 pixeles, con el antialiasing y el suavizado de fuentes desactivados, y agrupa las celdas idénticas pixel a pixel: de las 54, ‐ U+2010 coincide con U+2011 y : U+003A coincide con U+A789, y ninguna otra tiene gemelo. A 50 pixeles (m= 5), con el antialiasing activado y el suavizado desactivado, ー U+30FC dibuja 200 pixeles de dispositivo entintados con un gancho en su extremo izquierdo y 一 U+4E00 250, no idénticos, ambos con 0 pixeles parciales. Cada carácter ASCII imprimible avanza 5 pixeles de fuente. Ampliado más tarde el 5 de octubre, con el script y la salida anteriores guardados al lado y cada línea anterior de la salida sin cambios: los 24 caracteres del bloque Halfwidth and Fullwidth Forms, U+FF01 a U+FFEF, cuya normalización de compatibilidad (NFKC) es uno de los caracteres listados (! ) , . : ; ? ] } ⦆ 。 」 、 ・ ァ ィ ゥ ェ ォ ャ ュ ョ ッ ー), y ~ U+FF5E, añadido por el autor: la fuente asigna 24 de los 25, todos salvo ⦆ U+FF60, los de ancho completo de 10 pixeles de ancho y los de medio ancho de 5, y ninguno de los 24 tiene un gemelo idéntico pixel a pixel entre los puntos de código de la fuente, así que el conjunto de comparación es de 75 caracteres: las 54 entradas contienen 51 caracteres, ya que ), 〕 y ] están listados tanto en cl-02 como en cl-29, y las 24 formas suman 75 (la propia última línea de la sonda, 54 + 24 = 78, cuenta entradas). ↩↩↩↩ -
Medición del autor, 15 de octubre de 2026:
measure_cell_masks.pyen la carpeta de evidencias del autor para este artículo, salidameasure_cell_masks.outy la lista de resúmenescanon_cell_masks.txt, ejecutado sobre los archivos de pret guardados para este artículo (graphics/fontsde pokeemerald, 17 hojas, ygraphics/text_window, 21;gfx/framesde pokecrystal, 10; losgfx/font/font.pngde pokecrystal y pokered). Cada hoja se decodifica a RGBA; un pixel está activo donde difiere del pixel superior izquierdo de la hoja; las celdas son de 8 por 8 desde la esquina superior izquierda; las celdas vacías y sólidas se dejan fuera; el resumen de una máscara es el SHA-256 de sus 8 bytes de fila, con el pixel más a la izquierda como bit alto.japanese_normal.png, 128 por 512 pixeles: 1.024 celdas, 430 vacías, 594 conservadas, 478 distintas. Las 50 hojas: 7.746 celdas conservadas, 1.484 resúmenes distintos. ↩↩ -
Blake Crosley, «Pixel-Art People: Characters and a Creator on iPhone», blakecrosley.com, 3 de octubre de 2026, leído el 5 de octubre de 2026: para la figura de las compilaciones 21 a 33, «The cell is 32 by 32; the figure is 26 tall to the crown of the head, 27 with most hair (28 with buns, spikes or the puff), and about 14 wide at the shoulders»; en su actualización para la compilación 34, «The cell is 32 by 40 now, with eight rows of headroom and two under the feet, and the figure 30 pixels»; y los anclajes de cabeza y mano del manifiesto para el globo y la carta 3D, «though both still take their place from the cell’s height for now», https://blakecrosley.com/blog/pixel-art-characters-on-iphone. ↩↩
-
Lectura del autor del árbol de trabajo de Kiradex en el commit
fc9d4876(refs/heads/main), 15 de octubre de 2026 a las 22:29 hora del Pacífico:Kiradex/World/PlazaStage.swift(modificado a las 17:13 de ese día), línea 373 (.modifier(StageAccessibility(covered: covered, trace: stepTrace))), línea 520 (private struct StageAccessibility: ViewModifier), líneas 511 a 513 (el comentario: el escenario es un solo elemento de accesibilidad, «The plaza» con el último paso del jugador como valor, o ninguno mientras un lugar está superpuesto), línea 525 (content.accessibilityRepresentation {), línea 526 (if !covered {), línea 533 (.accessibilityLabel("The plaza")) y línea 534 (.accessibilityValue(trace)). Las demás lecturas de Kiradex del artículo son del 5 de octubre y están fechadas. ↩ -
Código de Kiradex,
server/app/npcs.py, leído a las 12:33 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfe(el archivo, con fecha del 3 de octubre; repositorio privado): los cuatro coleccionistas del pueblo deDEFINITIONS(líneas 36 a 58), Moss Keeper 1999, Prism Scout 2024, Comet Pocket 3030 y Dawn Sprout 4040, cuyas líneas son índices deLINES; cada uno dice su primera línea entre 8 y 20 segundos después (línea 77) y luego una cada 20 a 40 segundos (línea 108).server/app/main.py, línea 231, difunde la línea de un jugador a toda la sala, incluido el jugador (elexcept_iddebroadcastno está fijado;rooms.py, línea 182), leído a las 12:33. ↩↩ -
Código de Kiradex,
KiradexUITests/KiradexUITests.swift, leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado); el archivo tenía fecha de las 10:32 y no cambió durante la lectura: línea 228 (elme-handlede la pestaña Me contiene el alias, dos palabras y un número),testTheCollectorFacesTheWayItWalksa partir de la línea 432 (lee el valor del escenario para cada orientación),testThePlazaKeepsTimea partir de la línea 502 (leeplaza-statusy comprueba su prefijo, línea 509),testTheChimneysSmokea partir de la línea 523 (lanzada con-airProbe, espera elvalue CONTAINS 'smoke 18 'del escenario, línea 531),testVisitingARoomIsAVisit(líneas 469 a 472) ytestYourRoomHasYourBinders(líneas 604 a 607), que esperan las primeras palabras deroom-status,testTheShowHallHasEveryonesCards(líneas 490 a 494), que esperahall-status,testTheTownHasCollectors(líneas 672 a 676), que espera enplaza-statusun recuento de cinco o más «here», ytestThePlazaHasCompanya partir de la línea 689 (omitida salvo conKIRADEX_PLAZA=1, el servidor, y según su mensaje de omisión también necesita otro jugador, líneas 690 y 691; espera el recuento enplaza-status, elige «Hi!» en el menú Say y espera 5 segundos al globoSaid: Hi!, línea 714). ↩↩↩↩ -
Código de Kiradex,
server/requirements.txt(fastapi,uvicorn[standard],websockets,httpxypytest, ninguna biblioteca de fuentes) yserver/tests/(test_rooms.py), leído a las 12:28 hora del Pacífico el 5 de octubre de 2026, en el commit334fbfecon las ediciones sin confirmar de ese día, de un árbol de trabajo que se estaba editando ese día (repositorio privado). ↩ -
Blake Crosley, «Pixel-Art Routes: Map Connections and Districts on iPhone», blakecrosley.com, 5 de octubre de 2026, sección 7, comprobación 13 (una lista de denegación en el repositorio, con su prueba, que deben superar cada nombre de zona, cada letrero y cada cadena), https://blakecrosley.com/blog/pixel-art-world-beyond-the-plaza. ↩