Component Hero
Public Made by Adomby adom
The Adom standard for a component page's 3D hero: teal dashed pad outlines, silkscreen with pin 1, signal names. Spec + deterministic generator.
Install?
The Adom standard (adom-hero 1.0) for a component page's annotated 3D hero, and a deterministic generator for it.
adom-wiki pkg install adom/component-hero
Latest: v0.1.2, published
Contents
- Why a standard
- Two files: the hero and the board-use model
- Scene structure
- Coordinates
- Materials
- Layer 1: pad outlines
- Layer 2: silkscreen and pin 1
- Layer 3: signal names
- Metadata: asset.extras.adomHero
- Sidecar: <slug>-hero.overlay.json
- Alignment guard
- Checks for a linter
- Building one
- Differences from the existing hand-built heroes
- Examples
- Open items
- Change log
README
markdownComponent hero standard (adom-hero 1.4)
Every component page on the wiki shows its part in 3D with the footprint drawn under it: the pads as teal dashed outlines, the silkscreen with pin 1, and each pad's signal name. This document defines that artwork exactly, so any person or AI builds the same thing, a linter can check it, and our factory can generate it for every page.
Status: 1.4, 2026-09-30 (see the change log at the end). Applied to 7 factory pages as a test (linked at the end). The generator is part
of this page's skill (skills/component-hero/), so any AI that installs it can build a conforming hero.


Why a standard
In September 2026, 48 of the wiki's 15,979 component pages had this artwork. All 48 were built by hand by
people's AIs following prose in the wiki-component skill. Three different styles exist, no generator was
ever published, and it only happened when someone showed their AI an example. The factory's 15,580 pages
had none.
The most common style, used on 45 pages by six authors, is the base for this standard. Call it style A. Its names and colours are kept exactly, so those 45 pages already conform on names and colours. What this version adds is precise geometry, pin-1 rules, a metadata block, a sidecar file and machine-checkable rules.
Two files: the hero and the board-use model
A component page ships two GLBs:
| file | purpose | page.json key |
|---|---|---|
<slug>-hero.glb |
presentation: chip + reference artwork | component.parts.model_3d |
the clean model (for factory pages <slug>-etched.glb) |
board use: downloads, EDA, assemblies | component.parts.model_3d_plain |
The wiki viewer shows model_3d by default. The artwork never goes into the board-use model: a part
dropped onto a board must not bring outlines and labels with it. This follows the wiki-component-lod
rule that every board-use GLB is free of footprint, silkscreen and label helpers.
The hero keeps the physical model untouched, including the virtual MPN marking (Adom.LaserEtch.MPN,
made by service-occt). The artwork is only added.
Scene structure
scene
├── <physical model root> unchanged from the board-use GLB
└── Adom reference artwork (nonphysical) node, no mesh
├── Footprint pads - teal dashed outlines - 50 percent opacity
├── Silkscreen reference lines - 30 percent opacity
└── Signal names - 50 percent opacity
- The three children are mesh nodes. Each mesh has one primitive, and that primitive's material carries the same name as the node.
- A child may be absent when it would be empty (for example, no labels on a ball-grid part). Its absence is recorded in the metadata.
- The artwork root sits at the scene root with an identity transform.
Coordinates
- Axes: glTF x = KiCad x, glTF y = −KiCad y, Z up, metres.
- Origin: the KiCad footprint origin, which is where KiCad places the part's 3D model.
- Plane: all artwork is flat at z = −0.02 mm, just below the seating plane, so it never fights the underside of the chip for depth.
Materials
All three materials are:
- unlit (
KHR_materials_unlit, and the extension is listed inextensionsUsed); alphaMode: BLEND;metallicFactor 0,roughnessFactor 1;doubleSided: truefor the pad outlines and silkscreen, anddoubleSided: falsefor the signal names, which carry two one-sided copies instead (see Layer 3).
| layer | material name (exact) | baseColorFactor (RGBA) |
|---|---|---|
| Pad outlines | Footprint pads - teal dashed outlines - 50 percent opacity |
[0, 0.902, 0.863, 0.5] (teal #00E6DC) |
| Silkscreen | Silkscreen reference lines - 30 percent opacity |
[0.92, 0.96, 1.0, 0.3] |
| Signal names | Signal names - 50 percent opacity |
[0.92, 0.96, 1.0, 0.5] |
"70% transparent silkscreen" means alpha 0.3. The outline colour is teal, not blue: every hero built so far
uses this teal, and the wiki-component skill specifies it.
Layer 1: pad outlines
- What is drawn: the copper perimeter of every pad on F.Cu or *.Cu. Solder-mask and paste openings are not drawn. Non-plated holes are skipped, and drills are not drawn.
- Shapes:
rectandtrapezoidare drawn as rectangles.roundrectuses corner radius =roundrect_rratio × min(w, h).circleandovalare drawn as circles and stadiums.customis drawn from its firstgr_polyprimitive, or from its anchor rectangle when it has none.- Pad rotation is applied, including its sign.
- Dashes: the outline is dashed as a closed path, and a dash may turn a corner.
- Let span be the largest dimension of the pad field, in mm, and at least 1.
- dash = clamp(0.025 × span, 0.12, 0.45) mm.
- gap = 0.6 × dash.
- stroke = clamp(0.006 × span, 0.03, 0.09) mm.
- Per-pad cap, so small pads still read as their shape: dash ≤ max(perimeter / 6, 0.05), and stroke ≤ max(perimeter / 25, 0.02).
- Geometry: each dash is one continuous ribbon of the stroke width, centred on the path, with mitred joins at every bend (mitre limit 4×). There are no gaps at bends and no overlapping triangles: overlaps double the alpha and show as bright seams. Curves (rounded corners, circles, ovals, silkscreen arcs) are sampled so that no straight piece is longer than 0.005 mm, so they stay smooth when zoomed in. Silkscreen strokes use the same ribbons. Meshes are indexed, so shared vertices are stored once.
- Worked example: a SOT-23-6 gives 0.12 mm dashes with a 0.03 mm stroke; an LQFP-48 gives about 0.23 mm dashes with a 0.054 mm stroke. On 0.3 mm BGA balls the per-pad cap keeps them as dashed circles.
- Why this weight: subtle, but visible at the wiki viewer's default zoom. The hand-built heroes' 0.015 mm stroke vanished there, so the 30% silkscreen was taken for the footprint; 1.1's 0.05 mm read as heavy.
Layer 2: silkscreen and pin 1
- Footprint silkscreen: every F.SilkS
fp_line,fp_arc(both the three-point and the angle form),fp_circle,fp_rectandfp_poly, at the footprint's own stroke width.- Solid-filled shapes and polygons are filled. A polygon with no fill setting counts as filled, because KiCad's pin-1 triangles are written that way.
- Silkscreen text (
REF**, the value) is not drawn.
- Pin 1:
- Footprint mark first. If the footprint's silkscreen already marks pin 1, that mark is the pin-1 indicator and nothing is added. A filled silkscreen shape counts as the mark when its centre is within 2.5 mm of pad 1 and no other pad is closer.
- Otherwise, an added dot. A filled dot goes on this layer:
- on parts with 3 or more signal pads, at pad 1 (or
A1); - on a 2-pad part, only when a pin is named
K,KA,CATHODEor+. The dot goes at that pin. Unpolarised 2-pad parts get no dot, because they have no orientation.
- on parts with 3 or more signal pads, at pad 1 (or
- Dot size and position: radius = clamp(0.22 × the smaller pad dimension, 0.1, 0.35) mm. It is placed 0.2 mm plus its radius beyond pad 1's outer end, along pad 1's row (its column for side rows). On a ball grid it goes on the diagonal, away from the grid's centre.
- Record: the metadata says which source marked pin 1, so an added dot is never mistaken for manufacturer evidence.
Layer 3: signal names
- Text:
- comes from the page's pinout (
component.pins, pad number → name), exactly as the datasheet spells it; - active-low
~{X}is drawn as X with an overbar; - when a pin has no real name (
~or empty), the pad number is shown, so every label stays unique. Never a repeated "Terminal".
- comes from the page's pinout (
- Font: DejaVu Sans Mono, filled glyphs with holes kept. Islands inside holes, such as the dot in the
zero, stay filled. The glyphs come pre-triangulated at font size 1 in
hero_glyphs.json(ASCII plus common symbols such as ±, µ, Ω, °, ×), so no font library is needed and every implementation draws identical text. A character not in the table is drawn as?. - Readable from both sides: the mesh has two primitives with the same single-sided material. The first faces up (counter-clockwise seen from above). The second is a copy mirrored across each label's own horizontal centre line, facing down, so it reads correctly from below, when the model is tipped over toward the viewer. Each copy is visible only from its own side.
- Which pads: each pad number is labelled once. There are no labels on:
- exposed or thermal pads. A pad counts as thermal when it is named
EP,PAD,TABor0, or when it is more than 4× the median pad area and sits inside the pad field on a part with 5 or more pads; - ball grids, meaning 16 or more pads with at least 4 distinct rows and 4 distinct columns, filling more than 60% of the grid. Labels there would sit under the body, and the metadata records why they were omitted.
- exposed or thermal pads. A pad counts as thermal when it is named
- Placement: outside the pad, on the side of the pad field it belongs to.
- Left and right rows are horizontal, and the text runs away from the part.
- Top and bottom rows are rotated 90° and read upward.
- A 2-pad part is labelled left and right.
- Size: label height = clamp(0.5 × pitch along its row, 0.12, 0.6) mm. On 2-pad parts it is clamp(0.7 × the pad's shorter side, 0.12, 0.6) mm. The gap from the pad is max(0.25 × height, 0.1) mm.
- Collisions: a label that would overlap a filled silkscreen shape (the footprint's pin-1 triangle, the added dot) steps outward past it.
Metadata: asset.extras.adomHero
The hero's glTF asset.extras carries one object. Here is the real block from adom/opa2325idgkt:
{
"spec": "adom-hero 1.4",
"mpn": "OPA2325IDGKT",
"kind": "component + footprint reference art",
"board_use": false,
"plane_z_mm": -0.02, "units": "metre", "upAxis": "Z",
"layers": {
"pad_outlines": { "material": "Footprint pads - teal dashed outlines - 50 percent opacity",
"rgba": [0, 0.902, 0.863, 0.5], "pads": 8,
"span_mm": 4.05, "dash_mm": 0.12, "gap_mm": 0.072, "pad_stroke_mm": 0.0300 },
"silkscreen": { "material": "Silkscreen reference lines - 30 percent opacity",
"rgba": [0.92, 0.96, 1.0, 0.3], "footprint_items": 3,
"pin1": { "source": "footprint silkscreen", "pad": "1" } },
"signal_names": { "material": "Signal names - 50 percent opacity",
"rgba": [0.92, 0.96, 1.0, 0.5], "font": "DejaVu Sans Mono",
"labels": 8, "fallback_to_pad_number": 0 }
},
"align": { "ok": true, "centre_offset_mm": 0.0, "tolerance_mm": 0.324, "orientation_flipped": false,
"contacts_bbox_mm": [-1.55, 1.55, -0.86, 0.86], "pads_bbox_mm": [-2.025, 2.025, -0.925, 0.925],
"seating_z_mm": 0.0 },
"sources": { "glb": "opa2325idgkt-etched.glb", "glb_sha256": "4b9b…e7bf",
"footprint": "opa2325idgkt.kicad_mod", "footprint_sha256": "dca7…75a8",
"pins": "page.json component.pins" },
"generator": "factory/hero_glb.py"
}
silkscreen.pin1is one of three things:{source: "footprint silkscreen", pad};{source: "added dot (AI)", pad, center_mm, r_mm};null, when the part has no orientation.
signal_names.omittedappears when labels were skipped, with the reason.
Sidecar: <slug>-hero.overlay.json
Next to the hero, the page ships a sidecar with:
- the same object as the metadata;
- every pad: number, shape, centre, size and rotation, all in footprint millimetres;
- every label: pad, text, anchor, alignment, orientation and height.
A reviewer or a tool can check the artwork without opening the GLB.
Alignment guard
The artwork is drawn from the footprint and the chip comes from its 3D model. If the model is offset or
turned relative to the footprint, the artwork would look authoritative and be wrong. So before a hero is
published, the chip's lowest geometry (its contacts) is compared with the pad field. The result is recorded
in align, and a hero is published only when ok is true. It fails when:
- The centres are too far apart. The limit is max(0.25 mm, 8% of the larger pad-field dimension).
- The orientation is swapped. This means one box is more than 1.25× longer in x than in y while the other is more than 1.25× longer in y than in x, which is what a model turned 90° looks like.
Width alone is not used: a leadless body (QFN, WSON) rests its whole underside on the seating plane.
Checks for a linter
A component page conforms when all of these hold. Each can be checked from the GLB's JSON chunk alone, without downloading the buffers.
component.parts.model_3dnames a.glbwhoseasset.extras.adomHero.specstarts withadom-hero 1..adomHero.board_useisfalse.component.parts.model_3d_plainnames a different GLB, and that GLB contains no node namedAdom reference artwork (nonphysical)and no material with any of the three layer names.- The hero has exactly one node named
Adom reference artwork (nonphysical)at the scene root, and its children are drawn only from the three layer names. - The node
Footprint pads - teal dashed outlines - 50 percent opacityexists. - Each layer's material has its exact name and
baseColorFactor, withalphaMode: BLENDandKHR_materials_unlit;doubleSidedis true for pad outlines and silkscreen and false for signal names, and the signal-names mesh has two primitives (up-facing and down-facing). adomHero.layers.pad_outlines.padsequals the number of copper pads in the page's.kicad_mod.adomHero.align.okistrue.- A part with 3 or more signal pads has a non-null
silkscreen.pin1. signal_namesis present unlesssignal_names.omittedgives a reason.
Checks 1 to 6 are presence and format. Checks 7 to 10 compare against the page's own files.
Building one
The generator in this page's skill (skills/component-hero/scripts/hero_glb.py, also the factory's) implements
everything above deterministically, with no model calls:
python3 hero_glb.py <board-use.glb> <footprint.kicad_mod> <page.json> <slug>-hero.glb [--png preview.png]
It needs hero_glyphs.json beside it. It prints one line: pads, silkscreen items, pin-1 source, labels and
the alignment verdict. It also writes
the sidecar next to the hero. --png writes a top and oblique preview for review. A hero is typically
50-300 KB and takes a few seconds to build.
To publish, add <slug>-hero.glb and <slug>-hero.overlay.json to the page, set model_3d and
model_3d_plain as described above, bump the version, publish, and push page.json last.
Differences from the existing hand-built heroes
- Kept: style A's layer and material names, colours and alphas, the separate hero file, the
-0.02 mmplane and the unlit materials. - Now exact: dash, gap and stroke sizes, label height and placement, the pin-1 rules, and the exposed-pad and ball-grid rules.
- Changed: the pad outlines are about 2× the hand-built heroes' stroke, so the footprint is visible at the viewer's default zoom, and each dash is one smooth continuous stroke.
- Added:
- the pin-1 dot on the silkscreen layer. John asked for it, and the one earlier attempt was a 3D block stuck on the chip;
- the
adomHerometadata and the sidecar; - the alignment guard;
- label collision avoidance.
- Not adopted:
- the
Adom.PadOutlines/Adom.PadLabels/Adom.Silkscreennaming on the three VL53 pages; - board-context
.insertion.glbcomposites. Those are useful, but a different asset.
- the
- Existing style A pages: they already match on names and colours. Adding
adomHerowould make them pass checks 1-2 and 7-10.
Examples
Built with this standard (2026-09-30):
- adom/tps54202ddcr: SOT-23-6
- adom/opa2325idgkt: VSSOP-8
- adom/tps62590drvr: WSON with an exposed pad
- adom/drv8313rhhr: QFN-36 with an exposed pad; one label steps past the footprint's pin-1 triangle
- adom/stm32g071c8t6: LQFP-48
- adom/1n4148w-7-f: SOD-123; cathode dot, K and A labels
- adom/lm1117dtx-1-8: TO-252; the tab is labelled VOUT
Hand-built style A, for comparison:
Open items
- Ball grids have no labels. A later version could label the outer ring outside the body, or offer labels as a viewer toggle.
- Through-hole drills are not drawn. Only the copper ring is.
- Custom pads use their first primitive only. Complex custom pads, such as some connector shields, may need the union of all primitives.
- Hero freshness. When a page's footprint or pinout changes, its hero must be rebuilt. The sidecar's source hashes let a lint rule detect a stale hero.
Change log
- 1.4 (2026-09-30): signal names readable from both sides: two single-sided copies, the underside one mirrored top-to-bottom. Colby, viewing from below, saw "WODE" and "ΛIN". Text now comes from a pre-triangulated glyph table, so the generator no longer needs a font library.
- 1.3 (2026-09-30): each dash is one continuous mitred ribbon, curves sampled to 0.005 mm, meshes indexed. Ray, zoomed in: "why is it not a continuous shape? and smooth?" The dashes were separate quads per segment, with wedge gaps and bright overlaps at rounded corners, and corners had 7 points per 90°.
- 1.2 (2026-09-30): outline weight between 1.0 and 1.1 (stroke 0.03-0.09 mm, dash 0.12-0.45 mm). Colby liked the subtle look; 1.0 vanished at default zoom. Ray chose the middle.
- 1.1 (2026-09-30): pad outlines bolder: stroke 0.015 to 0.05-0.15 mm, dash 0.07 to 0.18-0.6 mm. Colby asked whether the gray lines were the footprint: at 1.0 sizes the teal outlines vanished at the viewer's default zoom and only the silkscreen showed.
- 1.0 (2026-09-30): first version, unified from the 45 hand-built style A heroes.