Quería construir aplicaciones de escritorio con HTML y JavaScript, pero con ventanas de verdad: posición exacta, transparencia, multi-monitor, always-on-top. Ningún envoltorio me daba ese control, así que compilé el mío. OnFramer es un Chromium a medida con un puente JavaScript: tu web manda sobre la ventana como si fuera nativa.
Productos
C++, CEF, JavaScript, HTML/CSS, CMake, WebSocket, PHP, Docker
Hacer una app de escritorio con tecnología web es fácil; hacerla comportarse como una app de verdad, no. Los envoltorios habituales te dan una ventana genérica, pero cuando necesitas colocar ventanas en monitores concretos, hacerlas transparentes, fijarlas always-on-top o gobernarlas a distancia, te das contra el techo del framework.
Mi caso de uso era exactamente ese: pantallas múltiples, ventanas posicionadas al píxel, contenido web. El techo llegó pronto.
Bajar un nivel: compilar un Chromium propio (sobre CEF, el Chromium empotrable) y exponer la gestión nativa de ventanas a JavaScript mediante un puente. La web deja de estar "dentro de" una ventana y pasa a mandar sobre la ventana:
// El SDK envuelve el puente en una API de promesas
await OnFramer.setPosition(left, top, width, height);
await OnFramer.alwaysOnTop();
const monitors = await OnFramer.monitorInfo(); // cuántas pantallas, tamaños, DPI
Por debajo, cada llamada viaja por window.cefQuery() hasta el C++ del navegador, que ejecuta la orden nativa y responde JSON. Del lado web solo se ven promesas.
El protocolo es deliberadamente simple: cada orden es un mensaje con nombre y parámetros que el C++ resuelve y contesta:
"Window.Position:100,50,1280,720" → el navegador mueve la ventana y responde JSON
El catálogo cubre lo que una app de verdad necesita: posición, maximizar/minimizar/restaurar, pantalla completa, always-on-top, silenciar audio, información de monitores… Y como todo pasa por un único canal con nombre + parámetros, añadir una orden nueva es tocar dos sitios: su handler en C++ y su método en el SDK.
El catálogo de superpoderes, todos desde JavaScript:
La pieza que más uso: posicionar ventanas en cuadrículas de varias pantallas desde la propia URL. Sin código: la URL declara dónde vive esa ventana:
app.html?ofpos=2x3_1-2-3-1
→ cuadrícula de 2×3, pantalla 1, columna 2, fila 3, adaptando tamaño
Para paneles de control, señalización o puestos con varios monitores, esto convierte un despliegue de ventanas en una lista de URLs.
Las mismas órdenes del puente pueden llegar por WebSocket: un relay en la nube conecta un panel de control con las aplicaciones desplegadas, estén donde estén. Reorganizar las pantallas de un local (o de veinte locales) sin levantarse de la silla:
// Desde el panel: mueve la ventana del puesto 3 a la pantalla 2
relay.send("puesto-3", { cmd: "Position", args: [0, 0, 1920, 1080], screen: 2 });
Es la pieza que convierte OnFramer en plataforma: no solo abres ventanas: las gobiernas en flota.
Con los años, el navegador se rodeó de su pequeño ecosistema: un SDK JavaScript servido por CDN, un gestor de plugins (proxy, WebSocket…), un servidor PHP portable para que todo corra desde una carpeta en Windows sin instalar nada, y un lanzador silencioso que lo arranca todo en segundo plano.
La pieza más reciente: una cadena de build bajo demanda. Un orquestador siempre encendido recibe la especificación de una edición (icono, ajustes, plugins del catálogo) y decide el camino barato o el caro:
{
"name": "edicion-cliente",
"icon": "cliente.ico",
"settings": { "kiosk": true, "startUrl": "https://panel.cliente.com" },
"plugins": ["websocket", "proxy"]
}
Pedir una edición a medida es mandar ese JSON. La máquina de compilar solo gasta luz cuando compila.
Sin cadena de build, sin código nativo. Una línea de PowerShell instala el CLI y el Manager:
iwr -useb https://onframer.io/installer | iex
Después: apunta OnFramer a cualquier URL o HTML local, carga el SDK y llama a OnFramer.*. De página web a app de escritorio en tres pasos.
Una app OnFramer es solo una página web con una API de superpoderes de escritorio, justo lo que un agente de código sabe manejar. El starter incluye CLAUDE.md y AGENTS.md: dos ficheros de instrucciones que enseñan al agente toda la API, los flags de arranque y sus trampas. Le pides la app a Claude Code, Cursor o el CLI que uses, y el agente ya sabe conducir window.OnFramer, sin prompting desde cero.
Donde el patrón encaja: señalización digital (pantallas de local gobernadas a distancia), kioskos y puestos de autoservicio, paneles de control con cuadrículas de ventanas sobre varios monitores, puestos de trabajo donde una web tiene que comportarse como programa (arrancar sola, a pantalla completa, sin barra del navegador) y overlays de ayuda: tutoriales o asistentes flotando sobre otra aplicación gracias al click-through.
Compilar Chromium impone respeto: decenas de gigas de código, horas de máquina y una cadena de build que se rompe con mirarla. La primera compilación buena costó más que muchas features enteras. ¿Compensó? Sí, porque todo lo que vino después (transparencias, multi-monitor, control remoto) era imposible sin ser dueño del navegador. A veces el atajo es no coger el atajo.
Un framework de escritorio propio, en producción, con su web en onframer.io, su documentación y sus ejemplos en vivo, y la base de varios despliegues reales con pantallas múltiples. De todos mis proyectos, el que mejor responde a la pregunta "¿y tú qué sabes hacer?": desde el C++ del navegador hasta el HTML de la ventana.