Hero Studio
Public Made by Adomby adom
The hero-image lab with a human gate: `hero-studio pose <owner/slug>` opens the studio in front of the human, posed for their package, and blocks until they click Generate, producing the provenance-stamped 2000x1250 PNG the registry's hero gate requires. The image carries the title and artwork; the exported image also bakes the type pill (top right) and full wiki slug (bottom right); the page shows the hero bare, and only the homepage marquee overlays its own dynamic info. Adom-org pages get the
Install?
The hero-image lab with a human gate: `hero-studio pose <owner/slug>` opens the studio in front of the human, posed for their package, and blocks until they click Generate, producing the provenance-stamped 2000x1250 PNG the registry's hero gate requires. The image carries the title and artwork; the exported image also bakes the type pill (top right) and full wiki slug (bottom right); the page shows the hero bare, and only the homepage marquee overlays its own dynamic info. Adom-org pages get the house wordmark and palette automatically; every other owner brings their own accent and background colors, with placement fixed for all. The floating app window is the showcase: it auto-loads a real screenshot from the package's wiki page (screenshots/, docs/), takes a manual import, or a full-hero import (the human-ratified re-stamp path for existing heroes). The pose gate opens in verification mode: per-item checklist (title, subtitle, showcase, type match) and a Generate that unlocks only fully confirmed. Includes showcase bleeds, brand tile themes, gradient angles, pixel-faithful wiki marquee and index-card previews, and a component-hero mode with a photo/raytrace/phong fallback ladder.
adom-wiki pkg install adom/hero-studio
Latest: v0.20.5, published
Contents
README
markdownHero Studio
A live playground for the hero image v2 definition: the lower third of every hero is a true-text overlay, rendered by the surface that shows it, never baked into the image.
The overlay carries the metadata that should stay dynamic and clickable: the type pill (APP / SKILL / BOOTSTRAP / COMPONENT), the trending score, the star count, the title, the author, and the wiki slug in the lower right. Because it is real text, every part of it can be a link, and the scores update daily without re-rendering a single PNG. The image part of the hero keeps the lower third text-free: the background gradient or brand tile simply continues to the bottom edge, and the app screenshot may bleed under the overlay zone knowing the scrim will cover it.
What you can flip, live
- Package: real pages from
adom-wiki page trending, with their live scores, stars, installs, authors, and tags. - Screenshot placement: bleed bottom, bleed right, bleed top, lower-right corner, upper-right corner, contained, and mirror (text right, window left). Mirror flips the whole background composition too: glows, tiles, and corner motifs.
- Background theme: six on-brand looks, including the authentic Kickstand tiling
patterns from the
adom/brandpage (concentric-arc onion corner, scattered pill field, outlined square grid) plus midnight dot-grid, PCB traces, and the flagship gradient. - Gradient angle: rotate the base gradient to make a hero feel unique while staying on-brand (default 155).
- Image-zone text: wordmark, big title, value-prop subtitle, detail line.
- Title placement: overlay only, image only, or both, to settle the redundancy question directly.

In-context previews, copied from the wiki source
The studio renders the same hero into pixel-faithful copies of the surfaces that will show it, so you judge the design where it actually lives:
- the wiki homepage marquee (
.ts-slidetiles: caption scrim, badge plates, trending and star pills, scrolling track), - the wiki index page card grid (
.page-card: 16:10 hero slot, badge colors, meta row, tag chips, install row), - an adom-desktop right bar showing the full v2 hero with its baked overlay.
The wiki surfaces receive the image part only, because the wiki already overlays its own true text. That is the core of the v2 idea: the overlay is per-surface chrome, and the homepage marquee already proves the pattern.

Component heroes
A separate mode for component pages, switched at the top of the panel ("What are you making"). A component hero leads with the physical part, not an app window:
- Image ladder: a real-world photo where the screenshot area would be; if none exists,
a raytraced render; last resort, the plain phong 3D viewport shot. The ladder is the
quality bar: the wiki's own
sm02b-srss-tbhero is currently the bottom tier. - Name where the title goes, and a plain-language spec line as the subtitle ("100k SMD 1% resistor").
- MPN placement: in the family chip row, under the name, or in the lower-third overlay next to the slug.
- Family chip ("JST · SH SERIES · 1.0 MM") in the eyebrow slot, following the adom-usb family-marker pattern.

The bundled component imagery is sample material for the lab: the photo tier is cropped from the john/adom-usb-sniffer-dap hero (a Wikimedia Commons photograph under its respective CC license), the phong tier is cropped from the live adom/sm02b-srss-tb hero, and the raytrace tier is an illustrative render. Swap in your own part's imagery when designing a real hero.
Run it
hero-studio # serves on port 8846
Open /proxy/8846/ in a webview (or http://localhost:8846 locally). The server itself
is plain Node with no dependencies; only Generate needs the renderer runtime below.
Refresh the sample data from the live wiki any time:
./refresh-data.sh # needs the adom-wiki CLI, then restart the server
Runtime requirements (Generate)
Generate renders headless Chrome INSIDE the container the server runs in. Light images (Hydrogen Desktop containers, for example) do not ship any of this, on purpose. What the render pipeline needs:
- puppeteer-core (npm). On Node below 22.12 pin
puppeteer-core@24; 25.x declaresengines: node >=22.12and can fail at launch rather than at import. - A Chrome binary:
npx @puppeteer/browsers install chrome@stable --path ~/.cache/puppeteer(that--pathputs it where the renderer scans), or pointCHROMEat any binary. - The browser's OS libraries (libnss3, libgbm1, libasound2t64 on noble, and friends); a Chrome binary that exists but cannot start is the classic light-container trap.
- python3 + PIL for the export downscale and provenance stamp.
hero-studio doctor checks all of it, including that Chrome actually launches, and prints
the exact fix commands for whatever is missing. Install runs it and warns loudly; pose
refuses to open the gate for a human until it passes. Whoever installed the package is
already inside the container, so the fixes never require outside access.
When the container cannot run Chrome but Adom Desktop answers, Generate falls back to
rendering through the HOST browser (pup): the host opens the render view via the
workspace proxy URL, screenshots it, and the hero is cropped and stamped container-side
(python3+PIL is the only container requirement on that path). The provenance stamp
records renderer: local or renderer: pup. Pin a leg with POST /generate {"renderer":"pup"} per request or the HERO_RENDERER env server-wide.
Generate
The Generate button (or POST /generate) renders the current hero server-side with
Puppeteer to the hero-standard 2000x1250 PNG, pops a toast and a preview modal in every
open studio, and writes generated/latest.png. Each PNG carries a comment metadata
chunk recording that hero-studio produced it, plus the exact studio state, so publish
tooling can verify a hero came through the studio rather than being hand-rolled slop.
The canonical flow for an agent is the pose gate: hero-studio pose <owner>/<slug>,
which opens the studio in front of the human and blocks until THEY click Generate. An
agent never calls POST /generate itself; a hero a human did not make should not exist.
Drive it (AI-first)
State lives on the server; the UI, the CLI, and any agent stay in lockstep through a live channel with a 1 second poll fallback (the SSE stream can be buffered by proxies).
GET /state # current studio state
POST /state # merge a partial state, e.g. {"theme":"onion","gradAngle":245}
GET /console # the page's console ring buffer (no DevTools needed)
POST /ui/toast # raise a toast: {"text":"...","kind":"info|success|error"}
GET /api/pages # the trending dataset the studio renders
Every control in the panel maps to a state field: page, layout, theme, gradAngle,
titleMode, show.*, overlay.*, guides.
