Install this skill

Paste this into Claude Code (VS Code panel, Adom editor, or terminal) to install:

Search the Adom Wiki for the skill "Hydrogen Webview Tab Icons" (slug: hydrogen-webview-tab-icons) at https://wiki-ufypy5dpx93o.adom.cloud/wiki/skills/hydrogen-webview-tab-icons and install it into my local ~/.claude/skills/hydrogen-webview-tab-icons/ directory. Fetch the skill_source content from the wiki page and save it as SKILL.md. Then confirm it's installed by showing the first 5 lines.
?
What is a skill? Skills are instructions that teach AI assistants like Claude Code how to perform specific tasks. The description below is loaded into the AI as context when you invoke this skill. Well-written skills make the AI significantly more effective. Like Wikipedia, anyone can improve a skill by clicking Edit AI Skill — or have your AI submit an edit on your behalf.

Description

Edit AI Skill

Hydrogen Webview Tab Icons

How Hydrogen webview workspace tabs actually get their icons in the Adom editor. Read the "Real mechanism" section first — the placeholder vs. favicon distinction is the thing future Claude sessions usually get wrong, including an earlier version of this skill.

Scope

This skill is only about tabs whose panelType is adom/a1b2c3d4-0031-4000-a000-000000000031 — the generic Hydrogen webview that loads an HTML page from a URL. The favicon-override mechanism described below is specific to webview panels because only they load an HTML page that can ship its own <link rel="icon">.

Other panel types — Schematic Editor, 3D Editor, KiCad panel, Desktop Demo, Movie Maker, Adom Viewer native panel, etc. — have their icons assigned by Hydrogen's internal panel registry keyed off panelType, not by anything the tab adder passes in. If your tab isn't a webview and its icon is wrong, this skill will not help you — open a Hydrogen issue instead.

Real mechanism (the thing everyone misses)

Hydrogen webview tabs have two sources for their displayed icon, and the loaded page wins:

  1. panelState.displayIcon — a placeholder you pass via --display-icon / HTTP displayIcon. Shown only until the page loads.
  2. The loaded page's <link rel="icon"> — Hydrogen's Web View panel reads the favicon after load and writes it into panelState.displayIcon, overriding whatever the placeholder was.

Practical consequence: once any page with a favicon finishes loading, your --display-icon "mdi:chip" is gone. If you want the icon to be stable and predictable, you have to serve the favicon you want from the page you load.

Empirical proof: create a tab with --display-icon "mdi:rocket-launch", navigate it to https://example.com, then inspect the tab's panelState.displayIcon via adom-cli hydrogen workspace tabs — it will be a data:image/svg+xml;base64,... value matching example.com's favicon, not mdi:rocket-launch.

Brand rule: icons must be monochrome #e6edf3

Per gallia/skills/brand/SKILL.md, all Adom icons must be monochrome white (#e6edf3) — no colored icons, no multi-color, no brand-palette colors in icons. This applies to tab icons too.

  • First choice: use an mdi:<name> placeholder for the --display-icon flag. MDI icons are already monochrome and inherit the theme color automatically, so you get brand compliance for free. Search https://pictogrammers.com/library/mdi/ for a matching icon.
  • If you need a custom icon (no MDI match, or you want to ship your own favicon for the page-load override): hand-roll an SVG with fill="#e6edf3" (or fill="currentColor" so it inherits), a 24x24 viewBox, and clean filled paths or 2px strokes. No gradients, no shadows, no color. Details that break at 16 px lose.

Concrete example of a brand-compliant custom icon (the adom-tsci chip) — 318 bytes, single path, monochrome #e6edf3:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#e6edf3">
  <path d="M6 2a2 2 0 0 0-2 2v2H2v2h2v3H2v2h2v3H2v2h2v2a2 2 0 0 0 2 2h2v2h2v-2h3v2h2v-2h3v2h2v-2a2 2 0 0 0 2-2v-2h2v-2h-2v-3h2v-2h-2V8h2V6h-2V4a2 2 0 0 0-2-2h-2V0h-2v2h-3V0h-2v2H9V0H7v2H6zm0 2h12v16H6V4zm2 3v10h8V7H8zm2 2h4v6h-4V9z"/>
</svg>

Rendered in a dark-background Hydrogen tab bar, that's a white chip with pins sticking out — visually identical to mdi:chip but served from your own app so it can't be overridden.

The right way: serve your own favicon from your app

If you're writing a Rust/Node/Python/Go app that opens a Hydrogen webview tab, put a <link rel="icon"> in the HTML you serve. Hydrogen will pick it up on load and that's what the user will see. Use a brand-compliant #e6edf3 monochrome SVG (see section above).

Rust + tiny_http example (the adom-tsci pattern)

<!-- src/assets/shell.html, embedded in the binary via include_str! -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My App</title>
<!-- Hydrogen reads this and uses it as the tab icon. -->
<link rel="icon" type="image/svg+xml" href="favicon.svg">
...
// Serve favicon.svg from the tiny_http route handler.
if url == "/favicon.svg" || url == "/favicon.ico" {
    let body = include_str!("../assets/icon.svg");
    return Ok(request.respond(
        Response::from_string(body)
            .with_header(
                Header::from_bytes(&b"Content-Type"[..], &b"image/svg+xml"[..]).unwrap()
            ),
    )?);
}
<!-- src/assets/icon.svg — MONOCHROME per the brand rule. fill must be
     "#e6edf3" (or "currentColor"), NEVER a colored palette value. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#e6edf3">
  <rect x="5" y="5" width="14" height="14" rx="1"/>
  <rect x="3"  y="7"  width="2" height="2"/>
  <rect x="3"  y="11" width="2" height="2"/>
  <rect x="3"  y="15" width="2" height="2"/>
  <rect x="19" y="7"  width="2" height="2"/>
  <rect x="19" y="11" width="2" height="2"/>
  <rect x="19" y="15" width="2" height="2"/>
  <rect x="7"  y="3"  width="2" height="2"/>
  <rect x="11" y="3"  width="2" height="2"/>
  <rect x="15" y="3"  width="2" height="2"/>
  <rect x="7"  y="19" width="2" height="2"/>
  <rect x="11" y="19" width="2" height="2"/>
  <rect x="15" y="19" width="2" height="2"/>
</svg>

(Perfectly symmetric chip: body + 12 pins, 3 per side, even 4-unit spacing, rx=1 rounded corner, all in brand #e6edf3. This is the exact adom-tsci icon — taken from the repo's src/assets/icon.svg.)

When the page loads from https://<workspace>.adom.cloud/proxy/<port>/, the browser fetches /proxy/<port>/favicon.svg, your app returns the SVG, Hydrogen syncs it onto the tab, and the icon stays put.

Rules for the favicon file:

  • Square viewBox (e.g. 0 0 64 64 or 0 0 24 24).
  • Self-contained SVG — no external fonts, no xlink:href to other files, no embedded images.
  • Bold, filled shapes over thin strokes — the tab bar is ~16–20 px so details get lost.
  • Transparent background is fine, the tab bar shows through.
  • Brand color in the SVG itself if you want a colored icon. MDI icons can't be tinted.

Placeholder-only case: mdi:<name> / data:... via add-tab

If the page you're loading doesn't set its own favicon, or if you're creating a tab that navigates to about:blank or similar, the --display-icon placeholder is all you get — and it will stick.

Examples where this is actually useful:

  • A tab that loads an external site with no favicon. Rare in practice; most real sites have a favicon.
  • A stopgap during the ~100ms the page takes to load — the user sees the placeholder, then it swaps to the page's favicon.
  • When you don't own the page — you can't inject a <link>, so the placeholder is your only control point, knowing it's about to get overridden.

CLI

adom-cli hydrogen workspace add-tab \
  --panel-id <leaf-id> \
  --panel-type "adom/a1b2c3d4-0031-4000-a000-000000000031" \
  --display-name "My App" \
  --display-icon "mdi:chip" \
  --initial-state '{"url":"https://example.com/"}'

HTTP API

curl -s -X POST \
  -H "X-Api-Key: $API_KEY" $TARGET_HEADER \
  -H "Content-Type: application/json" \
  -d '{
    "panelId": "<leaf-id>",
    "panelType": "adom/a1b2c3d4-0031-4000-a000-000000000031",
    "displayName": "My App",
    "displayIcon": "mdi:chip",
    "initialState": { "url": "https://example.com/" }
  }' \
  "https://hydrogen.adom.inc/api/workspaces/editor/$OWNER/$REPO/current/tabs"

Two placeholder formats

FormatWhen to useExample
mdi:<icon-name>Monochrome icon from Material Design Icons. Inherits the editor theme's foreground color. Can't be tinted.mdi:chip, mdi:bug, mdi:eye
data:image/svg+xml;base64,<b64>Custom SVG, full control. Must still be monochrome #e6edf3 per the brand rule — don't color your own placeholder.data:image/svg+xml;base64,PHN2...

Again: both are placeholders. The page's favicon overrides them both as soon as it loads.

Common MDI icons used in existing Adom tabs

IconTypical use
mdi:chipchips, ICs, boards, PCB/tscircuit tools
mdi:eyeviewers (AV)
mdi:bugbug-filing tools
mdi:chart-linevisualizers
mdi:monitor-cellphonedemo/desktop tools
mdi:githubrepo browsers
mdi:book-open-variantdocs viewers
mdi:cartcommerce tools
mdi:robotautomation / AI
mdi:folderfile explorers
mdi:code-tagscode editors
mdi:palettedesign tools
mdi:camerascreenshot tools

Full catalog: https://icon-sets.iconify.design/mdi/.

Building a custom SVG data URL by hand

When you need a one-off custom icon and don't want to ship a file, you can build a data: URL inline:

SVG='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#00b8b0" d="M13.13 22.19L11.5 18.36..."/></svg>'
B64=$(echo -n "$SVG" | base64 -w0)
DATA_URL="data:image/svg+xml;base64,$B64"

adom-cli hydrogen workspace add-tab \
  --panel-id <leaf-id> \
  --panel-type "adom/a1b2c3d4-0031-4000-a000-000000000031" \
  --display-name "My App" \
  --display-icon "$DATA_URL" \
  --initial-state '{"url":"about:blank"}'

base64 -w0 (no line wrapping) is important — newlines inside the value break the JSON it gets embedded in.

This is still a placeholder. If the tab ever navigates to a page with its own favicon, the placeholder is lost.

Troubleshooting

"I pass mdi:chip but the tab shows a different icon"

Your loaded page has a favicon that overrode the placeholder. Options:

  • Best: serve your own favicon from your app (see Real mechanism above). Pick an SVG that matches the brand/icon you want. Hydrogen will sync it onto the tab.
  • Acceptable: if you don't control the page, you can re-set the displayIcon after load with another add-tab/PATCH call — but the next navigation will override it again.

"My placeholder flickers for a moment then reverts"

That's the expected behavior — the placeholder shows until the page finishes loading, then Hydrogen swaps in the page's favicon.

"My tab has no icon at all"

The loaded page has no <link rel="icon"> and no --display-icon was passed. Hydrogen falls back to the default Web View icon (a globe). Add a favicon to your served HTML.

"I pass a data:image/svg+xml;base64,... and it's broken"

Usually a base64 encoding issue:

  • Use base64 -w0 (no wrap) so the output is a single line.
  • Make sure the raw SVG has no unescaped newlines or tabs that break the JSON wrapper.
  • The SVG must be self-contained: no xlink:href to other files, no @import in <style>, no embedded <image> pointing at URLs.

"I set the tab to mdi:chip but workspace tabs shows a data URL"

Normal. Hydrogen rewrites panelState.displayIcon after page load with whatever the page's favicon was (usually a data URL because some sites inline their favicons). This is the override in action.

How the adom-tsci app handles this

  1. src/cli/start.rs passes --display-icon "mdi:chip" to adom-cli hydrogen workspace add-tab — this shows the MDI chip icon for ~100ms while the page loads.
  2. src/assets/shell.html has <link rel="icon" type="image/svg+xml" href="favicon.svg">.
  3. src/server/mod.rs serves the favicon at /favicon.svg with the content of src/assets/icon.svg — a teal-colored (#00b8b0) custom SVG chip.
  4. When the shell loads, Hydrogen fetches favicon.svg, gets the teal chip SVG, and writes that into panelState.displayIcon.
  5. The tab now permanently shows the teal chip — because every future reload re-serves the same favicon.

The MDI mdi:chip placeholder and the served favicon.svg are visually similar by design — the transition is invisible. If they were different, you'd see a brief flash.

See also

  • ~/.claude/skills/adom/guides/adom-workspace-control.md — the full workspace API reference that documents displayIcon as a panelState field (but buries the favicon-override behavior).
  • ~/.claude/skills/adom/webview/SKILL.md — Web View panel actions (navigate, refresh, setHeaderHidden, setProxyEnabled).
  • ~/.claude/skills/adom/guides/app-creator.md — app conventions including the docs/icon.svg brand-icon requirement.
  • iconify MDI catalog — the searchable list of every mdi:<name>.

Sub-Skills
?
What are Sub-Skills?

Sub-skills are community-contributed AI skill extensions for this component. They teach AI assistants about specific tools, configurators, or workflows.

Examples:

  • A manufacturer’s configuration tool for a motor controller
  • A community-written design guide for an amplifier circuit
  • An automated test/validation script for a sensor module

How to add one: Click Add Sub-Skill, provide the URL to your skill and a brief description. Submissions are reviewed by the Adom team before going live.

No sub-skills yet. Be the first to contribute one!

0 revisions · Updated 2026-04-16 10:56:13