pixoo-mcp-server
Control LED Divoom Pixoo
Documentación
@cyanheads/pixoo-mcp-server
Renderiza y envía pixel art, texto, paneles y animaciones con estilo a las pantallas LED Divoom Pixoo en tu red local mediante MCP. STDIO o Streamable HTTP.
Resumen
Matrices de pantalla LED Divoom Pixoo en la red local, con Pixoo-64 como objetivo principal y las de 16 y 32 también compatibles. Renderiza y envía texto con estilo, escenas en capas, paneles, animaciones y páginas HTML, o lee y cambia el estado del dispositivo. Se ejecuta como proceso stdio o como servidor local Streamable HTTP.
Herramientas
| Herramienta | Descripción |
|---|---|
pixoo_display_text | Renderiza texto con estilo, temas, degradados, sombras y ajuste automático, estático o animado, y lo envía |
pixoo_compose_scene | Compone escenas en capas de texto, iconos, widgets, formas, mapas de bits, imágenes y sprites, estáticas o animadas |
pixoo_push_image | Redimensiona una imagen local o https a la cuadrícula LED y la envía, un GIF animado o WebP como animación |
pixoo_render_html | Renderiza una página HTML (CSS, SVG, Canvas, WebGL) en un navegador sin interfaz al tamaño del panel, fija o animada fotograma a fotograma en un reloj virtual, y la envía |
pixoo_overlay_text | Establece o borra una superposición de texto desplazante renderizada por el dispositivo |
pixoo_control_device | Lee o cambia el brillo, el estado de la pantalla, el canal o la esfera del reloj |
pixoo_discover_devices | Encuentra dispositivos Pixoo y sus IPs LAN mediante el descubrimiento en la nube de Divoom |
pixoo_design_brief | Orientación experta para un tema de diseño, con estado del dispositivo en vivo y próximas llamadas prellenadas |
Recursos
| Recurso | Descripción |
|---|---|
pixoo://device/status | Instantánea del dispositivo en vivo: accesibilidad, canal, brillo, estado de la pantalla, tamaño de visualización |
pixoo://reference/themes | Registro de temas y paletas |
pixoo://reference/icons | Nombres de iconos integrados por categoría |
pixoo://reference/design-guide | Guía de creación extensa para la pantalla de 64px |
Las herramientas cubren el mismo terreno para clientes solo de herramientas: pixoo_control_device lee el estado del dispositivo en vivo, y pixoo_design_brief devuelve orientación experta, nombres de temas y nombres de iconos.
Referencia de capacidades
pixoo_display_text herramienta
textcomo cadena o como matriz de líneas;theme(midnight,ember,claude,ice,neon,forest,mono) establece el fondo y la paleta predeterminada.styletoma una rampapalette(ember,ice,neon,fire,lavender,claude,mono) o un{ from, to }personalizado, másshadow,outlineyscale1–8;positiones semántico o en píxeles, yalignalinea texto de varias líneasfont:standard(5×7) ycompact(3×5) dibujan ASCII imprimible más° ← ↑ → ↓ ▲ ▼ ♥ · …, y cualquier otro carácter (€,’, una nueva línea dentro de una cadena) como?, nombrado con su punto de código e índice de línea en la respuestanotice;numeralses una cara de dígitos 11×18 para relojes y lecturas que dibuja 0–9, espacio y: . - + / % ° ?, y el texto que contiene cualquier otro carácter falla la validación, nombrando esos caractereslayout[]informa cada decisión de ajuste como unaction(shrunk-to-compactcuando el texto cabe solo en la fuente compacta,scrollingcuando los fotogramas devueltos se desplazan,noneen caso contrario), elfontutilizado y si la caja de cada líneafitsen el panel; una sola línea demasiado ancha para el panel comienza en x 0, cortada en el borde derecho cuando no se desplaza. El texto de una sola línea retrocede de la fuente estándar a la compacta a menos quefontesté establecido — nunca anumerals— y el texto aún demasiado ancho solo se desplaza bajoeffect: "auto"o"scroll"effect:scrollhace una pasada en hasta 40 fotogramas,autose desplaza solo en desbordamiento, yfloatypulsese repiten durante 20 fotogramas;framesinforma el recuento, y la animación se envía como una animación de dispositivo
pixoo_compose_scene herramienta
- Hasta 50
elementsdibujados de atrás hacia adelante:text(en las mismas tres fuentes quepixoo_display_text),icon,rect,circle,line,progress,sparkline,bitmap,pixels,image(ruta absoluta o URL https, con el mismofinishquepixoo_push_image),sprite(ruta absoluta). Elbackgroundes un color sólido, un degradadov/h/ro untheme - Cada elemento toma
opacity(cada píxel aterriza en su propio alfa ×opacity, por lo que los bordes suaves se desvanecen uniformemente) yblend:normal,add(brillos y haces de luz),screenomultiply.liney el contornocircletomanstrokeWidthyantialias, y un borderecttomastrokeWidth, creciendo hacia adentro; cualquier campo en una forma que no dibuja trazo falla la validación, nombrándolo - Devuelve
layout[]: la caja colocada de cada elemento — para un trazo ancho o suavizado, cada píxel que dibuja — y sifitsen el panel. Los elementos se colocan como se dan y nunca se reajustan, por lo queactionsiempre esnone. Una ruta absolutaoutputguarda el primer fotograma como PNG en lugar del guardado automáticoPIXOO_OUTPUT_DIR. Fallos tipados:asset_not_found,invalid_image(una imagen o sprite que se leyó pero no decodifica),invalid_color,unknown_icon,invalid_output_path - Animación mediante presets de
effectpor elemento (float,scroll-left,scroll-right,pulse,blink,twinkle,drift,fade-in,fade-out) o fotogramas claveanimatesin procesar sobredx,dy,opacity(números o cadenas numéricas),visible(true/false) ycolor(interpolado a través de RGB en cualquier elemento con uncolor), manteniendo cada pista al menos un fotograma clave;frames1–800,speed10–2000 ms por fotograma (predeterminado 150). Más allá de 40 fotogramas, la escena se reproduce como un GIF que el dispositivo descarga de este host, conspeedredondeado a 10 ms. Un elemento tomaeffectoanimate, no ambos. Elamplitudede un efecto establece el movimiento defloat,scroll-*ydrift, y la profundidad 0–1 de la caída de opacidad depulseytwinkle
pixoo_push_image herramienta
sourcees una ruta local absoluta o una URL https, con descargas limitadas a 10 MB;fitescontain(predeterminado),coverofill, ykernelesnearest(predeterminado, para pixel art),lanczos3(fotos) omitchell- Una fuente que decodifica como GIF animado o WebP, cualquiera que sea su nombre de archivo, se envía como una animación de hasta
maxFramesfotogramas (1–800, predeterminado 40), muestreados uniformemente de una fuente más larga; más allá de 40 fotogramas se reproduce como un GIF que el dispositivo descarga de este host. Se reproduce a la duración total de la fuente sobre el recuento de fotogramas enviados (150 ms cuando la fuente no registra retrasos), o aspeed(10–2000 ms por fotograma);frames,sourceFramesyspeedinforman lo que se envió finishreduce la imagen a una paleta antes del envío: exactamente uno decolors(2–256, construido a partir de la imagen) opalette(1–256 colores hex o nombrados), másdither(none,bayer4,floyd-steinberg). Los píxeles transparentes permanecen apagados, y la paletacolorsde una animación es compartida por cada fotograma- Una ruta o URL ilegible falla como
asset_not_found, una fuente que se lee pero no decodifica (un archivo de texto, una página HTML, una descarga truncada) falla comoinvalid_image, y una entrada de paletafinishno resoluble falla comoinvalid_color; la vista previa es el fotograma exacto que recibe el dispositivo, o una cuadrícula de los fotogramas de una animación
pixoo_render_html herramienta
-
htmles un documento completo o un fragmento de cuerpo, hasta 500,000 caracteres, dispuesto en una ventana gráfica cuadrada con un píxel CSS por LED. La página es el panel:bodyno tiene margen, las barras de desplazamiento están ocultas, y una página que no pinta fondo se renderiza en negro (apagado). Su propio CSS anula cada uno -
frames1–800 (predeterminado 1),speed10–2000 ms por fotograma (predeterminado 150). Cada fotograma avanza un reloj virtual porspeed:window.render(t, frame), cuando la página lo define, se ejecuta antes de cada captura cont = frame / frames, por lo que el movimiento periódico se repite sin problemas;requestAnimationFrame,setTimeout/setInterval(piso de 4 ms para temporizadores anidados y repetidos),Date(comenzando en el tiempo real) yperformance.now()(0 en la carga) siguen el mismo reloj, y las animaciones CSS se pausan y se buscan en él, por lo que cada fotograma es determinista.requestIdleCallbacky los iframes mantienen el tiempo real. Más allá de 40 fotogramas, la página se reproduce como un GIF que el dispositivo descarga de este host, como enpixoo_compose_scene -
sampling:native(predeterminado) osupersample, que renderiza a 8× y promedia por área en cada LED, suavizando transformaciones, texto, SVG y canvas. Chromium ajusta los bordes de una caja simple a píxeles CSS completos antes de escalar, por lo que una caja enleft: 0.5pxaún aterriza en un LED; muévela contransformpara movimiento de subpíxel.finishtoma la misma reducción de paleta quepixoo_push_image, aplicada antes de la vista previa -
Nada se carga desde la red y los workers están bloqueados.
pageErrorsdevuelve los errores no capturados de la página, la salida deconsole.errory las URL bloqueadas (una navegación bloqueada comoBlocked navigation: <url>): los primeros 20, cada uno cortado a 500 caracteres. Unwindow.renderque lanza o rechaza falla comopage_error, nombrando el fotograma; sin navegador encontrado, la llamada falla comobrowser_unavailablecon pasos de instalación (ver Prerrequisitos);render_timeoutyrender_crashedcubren un renderizado más allá de 30 s y un navegador o página bloqueados.PIXOO_HTML_ENABLED=falseelimina la herramienta -
Cada página recibe un global
pixooantes de que se ejecuten sus propios scripts, para el texto de mapa de bits nítido, paletas e iconos que el suavizado del navegador mancharía a través de los LED:pixoo.context()es el contexto 2D de un canvas transparente del tamaño del panel fijado sobre la página.pixoo.text(ctx, text, x, y, { font, color, palette, scale, shadow, outline })dibuja las fuentes depixoo_display_text.pixoo.icon(ctx, name, x, y, { w, h, color, palette })dibuja un icono del registro.pixoo.palettescontiene las 7 paletas, ypixoo.sizees el tamaño del panel.
El texto y los iconos dibujados de esta manera coinciden con
pixoo_compose_scenepíxel por píxel en ambos modos de muestreo. Una paleta, icono o color desconocido lanza una excepción nombrándolo:<script> const ctx = pixoo.context(); pixoo.text(ctx, 'HELLO', 'center', 4, { palette: 'ember', scale: 2, shadow: true }); pixoo.icon(ctx, 'check-circle', 50, 50, { color: 'green' }); </script> -
pixoo_design_briefcon el temahtmlcubre bucles, el reloj, el muestreo, el runtimepixooy la legibilidad a 64 px. Un punto orbitando el panel una vez por bucle:
{
"html": "<svg viewBox=\"0 0 64 64\" style=\"display:block;width:100vw;height:100vh\"><circle id=\"dot\" r=\"6\" fill=\"#ffb000\"/></svg><script>const dot = document.getElementById('dot'); window.render = (t) => { const a = 2 * Math.PI * t; dot.setAttribute('cx', 32 + 20 * Math.cos(a)); dot.setAttribute('cy', 32 + 20 * Math.sin(a)); };</script>",
"frames": 20,
"speed": 100,
"sampling": "supersample"
}
pixoo_overlay_text herramienta
mode: "set"o"clear"en uno de los 20 espacios (id0–19).setrequieretexty toma un ID de dispositivofont(0–114),x/ydentro dePIXOO_SIZE,color,speed(0–100),direction,alignywidth- Devuelve
acknowledged,modeyid. El dispositivo renderiza la superposición, por lo que no hay vista previa, y persiste entre cambios de canal hasta que se borre
pixoo_control_device tool
- Sin parámetros, lee el estado; cualquiera de
brightness(0–100),screen(on/off),channel(faces/cloud/visualizer/custom) oclockFaceIdse aplica antes de la lectura - Devuelve
reachable,channel,brightness,screenOnyclockId(ausente cuando es inalcanzable) másapplied; un ajuste fallido se omite deappliedy se menciona en el aviso en lugar de fallar la llamada
pixoo_discover_devices tool
- Consulta el endpoint en la nube de Divoom (
app.divoom-gz.com), por lo que necesita acceso a internet;timeoutMs1000–30000 (predeterminado 5000) - Devuelve el
name,idyipde cada dispositivo; conPIXOO_IPconfigurado,configuredIpFoundindica si coincidió. Un endpoint inalcanzable falla comodiscovery_failed
pixoo_design_brief tool
topic:text,scene,dashboard,animation,pixel-art,htmlotroubleshooting; funciona sin un dispositivo alcanzable- Devuelve markdown
craftGuidance, undeviceContexten vivo,htmlRenderer(available,disabledcuandoPIXOO_HTML_ENABLED=false, ono_browser, encontrado sin lanzar un navegador),nextToolSuggestionscomo{ toolName, reason, args }con argumentos prellenados para el tema y el estado del dispositivo, másavailableThemesyiconCategories
pixoo://device/status resource
- Lectura en vivo sin caché:
reachable,channel,brightness,screenOn,clockId,displaySize,configuredIp - Devuelve
reachable: falseen lugar de un error cuando el dispositivo no se puede alcanzar oPIXOO_IPno está configurado
pixoo://reference/themes resource
- Cada tema (fondo,
textPalette,accent,shadow) y paleta (paradasfrom/to), másthemeNamesypaletteNamespara los parámetrosthemeypalette - Registro estático, en caché durante 24 h
pixoo://reference/icons resource
- El
name,categoryyviewBoxde cada icono, más una agrupación porbyCategory(clima, flechas, estado, medios); unnameva en un elemento de iconopixoo_compose_scene - Registro estático, en caché durante 24 h
pixoo://reference/design-guide resource
text/markdown: mínimos de legibilidad, disciplina de paleta, zonas de diseño, presupuesto de animación, ajustes preestablecidos de efectos, reglas de pixel art, ritmo de envío y comportamientos conocidos del dispositivo- La guía completa en un solo documento, donde
pixoo_design_briefdevuelve orientación por tema; en caché durante 24 h
Características
Construido sobre @cyanheads/mcp-ts-core: transportes stdio y Streamable HTTP, autenticación conectable (none / jwt / oauth), almacenamiento intercambiable (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), registro estructurado con rastreo opcional de OpenTelemetry.
Específico de Pixoo:
- Toda la composición ocurre en el host en un pipeline de lienzo RGBA (
@cyanheads/pixoo-toolkit); el dispositivo recibe fotogramas RGB terminados - Los envíos cambian el dispositivo al canal personalizado y se ejecutan uno a la vez, espaciados por
PIXOO_PUSH_MIN_INTERVAL_MS(predeterminado 1000) para que los envíos rápidos no congelen el dispositivo - Hasta 40 fotogramas de animación se envían en una solicitud cada uno; más envíos de fotogramas hacen que el dispositivo sea inestable. Más allá de 40,
pixoo_compose_scene,pixoo_push_imageypixoo_render_html(hasta 800 fotogramas) sirven un GIF desde un listener de un solo uso en este host, que el dispositivo descarga y repite, por lo que el dispositivo debe poder alcanzar este host.pixoo_display_textse mantiene dentro de 40
Salida amigable para agentes:
- Vista previa en cada renderizado:
pixoo_display_text,pixoo_compose_scene,pixoo_push_imageypixoo_render_htmldevuelven el fotograma como un bloque de imagen PNG ampliado 8×, enviado o no, para quepush: falseverifique un diseño sin dispositivo conectado. Las animaciones se previsualizan como una cuadrícula de sus fotogramas (cada fotograma mientras los mosaicos 1× quepan en la hoja de 512 px, una muestra uniforme más allá de eso), ya que la visualización de GIF varía entre clientes MCP; el GIF en sí se guarda enPIXOO_OUTPUT_DIRcuando está configurado: un GIF de vista previa 8×, o más allá de 40 fotogramas, el GIF del tamaño del panel que el dispositivo descarga - Transparencia de diseño:
layout[]informa cada decisión del renderizador (respaldo de fuente, desplazamiento y si cada caja cabe en el panel) para que los agentes puedan refinar un diseño - Verdad del dispositivo:
pushedrefleja el ACK del dispositivo (más allá de 40 fotogramas, el ACK de la reproducción más la solicitud del dispositivo para el GIF, con el archivo completo entregado al sistema operativo para enviar; el dispositivo no confirma la recepción), y la lectura dedeviceStatedespués de un envío viene con un aviso que nombra la corrección cuando el renderizado no será visible (pantalla apagada, brillo ≤ 10, fuera del canal personalizado) - Los renderizados sobreviven a envíos fallidos: en las cuatro herramientas de renderizado, el error tipado (
device_unreachable,device_http_error,device_rejected,gif_serve_failed,no_device_configured) llevaoutputFilesapuntando a la vista previa guardada (la copia dePIXOO_OUTPUT_DIR, o un archivo temporal cuando no está configurado)
Primeros pasos
Agrega lo siguiente a tu archivo de configuración del cliente MCP, con PIXOO_IP configurado a la dirección LAN de tu Pixoo. pixoo_discover_devices lo encuentra si no lo sabes.
{
"mcpServers": {
"pixoo-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/pixoo-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"PIXOO_IP": "192.168.1.50"
}
}
}
}
O con npx (sin necesidad de Bun):
{
"mcpServers": {
"pixoo-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/pixoo-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"PIXOO_IP": "192.168.1.50"
}
}
}
}
O con Docker:
{
"mcpServers": {
"pixoo-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"-e", "PIXOO_IP=192.168.1.50",
"-e", "PIXOO_SERVE_HOST=192.168.1.20",
"-e", "PIXOO_SERVE_PORT=8765",
"-p", "8765:8765",
"ghcr.io/cyanheads/pixoo-mcp-server:latest"
]
}
}
}
El dispositivo descarga una animación de más de 40 fotogramas desde este host, y en la red puente predeterminada de Docker, la dirección enrutada al dispositivo es la del propio contenedor, que el dispositivo no puede alcanzar. Configura PIXOO_SERVE_HOST a la dirección LAN del host de Docker y publica un PIXOO_SERVE_PORT fijo, como arriba; 40 fotogramas o menos no necesitan ninguno.
Para Streamable HTTP, configura el transporte e inicia el servidor:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 PIXOO_IP=192.168.1.50 bun run start:http
# Server listens at http://localhost:3010/mcp
Requisitos previos
- Bun v1.4.0 o superior (o Node.js v24+).
- Un Divoom Pixoo en la red local (Pixoo-64, Pixoo-32 o Pixoo-16).
- Opcional, para el renderizador HTML: chrome-headless-shell.
npx @puppeteer/browsers install chrome-headless-shell@stable --path ~/.cache/puppeteerlo instala donde el servidor lo busca por defecto. Instalado en otro lugar con--path <dir>, configuraPIXOO_BROWSER_PATHa la ruta del ejecutable que imprime la instalación. El servidor lo lanza sin cabeza, sin puerto DevTools, solo cuando un renderizado lo necesita.
Instalación
- Clona el repositorio:
git clone https://github.com/cyanheads/pixoo-mcp-server.git
- Navega al directorio:
cd pixoo-mcp-server
- Instala las dependencias:
bun install
- Configura el entorno:
cp .env.example .env
# edit .env and set PIXOO_IP
Configuración
| Variable | Descripción | Predeterminado |
|---|---|---|
PIXOO_IP | IP del dispositivo en la red local. Requerido para envíos, superposiciones y control del dispositivo; el descubrimiento, los resúmenes de diseño y los renderizados de push: false funcionan sin él. | — |
PIXOO_SIZE | Tamaño de pantalla en píxeles: 16, 32 o 64. | 64 |
PIXOO_OUTPUT_DIR | Directorio donde las herramientas de renderizado guardan archivos PNG y GIF de vista previa. Una ruta relativa se resuelve contra el directorio desde el que se lanzó el servidor, por lo que las rutas guardadas que informa son absolutas. Sin configurar, las vistas previas se devuelven solo en la respuesta. | — |
PIXOO_PUSH_MIN_INTERVAL_MS | Espacio mínimo entre envíos al dispositivo, en ms. | 1000 |
PIXOO_SERVE_HOST | Host anunciado en la URL desde la que el dispositivo descarga una animación de más de 40 fotogramas, en lugar de la dirección local a la que el sistema operativo enruta a PIXOO_IP. El listener se vincula a esa dirección enrutada de cualquier manera. Configúralo detrás de NAT o en un contenedor. | — |
PIXOO_SERVE_PORT | Puerto fijo para el listener de un solo uso de esa descarga, para reglas de firewall y publicación de puertos en contenedores. Sin configurar, un puerto libre por reproducción. | — |
PIXOO_BROWSER_PATH | Ejecutable del navegador para renderizado HTML. Cuando está configurado, es el único navegador probado: una ruta que no es un archivo ejecutable falla en lugar de recurrir a otro. Una ruta relativa se resuelve contra el directorio de lanzamiento. Sin configurar, el chrome-headless-shell más reciente en la caché de Puppeteer (~/.cache/puppeteer). La imagen de Docker no incluye navegador. | — |
PIXOO_HTML_ENABLED | Ofrecer pixoo_render_html. false lo elimina de tools/list; un valor que no sea booleano falla al inicio. | true |
MCP_TRANSPORT_TYPE | Transporte: stdio o http. | stdio |
MCP_HTTP_PORT | Puerto del servidor HTTP. | 3010 |
MCP_SESSION_MODE | Modo de sesión HTTP: stateless, stateful o auto. Un valor configurado aquí anula el stateless declarado del servidor. | stateless |
MCP_AUTH_MODE | Autenticación: none, jwt o oauth. | none |
MCP_LOG_LEVEL | Nivel de registro (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directorio para archivos de registro (solo Node.js). | <project-root>/logs |
LOG_TOOL_FAILURE_PAYLOADS | Registrar los argumentos y el resultado de cada llamada de herramienta fallida, redactados por nombre de clave y limitados a LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (predeterminado 16384). Un secreto dentro de un valor de forma libre no se redacta. | false |
OTEL_ENABLED | Habilitar OpenTelemetry. | false |
Consulta .env.example para la lista completa de anulaciones opcionales.
Ejecutar el servidor
Desarrollo local
-
Compilar y ejecutar:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http -
Ejecutar verificaciones y pruebas:
bun run devcheck # Lint, format, typecheck, security bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec # Real-browser suite for the HTML renderer (opt-in; launches the named browser) PIXOO_TEST_BROWSER_PATH=/path/to/chrome-headless-shell bun run test:browser
Docker
docker build -t pixoo-mcp-server .
docker run --rm -e PIXOO_IP=192.168.1.50 -p 3010:3010 \
-e PIXOO_SERVE_HOST=192.168.1.20 -e PIXOO_SERVE_PORT=8765 -p 8765:8765 \
pixoo-mcp-server
PIXOO_SERVE_HOST (la dirección LAN del host de Docker) y el PIXOO_SERVE_PORT publicado permiten que el dispositivo descargue animaciones de más de 40 fotogramas desde dentro del contenedor, como en la configuración stdio anterior.
El Dockerfile usa por defecto transporte HTTP, modo de sesión sin estado y registra en /var/log/pixoo-mcp-server. Las dependencias de pares de OpenTelemetry se instalan por defecto; compila con --build-arg OTEL_ENABLED=false para omitirlas.
Estructura del proyecto
| Directorio | Propósito |
|---|---|
src/index.ts | Punto de entrada de createApp(): registra herramientas y recursos e inicializa el servicio Pixoo. |
src/config/ | Análisis y validación de variables de entorno específicas del servidor con Zod. |
src/mcp-server/tools/ | Definiciones de herramientas (*.tool.ts), la ruta de envío posterior al renderizado compartida y el esquema de entrada compartido de finish. |
src/mcp-server/resources/ | Definiciones de recursos (*.resource.ts). |
src/services/pixoo/ | PixooService: envuelve @cyanheads/pixoo-toolkit con ritmo de envío, mapeo de resultados y lecturas de estado del dispositivo. |
src/services/browser/ | BrowserRenderer: renderiza HTML en un chrome-headless-shell aislado sin cabeza, controlado a través de la tubería del protocolo DevTools, y lo captura como un fotograma del panel. |
src/renderer/ | Pipeline de renderizado puro sin dependencia del dispositivo: renderizadores de elementos, motor de texto con estilo, temas, iconos, compilador de efectos, acabado de paleta, codificación de vista previa, obtención remota de imágenes y el reloj virtual inyectado en páginas HTML. |
tests/ | Pruebas unitarias y de integración que reflejan src/. |
Guía de desarrollo
Consulta CLAUDE.md/AGENTS.md para pautas de desarrollo y reglas arquitectónicas. La versión corta:
- Los handlers lanzan excepciones, el framework las captura — no hay
try/catchen la lógica de las herramientas - Usa
ctx.logpara logging con ámbito de solicitud,ctx.statepara almacenamiento con ámbito de tenant - El renderizador (
src/renderer/) es puro — sin dependencia del dispositivo, testeable sin hardware - Todas las llamadas al dispositivo pasan por
PixooService; cadaPixooResultse verifica — nunca asumas que un push tuvo éxito
Contribuciones
Las incidencias son bienvenidas. Ejecuta las comprobaciones y pruebas antes de enviar:
bun run devcheck
bun run test
Licencia
Apache-2.0 — consulta LICENSE para más detalles.