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.
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
| Ferramenta | Descrição |
|---|---|
pixoo_display_text | Renderiza texto estilizado com temas, gradientes, sombras e ajuste automático, estático ou animado, e o envia |
pixoo_compose_scene | Compõe cenas em camadas de texto, ícones, widgets, formas, bitmaps, imagens e sprites, estáticas ou animadas |
pixoo_push_image | Redimensiona uma imagem local ou https para a grade de LEDs e a envia, ou um GIF animado ou WebP como animação |
pixoo_render_html | Renderiza 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_text | Define ou limpa uma sobreposição de texto rolante renderizada pelo dispositivo |
pixoo_control_device | Lê ou altera brilho, estado da tela, canal ou face do relógio |
pixoo_discover_devices | Encontra dispositivos Pixoo e seus IPs de LAN através da descoberta em nuvem da Divoom |
pixoo_design_brief | Orientação de criação para um tópico de design, com estado do dispositivo ao vivo e próximas chamadas pré-preenchidas |
Recursos
| Recurso | Descrição |
|---|---|
pixoo://device/status | Instantâneo do dispositivo ao vivo: acessibilidade, canal, brilho, estado da tela, tamanho do display |
pixoo://reference/themes | Registro de temas e paletas |
pixoo://reference/icons | Nomes de ícones integrados por categoria |
pixoo://reference/design-guide | Guia 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
textcomo uma string ou um array de linhas;theme(midnight,ember,claude,ice,neon,forest,mono) define o fundo e a paleta padrão.styleaceita um gradientepalette(ember,ice,neon,fire,lavender,claude,mono) ou um{ from, to }personalizado, além deshadow,outlineescale1–8;positioné semântico ou em pixels, ealignalinha texto de múltiplas linhasfont:standard(5×7) ecompact(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 respostanotice;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 caractereslayout[]relata cada decisão de ajuste como umaction(shrunk-to-compactquando o texto cabe apenas na fonte compacta,scrollingquando os quadros retornados rolam,nonecaso contrário), ofontusado e se a caixa de cada linhafitsno 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 quefontesteja definido — nunca paranumerals— e texto ainda largo demais só rola sobeffect: "auto"ou"scroll"effect:scrollfaz uma passagem em até 40 quadros,autorola apenas em estouro, efloatepulsefazem loop em 20 quadros;framesrelata a contagem, e a animação é enviada como uma animação de dispositivo
pixoo_compose_scene ferramenta
- Até 50
elementsdesenhados de trás para frente:text(nas mesmas três fontes quepixoo_display_text),icon,rect,circle,line,progress,sparkline,bitmap,pixels,image(caminho absoluto ou URL https, com o mesmofinishquepixoo_push_image),sprite(caminho absoluto). Obackgroundé uma cor sólida, um gradientev/h/rou umtheme - Cada elemento aceita
opacity(cada pixel cai em seu próprio alfa ×opacity, então bordas suaves desvanecem uniformemente) eblend:normal,add(brilhos e feixes de luz),screenoumultiply.linee contornocircleaceitamstrokeWidtheantialias, e uma bordarectaceitastrokeWidth, 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 elefitsno painel. Os elementos são posicionados como fornecidos e nunca reajustados, entãoactioné semprenone. Um caminho absolutooutputsalva o primeiro quadro como PNG no lugar do salvamento automáticoPIXOO_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
effectpor elemento (float,scroll-left,scroll-right,pulse,blink,twinkle,drift,fade-in,fade-out) ou keyframesanimatebrutos ao longo dedx,dy,opacity(números ou strings numéricas),visible(true/false) ecolor(interpolado através de RGB em qualquer elemento com umcolor), cada trilha contendo pelo menos um keyframe;frames1–800,speed10–2000 ms por quadro (padrão 150). Acima de 40 quadros, a cena é reproduzida como um GIF que o dispositivo baixa deste host, comspeedarredondado para 10 ms. Um elemento aceitaeffectouanimate, não ambos. Oamplitudede um efeito define o movimento defloat,scroll-*edrift, e a profundidade 0–1 do mergulho de opacidadepulseetwinkle
pixoo_push_image ferramenta
sourceé um caminho local absoluto ou uma URL https, com downloads limitados a 10 MB;fitécontain(padrão),coveroufill, ekernelénearest(padrão, para pixel art),lanczos3(fotos) oumitchell- Uma fonte que decodifica como GIF animado ou WebP, qualquer que seja seu nome de arquivo, é enviada como uma animação de até
maxFramesquadros (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 emspeed(10–2000 ms por quadro);frames,sourceFramesespeedrelatam o que foi enviado finishreduz a imagem a uma paleta antes do envio: exatamente um decolors(2–256, construído a partir da imagem) oupalette(1–256 cores hex ou nomeadas), maisdither(none,bayer4,floyd-steinberg). Pixels transparentes permanecem apagados, e a paletacolorsde 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 comoinvalid_image, e uma entrada de paletafinishnão resolvível falha comoinvalid_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:bodynã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 -
frames1–800 (padrão 1),speed10–2000 ms por quadro (padrão 150). Cada quadro avança um relógio virtual emspeed:window.render(t, frame), quando a página o define, executa antes de cada captura comt = 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) eperformance.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.requestIdleCallbacke iframes mantêm o tempo real. Acima de 40 quadros, a página é reproduzida como um GIF que o dispositivo baixa deste host, como empixoo_compose_scene -
sampling:native(padrão) ousupersample, 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 emleft: 0.5pxainda cai em um LED; mova-a comtransformpara movimento sub-pixel.finishaceita a mesma redução de paleta quepixoo_push_image, aplicada antes da pré-visualização -
Nada é carregado da rede e workers são bloqueados.
pageErrorsretorna os erros não capturados da página, saídaconsole.errore URLs bloqueadas (uma navegação bloqueada comoBlocked navigation: <url>): os primeiros 20, cada um cortado em 500 caracteres. Umwindow.renderque lança ou rejeita falha comopage_error, nomeando o quadro; sem navegador encontrado, a chamada falha comobrowser_unavailablecom etapas de instalação (veja Pré-requisitos);render_timeouterender_crashedcobrem uma renderização acima de 30 s e um navegador ou página travados.PIXOO_HTML_ENABLED=falseremove a ferramenta -
Cada página recebe um global
pixooantes 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 depixoo_display_text.pixoo.icon(ctx, name, x, y, { w, h, color, palette })desenha um ícone do registro.pixoo.palettescontém as 7 paletas, epixoo.sizeé o tamanho do painel.
Texto e ícones desenhados desta forma correspondem a
pixoo_compose_scenepixel 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_briefcom tópicohtmlcobre loops, o relógio, amostragem, o runtimepixooe 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 (id0–19).setexigetexte recebe um ID defontdo dispositivo (0–114),x/ydentro dePIXOO_SIZE,color,speed(0–100),direction,alignewidth- Retorna
acknowledged,modeeid. 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) ouclockFaceIdé aplicado antes da leitura de retorno - Retorna
reachable,channel,brightness,screenOneclockId(ausente quando inacessível) além deapplied; uma configuração com falha é omitida deappliede 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;timeoutMs1000–30000 (padrão 5000) - Retorna o
name,ideipde cada dispositivo; comPIXOO_IPdefinido,configuredIpFoundindica se houve correspondência. Um endpoint inacessível falha comodiscovery_failed
pixoo_design_brief tool
topic:text,scene,dashboard,animation,pixel-art,htmloutroubleshooting; funciona sem um dispositivo acessível- Retorna markdown
craftGuidance, umdeviceContextao vivo,htmlRenderer(available,disabledquandoPIXOO_HTML_ENABLED=false, ouno_browser, encontrado sem abrir um navegador),nextToolSuggestionscomo{ toolName, reason, args }com argumentos pré-preenchidos para o tópico e o estado do dispositivo, além deavailableThemeseiconCategories
pixoo://device/status resource
- Leitura ao vivo sem cache:
reachable,channel,brightness,screenOn,clockId,displaySize,configuredIp - Retorna
reachable: falseem vez de um erro quando o dispositivo não pode ser alcançado ouPIXOO_IPnão está definido
pixoo://reference/themes resource
- Cada tema (fundo,
textPalette,accent,shadow) e paleta (paradas defrom/to), além dethemeNamesepaletteNamespara os parâmetrosthemeepalette - Registro estático, em cache por 24h
pixoo://reference/icons resource
- O
name,categoryeviewBoxde cada ícone, além de um agrupamento porbyCategory(clima, setas, status, mídia); umnamevai em um elemento de íconepixoo_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_briefretorna 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_imageepixoo_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_textpermanece dentro de 40
Saída amigável para agentes:
- Pré-visualização em cada renderização:
pixoo_display_text,pixoo_compose_scene,pixoo_push_imageepixoo_render_htmlretornam o quadro como um bloco de imagem PNG ampliado 8×, enviado ou não, para quepush: falseverifique 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 emPIXOO_OUTPUT_DIRquando 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:
pushedreflete 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 dedeviceStateapó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) carregaoutputFilesapontando para a pré-visualização salva (a cópia dePIXOO_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/puppeteero instala onde o servidor procura por padrão. Instalado em outro lugar com--path <dir>, definaPIXOO_BROWSER_PATHpara 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
- Clone o repositório:
git clone https://github.com/cyanheads/pixoo-mcp-server.git
- Navegue para o diretório:
cd pixoo-mcp-server
- Instale as dependências:
bun install
- Configure o ambiente:
cp .env.example .env
# edit .env and set PIXOO_IP
Configuração
| Variável | Descrição | Padrão |
|---|---|---|
PIXOO_IP | IP 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_SIZE | Tamanho da tela em pixels: 16, 32 ou 64. | 64 |
PIXOO_OUTPUT_DIR | Diretó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_MS | Intervalo mínimo entre envios ao dispositivo, em ms. | 1000 |
PIXOO_SERVE_HOST | Host 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_PORT | Porta 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_PATH | Executá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_ENABLED | Oferecer pixoo_render_html. false o remove de tools/list; um valor que não seja booleano falha na inicialização. | true |
MCP_TRANSPORT_TYPE | Transporte: stdio ou http. | stdio |
MCP_HTTP_PORT | Porta do servidor HTTP. | 3010 |
MCP_SESSION_MODE | Modo de sessão HTTP: stateless, stateful ou auto. Um valor definido aqui substitui o stateless declarado pelo servidor. | stateless |
MCP_AUTH_MODE | Autenticação: none, jwt ou oauth. | none |
MCP_LOG_LEVEL | Nível de registro (debug, info, warning, error, etc.). | info |
LOGS_DIR | Diretório para arquivos de registro (somente Node.js). | <project-root>/logs |
LOG_TOOL_FAILURE_PAYLOADS | Registrar 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_ENABLED | Habilitar 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ório | Finalidade |
|---|---|
src/index.ts | Ponto 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/catchna lógica das ferramentas - Use
ctx.logpara logging no escopo da requisição,ctx.statepara 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; cadaPixooResulté 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.