pixoo-mcp-server

Controle de LED Divoom Pixoo

Documentação

@cyanheads/pixoo-mcp-server

Renderize e envie pixel art estilizada, texto, painéis e animações para displays LED Divoom Pixoo na sua rede local via MCP. STDIO ou Streamable HTTP.

8 Ferramentas • 4 Recursos

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Visão geral

Displays LED matriciais Divoom Pixoo na rede local, com o Pixoo-64 como alvo principal e os modelos 16 e 32 também suportados. Renderize e envie texto estilizado, cenas em camadas, painéis, animações e páginas HTML, ou leia e altere o estado do dispositivo. Funciona como um processo stdio ou um servidor Streamable HTTP local.

Ferramentas

FerramentaDescrição
pixoo_display_textRenderiza texto estilizado com temas, gradientes, sombras e ajuste automático, estático ou animado, e o envia
pixoo_compose_sceneCompõe cenas em camadas de texto, ícones, widgets, formas, bitmaps, imagens e sprites, estáticas ou animadas
pixoo_push_imageRedimensiona uma imagem local ou https para a grade de LEDs e a envia, ou um GIF animado ou WebP como animação
pixoo_render_htmlRenderiza uma página HTML (CSS, SVG, Canvas, WebGL) em um navegador headless no tamanho do painel, estática ou animada quadro a quadro em um relógio virtual, e a envia
pixoo_overlay_textDefine ou limpa uma sobreposição de texto rolante renderizada pelo dispositivo
pixoo_control_deviceLê ou altera brilho, estado da tela, canal ou face do relógio
pixoo_discover_devicesEncontra dispositivos Pixoo e seus IPs de LAN através da descoberta em nuvem da Divoom
pixoo_design_briefOrientação de criação para um tópico de design, com estado do dispositivo ao vivo e próximas chamadas pré-preenchidas

Recursos

RecursoDescrição
pixoo://device/statusInstantâneo do dispositivo ao vivo: acessibilidade, canal, brilho, estado da tela, tamanho do display
pixoo://reference/themesRegistro de temas e paletas
pixoo://reference/iconsNomes de ícones integrados por categoria
pixoo://reference/design-guideGuia de criação detalhado para o display de 64px

As ferramentas cobrem o mesmo terreno para clientes somente-ferramenta: pixoo_control_device lê o estado do dispositivo ao vivo, e pixoo_design_brief retorna orientação de criação, nomes de temas e nomes de ícones.

Referência de capacidades

pixoo_display_text ferramenta

  • text como uma string ou um array de linhas; theme (midnight, ember, claude, ice, neon, forest, mono) define o fundo e a paleta padrão. style aceita um gradiente palette (ember, ice, neon, fire, lavender, claude, mono) ou um { from, to } personalizado, além de shadow, outline e scale 1–8; position é semântico ou em pixels, e align alinha texto de múltiplas linhas
  • font: standard (5×7) e compact (3×5) desenham ASCII imprimível mais ° ← ↑ → ↓ ▲ ▼ ♥ · …, e qualquer outro caractere (€, ’, uma nova linha dentro de uma string) como ?, nomeado com seu ponto de código e índice de linha na resposta notice; numerals é uma face de dígitos 11×18 para relógios e leituras que desenha 0–9, espaço e : . - + / % ° ?, e texto contendo qualquer outro caractere falha na validação, nomeando esses caracteres
  • layout[] relata cada decisão de ajuste como um action (shrunk-to-compact quando o texto cabe apenas na fonte compacta, scrolling quando os quadros retornados rolam, none caso contrário), o font usado e se a caixa de cada linha fits no painel; uma única linha larga demais para o painel começa em x 0, cortada na borda direita quando não rola. Texto de linha única cai da fonte padrão para a compacta, a menos que font esteja definido — nunca para numerals — e texto ainda largo demais só rola sob effect: "auto" ou "scroll"
  • effect: scroll faz uma passagem em até 40 quadros, auto rola apenas em estouro, e float e pulse fazem loop em 20 quadros; frames relata a contagem, e a animação é enviada como uma animação de dispositivo

pixoo_compose_scene ferramenta

  • Até 50 elements desenhados de trás para frente: text (nas mesmas três fontes que pixoo_display_text), icon, rect, circle, line, progress, sparkline, bitmap, pixels, image (caminho absoluto ou URL https, com o mesmo finish que pixoo_push_image), sprite (caminho absoluto). O background é uma cor sólida, um gradiente v / h / r ou um theme
  • Cada elemento aceita opacity (cada pixel cai em seu próprio alfa × opacity, então bordas suaves desvanecem uniformemente) e blend: normal, add (brilhos e feixes de luz), screen ou multiply. line e contorno circle aceitam strokeWidth e antialias, e uma borda rect aceita strokeWidth, crescendo para dentro; qualquer campo em uma forma que não desenha traço falha na validação, nomeando-o
  • Retorna layout[]: a caixa posicionada de cada elemento — para um traço largo ou anti-aliased, cada pixel que ele desenha — e se ele fits no painel. Os elementos são posicionados como fornecidos e nunca reajustados, então action é sempre none. Um caminho absoluto output salva o primeiro quadro como PNG no lugar do salvamento automático PIXOO_OUTPUT_DIR. Falhas tipadas: asset_not_found, invalid_image (uma imagem ou sprite que foi lido mas não decodifica), invalid_color, unknown_icon, invalid_output_path
  • Animação através de predefinições effect por elemento (float, scroll-left, scroll-right, pulse, blink, twinkle, drift, fade-in, fade-out) ou keyframes animate brutos ao longo de dx, dy, opacity (números ou strings numéricas), visible (true/false) e color (interpolado através de RGB em qualquer elemento com um color), cada trilha contendo pelo menos um keyframe; frames 1–800, speed 10–2000 ms por quadro (padrão 150). Acima de 40 quadros, a cena é reproduzida como um GIF que o dispositivo baixa deste host, com speed arredondado para 10 ms. Um elemento aceita effect ou animate, não ambos. O amplitude de um efeito define o movimento de float, scroll-* e drift, e a profundidade 0–1 do mergulho de opacidade pulse e twinkle

pixoo_push_image ferramenta

  • source é um caminho local absoluto ou uma URL https, com downloads limitados a 10 MB; fit é contain (padrão), cover ou fill, e kernel é nearest (padrão, para pixel art), lanczos3 (fotos) ou mitchell
  • Uma fonte que decodifica como GIF animado ou WebP, qualquer que seja seu nome de arquivo, é enviada como uma animação de até maxFrames quadros (1–800, padrão 40), amostrados uniformemente de uma fonte mais longa; acima de 40 quadros, é reproduzida como um GIF que o dispositivo baixa deste host. É reproduzida na duração total da fonte sobre a contagem de quadros enviada (150 ms quando a fonte não registra atrasos), ou em speed (10–2000 ms por quadro); frames, sourceFrames e speed relatam o que foi enviado
  • finish reduz a imagem a uma paleta antes do envio: exatamente um de colors (2–256, construído a partir da imagem) ou palette (1–256 cores hex ou nomeadas), mais dither (none, bayer4, floyd-steinberg). Pixels transparentes permanecem apagados, e a paleta colors de uma animação é compartilhada por cada quadro
  • Um caminho ou URL ilegível falha como asset_not_found, uma fonte que é lida mas não decodifica (um arquivo de texto, uma página HTML, um download truncado) falha como invalid_image, e uma entrada de paleta finish não resolvível falha como invalid_color; a pré-visualização é o quadro exato que o dispositivo recebe, ou uma grade dos quadros de uma animação

pixoo_render_html ferramenta

  • html é um documento completo ou um fragmento de corpo, até 500.000 caracteres, disposto em um viewport quadrado com um pixel CSS por LED. A página é o painel: body não tem margem, barras de rolagem são ocultas, e uma página que não pinta fundo renderiza em preto (apagado). Seu próprio CSS substitui cada um

  • frames 1–800 (padrão 1), speed 10–2000 ms por quadro (padrão 150). Cada quadro avança um relógio virtual em speed: window.render(t, frame), quando a página o define, executa antes de cada captura com t = frame / frames, então movimento periódico faz loop perfeitamente; requestAnimationFrame, setTimeout / setInterval (piso de 4 ms para timers aninhados e repetidos), Date (começando no tempo real) e performance.now() (0 no carregamento) seguem o mesmo relógio, e animações CSS são pausadas e buscadas nele, então cada quadro é determinístico. requestIdleCallback e iframes mantêm o tempo real. Acima de 40 quadros, a página é reproduzida como um GIF que o dispositivo baixa deste host, como em pixoo_compose_scene

  • sampling: native (padrão) ou supersample, que renderiza em 8× e faz média de área em cada LED, suavizando transformações, texto, SVG e canvas. Chromium ajusta as bordas de uma caixa simples a pixels CSS inteiros antes de escalar, então uma caixa em left: 0.5px ainda cai em um LED; mova-a com transform para movimento sub-pixel. finish aceita a mesma redução de paleta que pixoo_push_image, aplicada antes da pré-visualização

  • Nada é carregado da rede e workers são bloqueados. pageErrors retorna os erros não capturados da página, saída console.error e URLs bloqueadas (uma navegação bloqueada como Blocked navigation: <url>): os primeiros 20, cada um cortado em 500 caracteres. Um window.render que lança ou rejeita falha como page_error, nomeando o quadro; sem navegador encontrado, a chamada falha como browser_unavailable com etapas de instalação (veja Pré-requisitos); render_timeout e render_crashed cobrem uma renderização acima de 30 s e um navegador ou página travados. PIXOO_HTML_ENABLED=false remove a ferramenta

  • Cada página recebe um global pixoo antes de seus próprios scripts executarem, para o texto bitmap nítido, paletas e ícones que o anti-aliasing do navegador borraria nos LEDs:

    • pixoo.context() é o contexto 2D de um canvas transparente do tamanho do painel fixado sobre a página.
    • pixoo.text(ctx, text, x, y, { font, color, palette, scale, shadow, outline }) desenha as fontes de pixoo_display_text.
    • pixoo.icon(ctx, name, x, y, { w, h, color, palette }) desenha um ícone do registro.
    • pixoo.palettes contém as 7 paletas, e pixoo.size é o tamanho do painel.

    Texto e ícones desenhados desta forma correspondem a pixoo_compose_scene pixel por pixel em ambos os modos de amostragem. Uma paleta, ícone ou cor desconhecida lança erro nomeando-o:

    <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_brief com tópico html cobre loops, o relógio, amostragem, o runtime pixoo e legibilidade a 64 px. Um ponto orbitando o painel uma vez por loop:

{
  "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 ferramenta

  • mode: "set" ou "clear" em um dos 20 slots (id 0–19). set exige text e recebe um ID de font do dispositivo (0–114), x / y dentro de PIXOO_SIZE, color, speed (0–100), direction, align e width
  • Retorna acknowledged, mode e id. O dispositivo renderiza a sobreposição, portanto não há pré-visualização, e ela persiste entre trocas de canal até ser limpa

pixoo_control_device tool

  • Sem parâmetros, lê o estado; qualquer um de brightness (0–100), screen (on / off), channel (faces / cloud / visualizer / custom) ou clockFaceId é aplicado antes da leitura de retorno
  • Retorna reachable, channel, brightness, screenOn e clockId (ausente quando inacessível) além de applied; uma configuração com falha é omitida de applied e nomeada no aviso em vez de falhar a chamada

pixoo_discover_devices tool

  • Consulta o endpoint de nuvem da Divoom (app.divoom-gz.com), então precisa de acesso à internet; timeoutMs 1000–30000 (padrão 5000)
  • Retorna o name, id e ip de cada dispositivo; com PIXOO_IP definido, configuredIpFound indica se houve correspondência. Um endpoint inacessível falha como discovery_failed

pixoo_design_brief tool

  • topic: text, scene, dashboard, animation, pixel-art, html ou troubleshooting; funciona sem um dispositivo acessível
  • Retorna markdown craftGuidance, um deviceContext ao vivo, htmlRenderer (available, disabled quando PIXOO_HTML_ENABLED=false, ou no_browser, encontrado sem abrir um navegador), nextToolSuggestions como { toolName, reason, args } com argumentos pré-preenchidos para o tópico e o estado do dispositivo, além de availableThemes e iconCategories

pixoo://device/status resource

  • Leitura ao vivo sem cache: reachable, channel, brightness, screenOn, clockId, displaySize, configuredIp
  • Retorna reachable: false em vez de um erro quando o dispositivo não pode ser alcançado ou PIXOO_IP não está definido

pixoo://reference/themes resource

  • Cada tema (fundo, textPalette, accent, shadow) e paleta (paradas de from / to), além de themeNames e paletteNames para os parâmetros theme e palette
  • Registro estático, em cache por 24h

pixoo://reference/icons resource

  • O name, category e viewBox de cada ícone, além de um agrupamento por byCategory (clima, setas, status, mídia); um name vai em um elemento de ícone pixoo_compose_scene
  • Registro estático, em cache por 24h

pixoo://reference/design-guide resource

  • text/markdown: pisos de legibilidade, disciplina de paleta, zonas de layout, orçamento de animação, predefinições de efeito, regras de pixel art, ritmo de envio e comportamentos conhecidos do dispositivo
  • O guia completo em um único documento, onde pixoo_design_brief retorna orientação por tópico; em cache por 24h

Recursos

Construído sobre @cyanheads/mcp-ts-core: transportes stdio e Streamable HTTP, autenticação plugável (none / jwt / oauth), armazenamento substituível (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), registro estruturado com rastreamento OpenTelemetry opcional.

Específico do Pixoo:

  • Toda a composição acontece no host em um pipeline de canvas RGBA (@cyanheads/pixoo-toolkit); o dispositivo recebe quadros RGB finalizados
  • Os envios alternam o dispositivo para o canal personalizado e são executados um por vez, espaçados por PIXOO_PUSH_MIN_INTERVAL_MS (padrão 1000) para que envios rápidos não congelem o dispositivo
  • Até 40 quadros de animação são enviados em uma solicitação cada; mais envios de quadros tornam o dispositivo instável. Acima de 40, pixoo_compose_scene, pixoo_push_image e pixoo_render_html (até 800 quadros) servem um GIF a partir de um listener de uso único neste host, que o dispositivo baixa e repete, então o dispositivo precisa conseguir alcançar este host. pixoo_display_text permanece dentro de 40

Saída amigável para agentes:

  • Pré-visualização em cada renderização: pixoo_display_text, pixoo_compose_scene, pixoo_push_image e pixoo_render_html retornam o quadro como um bloco de imagem PNG ampliado 8×, enviado ou não, para que push: false verifique um design sem dispositivo conectado. Animações são pré-visualizadas como uma grade de seus quadros (todos os quadros enquanto tiles 1× couberem na folha de 512 px, uma amostra uniforme além disso), já que a exibição de GIF varia entre clientes MCP; o próprio GIF é salvo em PIXOO_OUTPUT_DIR quando definido — um GIF de pré-visualização 8×, ou acima de 40 quadros o GIF do tamanho do painel que o dispositivo baixa
  • Transparência de layout: layout[] relata cada decisão do renderizador (fallback de fonte, rolagem e se cada caixa cabe no painel) para que agentes possam refinar um design
  • Verdade do dispositivo: pushed reflete o ACK do dispositivo (acima de 40 quadros, o ACK da reprodução mais a solicitação do dispositivo pelo GIF, com o arquivo inteiro entregue ao SO para envio; o dispositivo não confirma o recebimento), e a leitura de deviceState após um envio vem com um aviso nomeando a correção quando a renderização não ficará visível (tela desligada, brilho ≤ 10, fora do canal personalizado)
  • Renderizações sobrevivem a envios com falha: em todas as quatro ferramentas de renderização, o erro tipado (device_unreachable, device_http_error, device_rejected, gif_serve_failed, no_device_configured) carrega outputFiles apontando para a pré-visualização salva (a cópia de PIXOO_OUTPUT_DIR, ou um arquivo temporário quando isso não está definido)

Primeiros passos

Adicione o seguinte ao arquivo de configuração do seu cliente MCP, com PIXOO_IP definido para o endereço LAN do seu Pixoo. pixoo_discover_devices o encontra se você não souber.

{
  "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"
      }
    }
  }
}

Ou com npx (sem necessidade 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"
      }
    }
  }
}

Ou com 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"
      ]
    }
  }
}

O dispositivo baixa uma animação de mais de 40 quadros deste host, e na rede bridge padrão do Docker o endereço roteado para o dispositivo é o do próprio contêiner, que o dispositivo não consegue alcançar. Defina PIXOO_SERVE_HOST para o endereço LAN do host Docker e publique uma PIXOO_SERVE_PORT fixa, como acima; 40 quadros ou menos não precisam de nenhum dos dois.

Para Streamable HTTP, defina o transporte e inicie o 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

Pré-requisitos

  • Bun v1.4.0 ou superior (ou Node.js v24+).
  • Um Divoom Pixoo na rede local (Pixoo-64, Pixoo-32 ou Pixoo-16).
  • Opcional, para o renderizador HTML: chrome-headless-shell. npx @puppeteer/browsers install chrome-headless-shell@stable --path ~/.cache/puppeteer o instala onde o servidor procura por padrão. Instalado em outro lugar com --path <dir>, defina PIXOO_BROWSER_PATH para o caminho do executável que a instalação imprime. O servidor o inicia headless, sem porta DevTools, apenas quando uma renderização precisar dele.

Instalação

  1. Clone o repositório:
git clone https://github.com/cyanheads/pixoo-mcp-server.git
  1. Navegue para o diretório:
cd pixoo-mcp-server
  1. Instale as dependências:
bun install
  1. Configure o ambiente:
cp .env.example .env
# edit .env and set PIXOO_IP

Configuração

VariávelDescriçãoPadrão
PIXOO_IPIP do dispositivo na rede local. Obrigatório para envios, sobreposições e controle do dispositivo; descoberta, briefings de design e renderizações de push: false funcionam sem ele.—
PIXOO_SIZETamanho da tela em pixels: 16, 32 ou 64.64
PIXOO_OUTPUT_DIRDiretório onde as ferramentas de renderização salvam arquivos PNG e GIF de pré-visualização. Um caminho relativo é resolvido em relação ao diretório de onde o servidor foi iniciado, então os caminhos salvos que ele relata são absolutos. Sem definição, as pré-visualizações são retornadas apenas na resposta.—
PIXOO_PUSH_MIN_INTERVAL_MSIntervalo mínimo entre envios ao dispositivo, em ms.1000
PIXOO_SERVE_HOSTHost anunciado na URL da qual o dispositivo baixa uma animação de mais de 40 quadros, no lugar do endereço local que o SO roteia para PIXOO_IP. O listener vincula esse endereço roteado de qualquer forma. Defina-o atrás de NAT ou em um contêiner.—
PIXOO_SERVE_PORTPorta fixa para o listener de uso único desse download, para regras de firewall e publicação de porta em contêineres. Sem definição, uma porta livre por reprodução.—
PIXOO_BROWSER_PATHExecutável do navegador para renderização HTML. Quando definido, é o único navegador tentado: um caminho que não é um arquivo executável falha em vez de recorrer a outro. Um caminho relativo é resolvido em relação ao diretório de inicialização. Sem definição, o chrome-headless-shell mais recente no cache do Puppeteer (~/.cache/puppeteer). A imagem Docker não inclui navegador.—
PIXOO_HTML_ENABLEDOferecer pixoo_render_html. false o remove de tools/list; um valor que não seja booleano falha na inicialização.true
MCP_TRANSPORT_TYPETransporte: stdio ou http.stdio
MCP_HTTP_PORTPorta do servidor HTTP.3010
MCP_SESSION_MODEModo de sessão HTTP: stateless, stateful ou auto. Um valor definido aqui substitui o stateless declarado pelo servidor.stateless
MCP_AUTH_MODEAutenticação: none, jwt ou oauth.none
MCP_LOG_LEVELNível de registro (debug, info, warning, error, etc.).info
LOGS_DIRDiretório para arquivos de registro (somente Node.js).<project-root>/logs
LOG_TOOL_FAILURE_PAYLOADSRegistrar os argumentos e o resultado de cada chamada de ferramenta com falha, editados por nome de chave e limitados a LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (padrão 16384). Um segredo dentro de um valor de formato livre não é editado.false
OTEL_ENABLEDHabilitar OpenTelemetry.false

Consulte .env.example para a lista completa de substituições opcionais.

Executando o servidor

Desenvolvimento local

  • Compilar e executar:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • Executar verificações e testes:

    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 (o endereço LAN do host Docker) e a PIXOO_SERVE_PORT publicada permitem que o dispositivo baixe animações de mais de 40 quadros de dentro do contêiner, como na configuração stdio acima.

O Dockerfile usa por padrão transporte HTTP, modo de sessão sem estado e registra em /var/log/pixoo-mcp-server. Dependências de pares do OpenTelemetry são instaladas por padrão; compile com --build-arg OTEL_ENABLED=false para omiti-las.

Estrutura do projeto

DiretórioFinalidade
src/index.tsPonto de entrada do createApp(): registra ferramentas e recursos e inicializa o serviço Pixoo.
src/config/Análise e validação de variáveis de ambiente específicas do servidor com Zod.
src/mcp-server/tools/Definições de ferramentas (*.tool.ts), o caminho compartilhado de envio pós-renderização e o esquema de entrada compartilhado de finish.
src/mcp-server/resources/Definições de recursos (*.resource.ts).
src/services/pixoo/PixooService: envolve @cyanheads/pixoo-toolkit com ritmo de envio, mapeamento de resultados e leituras de estado do dispositivo.
src/services/browser/BrowserRenderer: renderiza HTML em um chrome-headless-shell isolado, controlado pelo pipe do protocolo DevTools, e o captura como um quadro do painel.
src/renderer/Pipeline de renderização puro sem dependência de dispositivo: renderizadores de elementos, mecanismo de texto estilizado, temas, ícones, compilador de efeitos, finalização de paleta, codificação de pré-visualização, busca remota de imagens e o relógio virtual injetado em páginas HTML.
tests/Testes unitários e de integração espelhando src/.

Guia de desenvolvimento

Consulte CLAUDE.md/AGENTS.md para diretrizes de desenvolvimento e regras arquiteturais. A versão resumida:

  • Handlers lançam exceções, o framework captura — sem try/catch na lógica das ferramentas
  • Use ctx.log para logging no escopo da requisição, ctx.state para armazenamento no escopo do tenant
  • O renderizador (src/renderer/) é puro — sem dependência de dispositivo, testável sem hardware
  • Todas as chamadas de dispositivo passam por PixooService; cada PixooResult é verificado — nunca presuma que um push foi bem-sucedido

Contribuindo

Issues são bem-vindas. Execute as verificações e testes antes de enviar:

bun run devcheck
bun run test

Licença

Apache-2.0 — veja LICENSE para detalhes.