🔌 Guia de desenvolvimento de adaptadores
Os adaptadores ForcedSkin são escritos como fórmulas JSON declarativas ( forcedskin-adapter-formula/v1 ) descrevendo quais hostnames atingir e quais camadas de seletor colorir. O servidor armazena apenas JSON; a extensão traz um interpretador fixo que aplica regras de pintura — nunca JavaScript arbitrário.
Como funciona
O motor principal começa com sobreposições de variáveis CSS + estilos inline para a recoloração básica.
Quando um hostname corresponde, os adaptadores rodam em ordem crescente de prioridade — quanto menor o número, mais cedo o interpretador executa (adaptadores de site recomendados usam 100).
Cada adaptador ajusta nós alvo via os helpers engineApi expostos; pule sobreposições transparentes/pilhas de player conforme as boas práticas.
O runtime já observa deltas do DOM e reaplica adaptadores com throttle — você não precisa de MutationObserver.
As fórmulas chegam de GET /api/pub/extension-adapters ; o blob JSON de cada registro é armazenado em cache local. Atualizar a cópia no portal passa a valer quando os usuários atualizam os adaptadores ou reabrem o navegador — sem reinstalar.
Exemplo mínimo
{
"schema": "forcedskin-adapter-formula/v1",
"id": "example-site",
"priority": 100,
"match": {
"hostname": [
{ "op": "suffixDomain", "value": "example.com" }
]
},
"layers": [
{
"kind": "surface",
"skipOverlayLike": true,
"selectors": [".site-navbar", ".site-header"]
}
]
}Fórmula de adaptador forcedskin-adapter-formula/v1
O JSON enviado deve passar na validação do servidor — o esquema raiz é assim:
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| schema | string | Obrigatório | String de versão literal forcedskin-adapter-formula/v1 |
| id | string | Obrigatório | Id lógico do adaptador — geralmente o codinome do site, ex. bilibili |
| priority | number | Opcional | Ordem de execução (crescente). Adaptadores específicos de site costumam usar 100 |
| match.hostname | Rule[] | Obrigatório | Array de objetos de regra de hostname (veja a tabela abaixo) |
| layers | Layer[] | Obrigatório | Camadas de pintura ordenadas — tipos documentados na tabela de camadas |
Regras de match.hostname
| Operador | Significado |
|---|---|
| equals | Hostname igual a value (sem distinguir maiúsculas) |
| suffixDomain | Hostname igual a value ou termina com .value (cobre example.com e *.example.com) |
Chaves de paleta (richText cssVars / color)
| Campo | Descrição |
|---|---|
| background | Fundo da página |
| foreground | Texto principal |
| surface | Preenchimento de cartão / painel |
| surfaceMuted | Contêineres atenuados / fundos de hover |
| border | Cor da borda |
| muted | Texto secundário |
| primary500 | Ênfase primária (links) mapeada de theme primary.500 |
| primary700 | Estado primary mais profundo mapeado de primary.700 ou 800 |
Tipos de camada recomendados
Pense semanticamente — não só pelos nomes dos elementos. Veja o exemplo versionado home/server/seeds/bilibili-adapter.formula.json para um passo a passo completo.
| Tipo de camada | Uso | Mapeamento típico | markApplied |
|---|---|---|---|
| surface | Painéis, linhas de lista, cascas de navegação | background→surface, color→foreground, border→border | bg + texto + borda |
| accent | Abas ativas / linhas de lista atuais | background+border→primary700, color→background para contraste | bg + texto + borda |
| canvas | Blocos hero com fundos raster | Remover background-image, background→palette background | Geralmente só o fundo |
| richText | Sites que expõem web components da marca | Emitir as variáveis CSS necessárias + mapeamento de cor textual | texto (às vezes + fundo) |
| svgRecolor | Glifos SVG inline | fill/stroke padrão→currentColor; chaves de paleta fill/stroke opcionais para cor fixa | Marcação opcional para não interferir na limpeza |
Evite regiões arriscadas: O motor já ignora media, canvas, iframe, camadas pesadas de blend/backdrop e nós cujas classes sugerem máscaras ou overlays — estenda essas proteções para o chrome translúcido de players.
Opt-out do host: Marque subárvores (ex. prévias) com data-gts-ignore para que os descendentes pulem a repintura global.
Trecho de exemplo completo
{
"schema": "forcedskin-adapter-formula/v1",
"id": "bilibili",
"priority": 100,
"match": {
"hostname": [
{ "op": "equals", "value": "bilibili.com" },
{ "op": "suffixDomain", "value": "bilibili.com" }
]
},
"layers": [
{
"kind": "surface",
"skipOverlayLike": true,
"selectors": ["[class*='bili-']", "[class*='bpx-']"]
},
{
"kind": "accent",
"selectors": ["[class*='active']", ".bili-dyn-list-tabs__item.active"]
},
{
"kind": "canvas",
"selectors": [".message-bg", ".message-bgc"]
},
{
"kind": "richText",
"selectors": ["bili-rich-text"],
"cssVars": {
"--bili-rich-text-color": "foreground",
"--bili-rich-text-link-color": "primary500",
"--bili-rich-text-link-color-hover": "primary700"
},
"color": "foreground"
},
{
"kind": "svgRecolor",
"selectors": ["svg path", "svg rect", "svg circle"]
}
]
}Boas práticas
O JSON deve validar de forma estrita
Esquema/camadas/regras de host inválidos são recusados na revisão — use o exemplo mínimo e as seeds deste guia antes de enviar.
Ative skipOverlayLike em surface
Alinha-se às proteções do motor para que HUDs translúcidos/pilhas de vídeo não sejam achatados em preenchimentos sólidos.
Nunca envie JavaScript
O campo code é apenas JSON; a extensão não avalia mais strings com new Function.
Checklist de envio
🔐 Entre antes de enviar.
📋 Informe o nome de exibição, os domínios separados por vírgula e cole o JSON na área de código do adaptador.
⏳ O servidor valida o esquema JSON e as regras de segurança; JavaScript ou outro código de risco é rejeitado.
✅ Fórmulas válidas são publicadas automaticamente e chegam aos usuários da extensão que sincronizam adaptadores.
❌ Seletores amplos demais ou JSON inválido geram retorno — corrija e reenvie.
Formato do domínio de destino
siteDomain é a lista visível; a correspondência real usa match.hostname, por exemplo:
[
{ "op": "equals", "value": "bilibili.com" },
{ "op": "suffixDomain", "value": "bilibili.com" }
]Pronto? Abra a galeria de adaptadores e envie seu JSON.
🔌 Enviar um adaptador