Infografía · Blupoli Journal

La web como núcleo, Android como superficie

WebProducto
CapacitorPuente
AndroidDistribución
Una lectura visual del sistema de restricciones que define este capítulo.

Cuando este artículo se publicó por primera vez, el proyecto todavía se llamaba Blupoli. Hoy el producto es Blupoli Puzzles, pero la decisión que cuenta sigue siendo una buena fotografía de cómo intentamos diseñar la arquitectura: elegir la solución menos irreversible mientras todavía estamos aprendiendo. En septiembre de 2026 ya existía una plataforma web con motores, catálogo, contenido editorial, estilos, persistencia y una cantidad significativa de decisiones de producto. Al mismo tiempo aparecía una pregunta inevitable: ¿cómo llevar esa experiencia a Android sin convertir cada mejora futura en dos proyectos paralelos?

La respuesta no era obvia porque conocemos y utilizamos Android nativo. Kotlin, Jetpack Compose y la arquitectura de aplicaciones nativas no eran territorios desconocidos. Precisamente por eso la comparación debía ir más allá del entusiasmo tecnológico. Empezar una aplicación Android desde cero habría sido perfectamente posible. También habría significado reimplementar una enorme superficie antes de saber qué problemas reales nos causaría reutilizar la web. Elegir Capacitor como primer paso fue una decisión de secuencia, no una declaración ideológica de que la web sea siempre mejor que lo nativo.

La arquitectura correcta depende del momento del producto

Dos proyectos con el mismo objetivo final pueden necesitar decisiones distintas si se encuentran en etapas diferentes. Si Blupoli Puzzles hubiera empezado como aplicación móvil, construir nativo desde el principio podría haber sido natural. Pero el activo existente era web. Los motores estaban escritos para ejecutarse en el navegador. El catálogo se generaba desde datos del repositorio. Las páginas, la navegación y el sistema editorial ya formaban parte de una cadena de build. La UI compartida estaba todavía madurando.

Reescribir en ese momento habría congelado demasiadas decisiones. Para trasladar una experiencia hay que decidir qué contrato tiene cada motor, cómo se representa el estado, qué componentes son compartidos, qué metadatos viajan y dónde termina el dominio. Hacerlo mientras todas esas fronteras todavía están evolucionando significa convertir la migración en una fuente adicional de restricciones. Cada refactor web obliga a preguntarse si hay que repetirlo en Android o mantener temporalmente dos modelos.

Por eso la pregunta dejó de ser «¿cuál es la arquitectura móvil más elegante?» y pasó a ser «¿qué opción nos permite llegar a Android sin bifurcar todavía el producto?». En ese contexto, reutilizar primero y extraer después era una estrategia más conservadora.

Una segunda implementación no duplica solo código

Hablar de una reescritura como si el coste principal fueran líneas de código subestima el problema. Dos clientes implican dos lugares donde una decisión puede divergir. El mismo puzzle puede tener un bug corregido en web y pendiente en Android. Un ajuste de dificultad puede evolucionar en un motor y quedarse congelado en otro. Un cambio de onboarding puede necesitar dos implementaciones. La accesibilidad, los temas, la persistencia y el layout pasan a tener calendarios independientes.

Incluso cuando se comparte una capa de dominio, la superficie de producto sigue siendo amplia. Hay estados vacíos, errores, navegación, ayuda, estadísticas, preferencias, actualizaciones de contenido y comportamiento responsive. Si el proyecto todavía está descubriendo cuál es la experiencia correcta, mantener dos clientes maduros puede convertir cada aprendizaje en un trabajo de sincronización.

Eso no significa que duplicar nunca tenga sentido. Significa que debería responder a una ventaja concreta. Si una implementación nativa aporta latencia, integración, accesibilidad o interacción que el contenedor web no puede ofrecer razonablemente, entonces existe una razón. «Podemos hacerlo nativo» no es, por sí sola, una razón de producto.

Kotlin Multiplatform era interesante, pero resolvía otra fase

Kotlin Multiplatform apareció naturalmente en la conversación. Compartir lógica entre clientes resulta atractivo, sobre todo cuando ya existe experiencia en Kotlin. Pero KMP no transforma de manera automática motores JavaScript y una aplicación web existente en una base común. Adoptarlo en ese momento habría exigido decidir qué lógica migrar, qué parte conservar en JavaScript, cómo convivir con dos runtimes y qué capas merecían una nueva abstracción.

Eso podía ser una buena inversión más adelante, si los límites del producto lo justificaban. No era necesariamente el mejor primer paso. La diferencia es importante: una tecnología puede ser adecuada y aun así llegar demasiado pronto. KMP ofrecía una posible arquitectura de largo plazo; Capacitor ofrecía un experimento barato para descubrir cuánto de la web era ya suficientemente bueno para funcionar como aplicación.

Posponer KMP no cerraba la puerta. Al contrario, permitía recopilar evidencia. Si más adelante una parte del dominio demostraba que debía vivir fuera del navegador, podríamos migrarla con una razón concreta y un contrato más estable.

Capacitor como frontera, no como destino obligatorio

Capacitor permite empaquetar una aplicación web en una aplicación móvil y exponer capacidades del dispositivo mediante plugins o puentes nativos. La descripción puede sonar a «meter la web en un WebView», pero el valor arquitectónico está en la frontera: el grueso del producto sigue siendo una única aplicación y las necesidades específicas del dispositivo pueden cruzar a código nativo cuando haga falta.

Para Blupoli Puzzles eso significaba una estrategia clara. Motores, catálogo, navegación, contenido y gran parte de la UI podían continuar evolucionando en un único lugar. Funciones como almacenamiento avanzado, compartir, vibración, integración con el sistema, notificaciones o cualquier API que necesitara comportamiento nativo podían vivir detrás de una interfaz. La web no necesitaba fingir que el dispositivo no existe; simplemente no tenía que reescribir todo para acceder a él.

La elección tampoco comprometía a mantener cada puzzle en JavaScript para siempre. Si un juego concreto demostraba necesitar otro enfoque por rendimiento o integración, se podía estudiar ese caso. El punto de partida era preservar opciones, no cerrar decisiones.

Diagrama sin texto donde una base web única atraviesa un puente y accede a varias capacidades del teléfono sin duplicar los motores
La arquitectura propuesta mantiene una sola base de producto y utiliza el puente nativo como frontera para capacidades concretas del dispositivo.

La decisión elevó el listón de la web móvil

Hay una consecuencia incómoda y saludable al elegir reutilización: no puedes esconder una mala experiencia web detrás de un icono de aplicación. Capacitor empaqueta lo que tienes. Si el tablero es incómodo al tacto, seguirá siéndolo. Si la navegación desperdicia media pantalla, el contenedor no lo corrige. Si los controles dependen de hover o de un ratón preciso, Android hará más evidente el problema.

Eso convirtió la estrategia móvil en presión positiva sobre la web. Responsive, tamaño de objetivos táctiles, jerarquía, persistencia, rendimiento y comportamiento sin conexión dejaron de ser «mejoras para usuarios móviles» y pasaron a ser requisitos de cualquier futura app. El trabajo que se hiciera para Android beneficiaría primero a la web móvil.

La relación con el sistema de UI compartido es directa. Un shell capaz de adaptarse a pantallas pequeñas, reorganizar controles y mantener estados coherentes reduce el coste de cualquier contenedor posterior. La mejor preparación para una app no era crear otro cliente; era hacer que el cliente existente mereciera ser reutilizado.

El tacto cambia detalles que el escritorio perdona

Una interfaz que funciona con ratón puede resultar torpe con el pulgar. El puntero permite precisión milimétrica y hover; la mano tapa parte de la pantalla, necesita objetivos más grandes y puede provocar scroll accidental. Un gesto que parece obvio en escritorio puede competir con la navegación del sistema o con el desplazamiento de la página.

Los puzzles amplifican este problema porque la superficie interactiva suele ser densa. Una cuadrícula grande no puede aumentar cada celda indefinidamente. La solución depende de la mecánica: zoom, desplazamiento controlado, orientación, gestos, modos de entrada, barras cercanas o cambios de layout. No existe un ajuste universal.

Capacitor no elimina ese trabajo, y eso es importante admitirlo. La reutilización de código no equivale a reutilización automática de ergonomía. La ventaja es que esas mejoras siguen ocurriendo en el producto principal y no en una rama móvil separada.

Offline y persistencia cambian la expectativa de una aplicación instalada

Una página web puede apoyarse en la idea de conectividad con más facilidad. Una aplicación instalada crea una expectativa distinta: abrir rápido, conservar la sesión y seguir siendo útil cuando la red no está disponible. Para un producto de puzzles, buena parte de la lógica puede ejecutarse localmente, así que esa expectativa es razonable y debe formar parte del diseño.

La estrategia basada en web obliga a revisar qué assets necesita cada juego, cómo se cachean, qué datos se guardan, cómo se versiona una sesión y qué ocurre después de una actualización. El almacenamiento del navegador puede ser suficiente para unas cosas y no para otras. Capacitor permite complementar esas capacidades, pero necesitamos mantener un modelo claro para no terminar con estado duplicado en varias capas.

De nuevo aparece la misma idea: usar el puente donde aporta valor y no como excusa para mover responsabilidades sin necesidad. La persistencia de un puzzle pertenece al producto; el mecanismo físico de almacenamiento puede variar según el entorno.

El rendimiento debía medirse antes de reescribirlo

«Nativo será más rápido» puede ser cierto en determinadas tareas y demasiado genérico como criterio arquitectónico. Los puzzles del catálogo tienen perfiles muy diferentes. Muchos tableros dependen más de algoritmos de generación o solving que del renderizado. Otros son ligeros y pasan la mayor parte del tiempo esperando interacción humana. Antes de trasladar lógica, conviene saber dónde está realmente el cuello de botella.

El navegador moderno puede ejecutar bastante trabajo, pero también tiene límites. Un generador pesado puede bloquear la UI si está mal diseñado. Un canvas o DOM grande puede necesitar optimización. La respuesta correcta puede ser un Web Worker, un algoritmo mejor, un límite de generación, una implementación distinta o, en algún caso, código nativo. Lo importante es que la decisión se base en medición.

Esta filosofía ya existía en la arquitectura de motores. Como explicamos en el artículo sobre motores de puzzle, no intentamos utilizar un único algoritmo para todo. Tampoco necesitamos una única respuesta tecnológica para todos los problemas de rendimiento.

Una app móvil no debe convertirse en una excusa para duplicar marca y contenido

El producto no es solo el tablero. Hay nombres, descripciones, categorías, ayudas, artículos enlazados, onboarding, textos de interfaz y metadatos. Si la app nativa mantiene copias manuales, cada cambio editorial puede divergir. Eso multiplica problemas de internacionalización y vuelve mucho más difícil saber cuál es la fuente de verdad.

Preservar una base web única facilita que el mismo catálogo y el mismo contenido estructurado alimenten distintas superficies. Si en el futuro existe una UI nativa más profunda, debería consumir contratos y datos estables, no empezar con archivos duplicados. La decisión de Capacitor ayudaba a posponer esa duplicación hasta que tuviéramos mejores fronteras.

Esto resulta todavía más importante con varios idiomas. Una nueva cadena no debería necesitar aparecer en dos clientes y seis localizaciones por caminos distintos. La arquitectura móvil debe respetar la arquitectura de contenido, no crear un sistema paralelo.

El puente nativo tiene que ser pequeño y deliberado

Un riesgo de cualquier arquitectura híbrida es convertir el puente en un cajón de sastre. Cada vez que algo parece incómodo en web, se crea un plugin. Pronto la aplicación depende de decenas de APIs personalizadas y la ventaja de reutilización desaparece. Para evitarlo necesitamos criterios claros sobre qué merece cruzar la frontera.

Una capacidad es buena candidata cuando depende genuinamente del dispositivo, mejora de manera clara la experiencia y puede aislarse detrás de una interfaz estable. Compartir contenido con otras aplicaciones, controlar una respuesta háptica o acceder a una integración del sistema son ejemplos razonables. Mover un generador simplemente porque «Android es nativo» requiere una justificación mucho mayor.

La disciplina del puente también facilita pruebas. Una capa pequeña puede tener mocks para web y adaptadores para Android. Una capa enorme termina mezclando dominio, UI y sistema operativo.

La publicación en tiendas añade obligaciones que la web no tiene

Llevar un producto a Android no termina al generar un APK. Hay ciclo de releases, versiones, políticas, permisos, tamaño, comportamiento de back, estados de la aplicación, iconos, privacidad y expectativas de actualización. Elegir Capacitor reduce la duplicación del producto, pero no elimina el trabajo de plataforma.

Esta distinción evita promesas irreales. El objetivo no era «convertir la web en app en una tarde». Era construir un camino donde el coste adicional se concentrara en aquello que realmente pertenece a Android. Cuanto más madura fuera la base web, más pequeño podía ser ese delta.

También nos permitía avanzar por etapas: empaquetar, probar en dispositivos reales, medir problemas táctiles y de rendimiento, resolver integración, y solo después decidir si alguna parte merecía una arquitectura diferente.

La reversibilidad fue un criterio de diseño

Las decisiones arquitectónicas más peligrosas durante una fase de aprendizaje son las que obligan a pagar todo el coste antes de obtener información. Una reescritura total podía ser excelente y aun así impedirnos saber si era necesaria. Un contenedor híbrido ofrecía una prueba más reversible: si funcionaba, habríamos evitado duplicación; si fallaba en áreas concretas, esas áreas se convertirían en candidatos claros para otra solución.

La reversibilidad no significa falta de compromiso. Significa diseñar experimentos que produzcan información. Podemos comprometernos con una experiencia Android y, al mismo tiempo, evitar decidir por anticipado que todos los motores deben migrar. Esa separación entre objetivo de producto y elección de implementación es útil en muchos contextos.

El monorepo hace más clara la idea de productos separados con código compartido

Con la evolución hacia Blupoli, el proyecto se organiza como un monorepo donde la web principal, Puzzles y futuros productos pueden vivir como aplicaciones separadas mientras comparten paquetes y convenciones. Esa arquitectura encaja con la filosofía que motivó Capacitor: evitar una gran aplicación monolítica, pero tampoco copiar capacidades a mano.

Una futura app Android puede tener su propia superficie y su propio ciclo sin obligar a duplicar motores o datos innecesariamente. Capacitor es una opción dentro de esa estructura, no el centro de toda la arquitectura. El principio que permanece es más general: compartir aquello que realmente es compartido y mantener las fronteras de producto suficientemente claras para cambiar de implementación.

La auditoría de la web debía ocurrir antes de exigirle otra plataforma

En paralelo a la decisión móvil, estábamos empezando una auditoría de UX, UI, rendimiento y arquitectura. Eso era importante porque empaquetar una base inconsistente solo distribuye la inconsistencia. Antes de sumar otra superficie pública, necesitábamos reforzar el producto que ya existía.

El razonamiento está desarrollado en «Parar de añadir para auditar lo que ya habíamos construido». Responsive, temas, controles, catálogo, onboarding y deuda visual no son tareas independientes de Android. Son la base sobre la que cualquier cliente móvil debería apoyarse.

Este orden nos obliga a mejorar por las razones correctas. No optimizamos el táctil únicamente para cumplir una checklist de tienda. Lo mejoramos porque el producto web ya lo necesita. Android se beneficia como consecuencia.

Elegir Capacitor no fue elegir entre web y nativo

La comparación «web versus nativo» resulta demasiado binaria para una arquitectura híbrida. Podemos tener una interfaz web y servicios nativos. Podemos conservar motores JavaScript y añadir una integración específica. Podemos mover una parte del dominio en el futuro sin reescribir la navegación. Podemos incluso terminar construyendo una UI nativa distinta si la evidencia lo justifica.

La decisión real fue evitar una frontera demasiado grande demasiado pronto. Cuanto más pequeña es la capa específica de plataforma, más fácil es mantener coherencia y más evidente resulta cuándo esa capa necesita crecer. Eso permite que la arquitectura responda a problemas observados, no a una idea previa de pureza.

La mejor reescritura es la que puedes justificar con evidencia

Las reescrituras tienen una seducción especial porque prometen eliminar deuda de una vez. También suelen borrar conocimiento incorporado en pequeños detalles que solo se descubren al usar el producto. En Blupoli Puzzles, la web contiene años concentrados de decisiones aunque el proyecto sea joven: cómo responde un tablero, qué metadatos espera el catálogo, cómo se enlazan artículos, cómo se guarda una sesión, qué ocurre al cambiar tema.

Recrear todo eso puede ser correcto, pero merece una causa clara. Si una futura arquitectura móvil demuestra que mejora algo fundamental y el coste de mantener el híbrido supera el de migrar, tendremos una razón real. Hasta entonces, el objetivo es aprender barato.

Ese es el sentido de «Capacitor primero». No significa «Capacitor para siempre». Significa que la primera versión móvil debe conservar el máximo de producto, exponer los límites reales y permitir que la segunda decisión sea mejor que la primera porque estará basada en comportamiento, no en suposiciones.

Una estrategia móvil útil mejora el producto incluso antes de existir la app

La consecuencia más valiosa de esta decisión quizá sea que obligó a mirar la web con ojos de aplicación. ¿Abrimos rápido? ¿Guardamos estado? ¿Los controles táctiles funcionan? ¿El layout sobrevive a una pantalla estrecha? ¿La navegación se siente coherente? ¿Podemos trabajar sin red? ¿Las capacidades del dispositivo tienen fronteras claras?

Responder esas preguntas mejora Blupoli Puzzles aunque la persona nunca instale nada. Esa es una señal de una decisión arquitectónica saludable: crea trabajo que sigue teniendo valor si el plan de plataforma cambia.

En 2026 no necesitábamos adivinar el cliente perfecto para los próximos años. Necesitábamos una forma de llevar el producto existente a Android sin dividir prematuramente el equipo, el código y la experiencia. Capacitor ofrecía ese puente. Lo importante no era el nombre de la herramienta. Era conservar una idea que sigue guiando Blupoli: reutilizar primero, medir los límites y reescribir solo aquello que podamos explicar por qué merece ser diferente.