Website-AdapterEntwicklungsleitfaden

🔌 Adapter-Entwicklungsleitfaden

ForcedSkin-Adapter werden als deklarative JSON-Formeln ( forcedskin-adapter-formula/v1 ) erstellt, die festlegen, welche Hostnames angesprochen und welche Selector-Layer eingefärbt werden. Der Server speichert nur JSON; die Erweiterung enthält einen festen Interpreter , der Paint-Regeln anwendet — niemals beliebiges JavaScript.

So funktioniert es

Die Core-Engine startet mit CSS-Variable- und Inline-Overlays für die Basiseinfärbung.

Bei Treffer eines Hostnames laufen Adapter aufsteigend nach priority — je kleiner die Zahl, desto früher führt der Interpreter aus (empfohlen für Website-Adapter: 100).

Jeder Adapter passt gezielte Nodes über die exponierten engineApi-Helper an; überspringe transparente Overlays/Player-Stacks gemäß den Best-Practices-Hinweisen.

Die Runtime beobachtet DOM-Änderungen bereits und wendet Adapter gedrosselt erneut an — kein MutationObserver-Boilerplate nötig.

Formeln kommen von GET /api/pub/extension-adapters ; der JSON-Blob jedes Datensatzes wird lokal gecacht. Aktualisierungen im Portal wirken, sobald Nutzer Adapter aktualisieren oder den Browser neu öffnen — keine Neuinstallation nötig.

Minimales Beispiel

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

Adapter-Formel forcedskin-adapter-formula/v1

Eingereichtes JSON muss die Server-Validierung bestehen — das Root-Schema sieht so aus:

FeldTypErforderlichBeschreibung
schemastringErforderlichLiteraler Versionsstring forcedskin-adapter-formula/v1
idstringErforderlichLogische Adapter-ID — meist der Website-Codename, z. B. bilibili
prioritynumberOptionalAusführungsreihenfolge (aufsteigend). Website-spezifische Adapter verwenden typischerweise 100
match.hostnameRule[]ErforderlichArray von Hostname-Regelobjekten (siehe Tabelle unten)
layersLayer[]ErforderlichGeordnete Paint-Layer — Typen in der Layer-Tabelle dokumentiert

match.hostname-Regeln

OperatorBedeutung
equalsHostname entspricht dem Wert (Groß-/Kleinschreibung ignoriert)
suffixDomainHostname entspricht dem Wert oder endet mit .value (deckt example.com und *.example.com ab)

Paletten-Keys (richText cssVars / color)

FeldBeschreibung
backgroundSeitenhintergrund
foregroundPrimärer Text
surfaceKarten-/Panel-Füllung
surfaceMutedGedämpfte Container / Hover-Füllungen
borderRahmenfarbe
mutedSekundärer Text
primary500Primäre Betonung (Links), gemappt von Theme primary.500
primary700Tieferer Primary-Zustand, gemappt von primary.700 oder 800

Empfohlene Layer-Typen

Denke semantisch — nicht nur nach Elementnamen. Siehe das eingecheckte Beispiel home/server/seeds/bilibili-adapter.formula.json für eine vollständige Anleitung.

Layer-TypZweckTypisches MappingmarkApplied
surfacePanels, Listenzeilen, Nav-Shellsbackground→surface, color→foreground, border→borderbg + text + border
accentAktive Tabs / aktuelle Listenzeilenbackground+border→primary700, color→background für Kontrastbg + text + border
canvasHero-Flächen mit Raster-Hintergründenbackground-image entfernen, background→Palette backgroundMeist nur background
richTextWebsites mit gebrandeten Web ComponentsErforderliche CSS-Variablen + textuelles Color-Mapping ausgebentext (manchmal + background)
svgRecolorInline-SVG-GlyphenStandard fill/stroke→currentColor; optionale fill/stroke-Paletten-Keys für feste FarbeOptionales Marking, um Cleanup nicht zu stören

Riskante Bereiche überspringen: Die Engine ignoriert bereits media, canvas, iframe, schwere blend/backdrop-Layer und Nodes, deren Klassen auf Masken oder Overlays hindeuten — erweitere diese Guardrails für transluzentes Player-Chrome.

Host-Opt-out: Markiere Teilbäume (z. B. Vorschauen) mit data-gts-ignore , damit deren Nachfahren die globale Neufärbung überspringen.

Vollständiger Beispielauszug

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

Best Practices

JSON muss strikt validieren

Ungültiges Schema/Layer/Host-Regeln werden in der Prüfung abgelehnt — nutze das minimale Beispiel und Seeds aus diesem Leitfaden vor dem Einreichen.

skipOverlayLike auf surface aktivieren

Entspricht den Core-Engine-Sicherungen, damit transluzente HUDs/Video-Stacks nicht zu soliden Flächen werden.

Niemals JavaScript ausliefern

Das code-Feld ist nur JSON; die Erweiterung evaluiert Strings nicht mehr über new Function.

Checkliste für die Einreichung

🔐 Vor dem Einreichen anmelden.

📋 Anzeigename, kommagetrennte Domains angeben und das JSON in das Adapter-Code-Textfeld einfügen.

⏳ Einträge landen im Status pending, bis das Team Sicherheit und Selector-Umfang prüft.

✅ Freigegebene Adapter werden an alle Erweiterungsnutzer ausgerollt, die Adapter synchronisieren.

❌ Zu breite Selectors oder ungültiges JSON führen zu Feedback — korrigieren und erneut einreichen.

Format der Ziel-Domain

siteDomain ist die menschenlesbare Liste; das Matching erfolgt tatsächlich über match.hostname wie:

[
  { "op": "equals", "value": "bilibili.com" },
  { "op": "suffixDomain", "value": "bilibili.com" }
]

Bereit? Öffne die Adapter-Galerie und reiche dein JSON ein.

🔌 Adapter einreichen