Skin format
A skin is the skin/ folder of its project (MCP server).
The extension applies it once the project has a valid skin/skin.json.
skin/ skin.json metadata, and which files make up the skin (required) trigger.js decides where the skin is on (required) style.css optional content.html optional behavior.js optionalThe file names are yours to choose, except skin.json: it names the others.
skin.json
Section titled “skin.json”interface SkinJson { name: string; // the skin's title in the side panel; at most 40 characters description: string; // what it does; at most 160 characters activeWhen: string; // where it is on, in plain words, for people; at most 80 characters trigger: string; // file in skin/ with the trigger, e.g. "trigger.js" css?: string; // file in skin/ with CSS html?: string; // file in skin/ with HTML js?: string; // file in skin/ with JavaScript}- The text fields are single-line and non-empty. Unknown keys are rejected.
- File fields are paths inside
skin/: letters, digits,.,_,-and/, no...
trigger.js
Section titled “trigger.js”The body of an async function, run in the page on each page load and in-page navigation. The skin is
on only while it returns true.
// What the body can use:declare const url: string; // location.href when the trigger starteddeclare const document: Document; // the page's documentdeclare const location: Location; // the page's location// It returns: true to apply the skin. Anything else means no.- Only the literal
truecounts. Any other value, an error, or taking longer than 3 seconds means no. - It may
await, for example for an element to appear. - It runs on every web page you open, for every skin that’s on: check cheap things first, like the hostname, and return early.
How the parts are applied
Section titled “How the parts are applied”When the trigger returns true, once per page view:
| Part | Applied as |
|---|---|
css |
A stylesheet added to the page |
html |
Inserted into a container at the end of the page’s <body> |
js |
Run once, after the CSS and HTML are in |
- The JavaScript sees the page’s DOM, not the page’s own JavaScript variables. It can’t
importanything, and the page’s Content Security Policy doesn’t stop it. - Prefer CSS. Use JavaScript only for what CSS can’t do.
- If your JavaScript watches the page with a
MutationObserver, disconnect it while you change the page and reconnect after, and only write what actually changed. Otherwise each change triggers the next and the page never settles. - When the trigger stops returning
true, the CSS and HTML are removed. Whatever the JavaScript did stays until the page reloads.
Example: hello world
Section titled “Example: hello world”A skin that adds a greeting to example.com.
skin/skin.json
{ "name": "Hello world", "description": "Adds a greeting banner to example.com", "activeWhen": "On example.com", "trigger": "trigger.js", "css": "style.css", "html": "content.html", "js": "behavior.js"}skin/trigger.js
return location.hostname === "example.com";skin/content.html
<div class="hello-skin">Hello from your first skin! <span class="hello-time"></span></div>skin/style.css
.hello-skin { position: fixed; right: 16px; bottom: 16px; padding: 10px 14px; border-radius: 8px; background: #1d1d1f; color: #fff; font: 14px/1.4 system-ui, sans-serif;}skin/behavior.js
const time = document.querySelector(".hello-skin .hello-time");if (time) time.textContent = `It's ${new Date().toLocaleTimeString()}.`;Write these files to a project with writeGadgetFile (MCP server), publish the
draft, and open https://example.com.
