component
RC0402FR-0733KL - YAGEO
Public Made by Adomby adom
Thick film chip resistor 33 kOhm +/-1 %, 1/16 W, 50 V, 0402 (1005 metric)
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
"""Write README.md, land-pattern/README.md, page.json, package.json, models.json,
provenance.json, verification.json and LICENSE for one built page.
usage: records.py <slug>
Run once after build.py (page.json is needed by finish.py), then again after
finish.py so the hero, .lbr and Altium files are hashed and described.
"""
import sys, os, json, hashlib, re, math
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from parts import PARTS, TODAY, MOUNT
ROOT = "/tmp/claude-1001/esc3"
slug = sys.argv[1]
P = next(p for p in PARTS if p["slug"] == slug)
OUT = os.path.join(ROOT, "pages", slug)
MPN = P["mpn"]; OWNER = "adom"
B = json.load(open(os.path.join(ROOT, "work", f"{slug}-build.json")))
STEP, FP, SYM, MARKED = B["step"], B["fp"], B["sym"], B.get("marked")
check, land = B["check"], json.load(open(os.path.join(OUT, "land-pattern/land-check.json")))
lod = json.load(open(os.path.join(OUT, "lod/manifest.json")))
figs = json.load(open(os.path.join(OUT, "docs/figures/figures.json")))
def p_(f): return os.path.join(OUT, f)
ex = lambda f: os.path.exists(p_(f))
sha = lambda f: hashlib.sha256(open(p_(f), "rb").read()).hexdigest()
def blob(f):
b = open(p_(f), "rb").read(); return hashlib.sha1(b"blob %d\0" % len(b) + b).hexdigest()
D = P["dist"]
by = {"name": "Claude (AI agent) for John Lauer", "handle": "john"}
KICAD_SRC = f"KiCad packages3D {P['fp_lib']}.3dshapes/{P['fp']}.step (CC-BY-SA 4.0 with the KiCad library exception)"
KICAD_FP_SRC = f"KiCad standard library {P['fp_lib']}:{P['fp']} (CC-BY-SA 4.0 with the KiCad library exception)"
GL = "https://gitlab.com/kicad/libraries"
ds = P["ds"]
HERO = f"{slug}-hero.glb"; HERO_SIDE = f"{slug}-hero.overlay.json"; HERO_PNG = "docs/verify/hero-preview.png"
LBR = f"{MPN}.lbr"; SCH = f"altium/{MPN}.SchLib"; PCB = f"altium/{MPN}.PcbLib"; HUB = f"{MPN}.adom-lbr.json"
have_hero, have_alt, have_lbr = ex(HERO), ex(SCH) and ex(PCB), ex(LBR)
code = P.get("marking_code")
sz = P["package"].split()[0]
def F(name): return f"docs/figures/{name}"
# ---------------- land pattern text ----------------
L = P["land"]
rows = land["rows"]
t = "| Dimension | KiCad footprint | YAGEO recommendation | Difference |\n|---|---|---|---|\n"
for r in rows:
t += f"| {r['dim']} | {r['kicad_mm']:.2f} mm | {r['maker_nominal']:.2f} mm | {r['difference_mm']:+.2f} mm |\n"
maxd = max(abs(r["difference_mm"]) for r in rows)
k = land["kicad"]
if maxd <= 0.06:
land_verdict = (f"The KiCad pads are within {maxd:.2f} mm of every YAGEO value (YAGEO prints nominal values only, with a placement "
f"accuracy of {L['placement']} mm), so the footprint matches the maker's pattern for practical purposes.")
land_status = "matches"
else:
gapd = next(r['difference_mm'] for r in rows if r['dim'].startswith('gap'))
land_verdict = (f"The KiCad pads differ from YAGEO's nominal land by up to {maxd:.2f} mm: KiCad's pads are {k['len']:.2f} mm long and "
f"{k['wid']:.2f} mm wide (YAGEO {L['len_b']:.2f} x {L['wid_c']:.2f} mm), so KiCad's copper is shorter and wider, and the overall "
f"length is {k['overall']:.2f} mm against YAGEO's {L['overall']:.2f} mm. The gap between pads differs by {gapd:+.2f} mm. "
"KiCad generates this footprint to IPC-7351 nominal density (its own description says so), not to YAGEO's table. Both lands "
"cover the underside terminal (I2 0.25 +/-0.15 mm) with margin and both are usual reflow patterns. A design that wants YAGEO's "
f"exact land should make each pad {L['len_b']:.2f} mm long and {L['wid_c']:.2f} mm wide with pad centres "
f"{L['gap_a'] + L['len_b']:.2f} mm apart.")
land_status = "differs from maker (KiCad IPC nominal)"
land_readme = f"""# Land pattern check: {MPN}
The footprint on this page is KiCad's standard library footprint `{P['fp_lib']}:{P['fp']}`, renamed to
`{FP.replace('.kicad_mod','')}` so it can sit beside other parts in one library folder. The copper is unchanged.
This page compares those pads with the land pattern YAGEO recommends for reflow soldering.

Grey is the part body at its datasheet nominal size, teal is the KiCad copper and the dashed amber outline is
YAGEO's recommended land at its printed nominal size.
## Numbers
{t}
YAGEO's letters: {L['letters']}. YAGEO's placement accuracy for this size: {L['placement']} mm.
Source: {L['source']} ([PDF](../{MOUNT['file']})).
})
## Result
{land_verdict}
KiCad pad centres are at +/-{abs(k['overall'] - k['len']) / 2:.3f} mm, pad size {k['len']:.2f} x {k['wid']:.2f} mm,
rounded rectangle (corner ratio 0.25). The numbers are in [land-check.json](land-check.json); the drawing is made by
`provenance/tools/landcheck.py` from the footprint file and YAGEO's table.
"""
open(p_("land-pattern/README.md"), "w").write(land_readme)
# ---------------- verification.json ----------------
entries = []
ck = [{"text": f"{c['dim']}: model {c['model_mm']:.3f} mm, datasheet {c['datasheet_min']:.2f} to {c['datasheet_max']:.2f} mm", "result": "pass" if c["pass"] else "fail"} for c in check["checks"]]
ck.append({"text": "Z-up, seated on z = 0, centred on the footprint origin, long axis on X", "result": "pass"})
ck.append({"text": "no YAGEO STEP is reachable by plain HTTP for this part number (the product page builds its CAD links in the browser); the model is KiCad's library package, bytes unchanged, checked against the datasheet table", "result": "note"})
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "3D model matches the datasheet package dimensions",
"scope": ["3d-model"], "variants": ["*"], "checks": ck,
"evidence": [{"label": "overlay (top, bottom, side, end at true scale)", "href": f"docs/verify/{slug}-overlay.png"},
{"label": "numbers", "href": f"docs/verify/{slug}-check.json"},
{"label": "datasheet p.4 Table 1", "href": F("rc-p04-dimensions.png")},
{"label": f"datasheet ({ds['title']})", "href": ds["file"]}],
"files": {STEP: sha(STEP), ds["file"]: sha(ds["file"])}})
lck = [{"text": f"{r['dim']}: KiCad {r['kicad_mm']:.2f} mm, YAGEO {r['maker_nominal']:.2f} mm (difference {r['difference_mm']:+.2f} mm)",
"result": "pass" if abs(r["difference_mm"]) <= 0.06 else "note"} for r in rows]
entries.append({"date": TODAY, "by": by, "status": "verified" if land_status == "matches" else "open",
"title": "Footprint compared with YAGEO's recommended land pattern" + ("" if land_status == "matches" else " (KiCad IPC pads differ from YAGEO's nominal)"),
"scope": ["footprint"], "variants": ["*"], "checks": lck,
"evidence": [{"label": "comparison drawing", "href": "land-pattern/land-pattern.png"}, {"label": "numbers", "href": "land-pattern/land-check.json"},
{"label": "write-up", "href": "land-pattern/README.md"}, {"label": "YAGEO Mounting p.4", "href": F("mount-p04-land.png")}],
"files": {FP: sha(FP)}})
if code:
mk_checks = [{"text": f"{P['marking']} ({P['marking_src']})", "result": "pass"},
{"text": f"the marked display copy {MARKED} adds the code {code} as a separate flat solid group (Adom.LaserEtch) 5 um above the top coat, reading along the long axis; the unmarked KiCad STEP is kept for board CAD", "result": "pass"},
{"text": "the code was derived from the EIA-96 table (value = 100 x 10^((n-1)/96), rounded); YAGEO's separate 'Chip resistors marking' sheet was not reachable to confirm it", "result": "note"},
{"text": "real parts may be placed either way round; the code's reading direction on a board is not fixed", "result": "note"},
{"text": "no AI-added part-number etch: the real marking is the identification shown", "result": "pass"}]
mk_files = {MARKED: sha(MARKED), STEP: sha(STEP)}
else:
mk_checks = [{"text": f"{P['marking']} ({P['marking_src']})", "result": "pass"},
{"text": "no AI-added part-number etch on any model (a 1.0 x 0.5 mm top has no room for a readable 15-character MPN)", "result": "pass"}]
mk_files = {STEP: sha(STEP)}
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Marking" + (f": datasheet code {code} on the top coat" if code else ": the real part is unmarked"),
"scope": ["3d-model", "marking"], "variants": ["*"], "checks": mk_checks,
"evidence": [{"label": "datasheet p.3 Marking", "href": F("rc-p03-marking.png")}], "files": mk_files})
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Board-use LOD GLBs are clean and share the STEP pose",
"scope": ["lod"], "variants": ["*"],
"checks": [{"text": "four levels written, read back, bounds equal the STEP (Z-up, metres, seat z = 0)", "result": "pass"},
{"text": "no footprint, pad outline, label or silkscreen helpers; terminals present at every level", "result": "pass"},
{"text": (f"marking code {code} kept in high and medium, omitted in low and super-low (unreadable there)" if code else "no marking at any level (the part has none)"), "result": "pass"},
{"text": "previews looked at by the AI agent, not yet by a person", "result": "note"}],
"evidence": [{"label": "manifest", "href": "lod/manifest.json"}],
"files": {lv["path"]: lv["sha256"] for lv in lod["levels"]}})
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Pin 1, polarity and symbol",
"scope": ["footprint", "3d-model", "symbol"], "variants": ["*"],
"checks": [{"text": "non-polar two-terminal resistor: pads 1 and 2 are interchangeable; symbol pins 1 and 2 map to pads 1 and 2", "result": "pass"},
{"text": "symbol pin ends at (0, +5.08) and (0, -5.08) mm, on the 2.54 mm grid", "result": "pass"},
{"text": "symbol fields MPN, Manufacturer, Mouser, DigiKey, LCSC, Datasheet and Footprint filled", "result": "pass"},
{"text": "model terminals sit on the footprint pads (both centred on the origin, long axis on X)", "result": "pass"}],
"evidence": [], "files": {FP: sha(FP), SYM: sha(SYM), STEP: sha(STEP)}})
if have_hero:
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Hero GLB built to the adom-hero standard",
"scope": ["3d-model", "hero"], "variants": ["*"],
"checks": [{"text": "built with component-hero hero_glb.py from package-reference.glb, the footprint and page.json; alignment check OK", "result": "pass"},
{"text": "teal dashed pad outlines (alpha 0.5), silkscreen (alpha 0.3) and pad-number labels 1 and 2 (alpha 0.5); no pin-1 dot because the part is non-polar", "result": "pass"},
{"text": "preview looked at by the AI agent; the live wiki viewer still needs a person's look", "result": "note"}],
"evidence": [{"label": "preview", "href": HERO_PNG}, {"label": "overlay record", "href": HERO_SIDE}],
"files": {HERO: sha(HERO), "package-reference.glb": sha("package-reference.glb")}})
if have_alt or have_lbr:
fl = {f: sha(f) for f in (LBR, SCH, PCB, HUB) if ex(f)}
entries.append({"date": TODAY, "by": by, "status": "verified", "title": "Fusion and Altium libraries generated from the KiCad symbol and footprint",
"scope": ["symbol", "footprint"], "variants": ["*"],
"checks": [{"text": "adom-lbr generate --part-metadata page.json: .lbr lint passed (MPN, MANUFACTURER, MOUSER_PN, DIGIKEY_PN, LCSC_PN attributes)", "result": "pass"},
{"text": "adom-lbr import-kicad then assemble-altium --no-dedupe: native .SchLib and .PcbLib written, STEP body embedded (models.embedded 1); the KiCad fields carried as Altium parameters", "result": "pass"},
{"text": "not yet opened in Fusion or Altium (no desktop app used for this page)", "result": "note"}],
"evidence": [], "files": fl})
ver = {"schema": "adom/verification@1", "part": MPN, "variants": [], "entries": entries}
json.dump(ver, open(p_("verification.json"), "w"), indent=1)
# ---------------- models.json ----------------
MK = {"text": code, "surface": "top coat", "colour": "light grey on black"} if code else None
models = [
{"path": STEP, "format": "step", "title": "Package model (STEP)", "status": "current", "slot": "step", "variant": "plain", "role": "derived",
"use": ["board-cad"], "marking": None,
"unique": "The board CAD model: KiCad library package geometry (bytes unchanged), checked against the datasheet table, " + ("unmarked" if code else "no marking (the part has none)"),
"source": KICAD_SRC, "sha256": sha(STEP), "git_blob": blob(STEP), "bytes": os.path.getsize(p_(STEP)), "thumb": "docs/models/step-plain.png"},
]
if code:
models.append({"path": MARKED, "format": "step", "title": f"Package model with marking {code} (STEP)", "status": "current", "slot": "step_marked", "variant": "etched",
"role": "derived", "use": ["render", "board-cad"], "marking": MK,
"unique": f"The same KiCad package plus the datasheet marking code {code} as a flat solid group on the top coat (step2glb laser-etch, flat mode)",
"derived_from": STEP, "source": KICAD_SRC + " + YAGEO marking code from the datasheet",
"sha256": sha(MARKED), "git_blob": blob(MARKED), "bytes": os.path.getsize(p_(MARKED)), "thumb": "docs/models/package-reference-step.png"})
models.append({"path": "package-reference.glb", "format": "glb", "title": "Package model (GLB)", "status": "current", "slot": "model_3d_plain", "variant": "plain", "role": "derived",
"use": ["render", "board-insertion"], "marking": MK,
"derived_from": MARKED or STEP, "unique": "Clean board-use model for viewers (step2glb), no footprint artwork" + (f", marking {code}" if code else ""),
"source": KICAD_SRC, "sha256": sha("package-reference.glb"), "git_blob": blob("package-reference.glb"), "bytes": os.path.getsize(p_("package-reference.glb"))})
if have_hero:
models.append({"path": HERO, "format": "glb", "title": "Hero model (GLB)", "status": "current", "slot": "model_3d", "variant": "hero", "role": "derived",
"use": ["wiki-hero"], "marking": MK, "derived_from": "package-reference.glb",
"unique": "The page's 3D view: the package plus teal dashed pad outlines, silkscreen and pad-number labels from the footprint (adom-hero standard)",
"source": "component-hero hero_glb.py", "sha256": sha(HERO), "git_blob": blob(HERO), "bytes": os.path.getsize(p_(HERO)), "thumb": HERO_PNG})
for lv in lod["levels"]:
models.append({"path": lv["path"], "format": "glb", "title": f"Board LOD, {lv['level']}", "status": "current", "variant": "lod", "role": "derived",
"use": ["board-insertion", "render"], "marking": MK if lv["level"] in ("high", "medium") else None,
"derived_from": MARKED or STEP,
"unique": f"{lv['level']} detail for board and scaffold viewers: {lv['triangles']} triangles, {lv['primitives']} primitives",
"thumb": lv["preview"]["path"], "source": KICAD_SRC, "sha256": lv["sha256"], "git_blob": blob(lv["path"]), "bytes": lv["sizeBytes"]})
json.dump({"schema": "adom/models@1", "part": MPN, "models": models, "updated": TODAY}, open(p_("models.json"), "w"), indent=1)
# ---------------- LICENSE ----------------
open(p_("LICENSE"), "w").write(f"""{MPN} component page
Original Adom content on this page (README text, the KiCad symbol {SYM}, the
verification drawings, the JSON records and the scripts in provenance/tools/)
is licensed under the Creative Commons Attribution 4.0 International License
(CC-BY-4.0): https://creativecommons.org/licenses/by/4.0/
Third-party files keep their own terms and are not relicensed by this page:
- {FP} and {STEP} (and every model derived from it: {(MARKED + ', ') if MARKED else ''}package-reference.glb,
{HERO}, lod/*.glb) are KiCad library content, CC-BY-SA 4.0 with the KiCad
library exception ({GL}/kicad-footprints, {GL}/kicad-packages3D).
The footprint geometry inside {LBR} and altium/{MPN}.PcbLib comes from the
same KiCad footprint and keeps that license.
- The PDFs in docs/ and the page crops in docs/figures/ are YAGEO documents,
copyright of their publisher, included unchanged (or cropped) for reference.
""")
# ---------------- README ----------------
spec_tbl = "| Parameter | Value | Datasheet |\n|---|---|---|\n" + "".join(f"| {a} | {b} | {c} |\n" for a, b, c in P["spec_rows"])
res_rows = [("Product page", P["product_url"]), ("Datasheet", f"{ds['title']}, [PDF]({ds['file']}) ([source]({ds['url']}))"),
("Mounting and land pattern", f"{MOUNT['title']}, [PDF]({MOUNT['file']}) ([source]({MOUNT['url']}))"),
("Marking and packing", "YAGEO's separate 'Chip resistors marking' and 'Chip resistors packing' sheets, named on p.3 and p.7 of the datasheet (not included here)")]
res_tbl = "| Resource | Link |\n|---|---|\n" + "".join(f"| {a} | {b} |\n" for a, b in res_rows)
dist_tbl = ("| Distributor | Part number | Stock seen " + TODAY + " |\n|---|---|---|\n"
+ "".join(f"| {n} | [{D[kk][0]}]({D[kk][1]}) | {D[kk][2]:,} |\n" for kk, n in (("mouser", "Mouser"), ("digikey", "DigiKey"), ("lcsc", "LCSC / JLCPCB"))))
notes = "".join(f"- {n}\n" for n in P["notes"])
fail_bits = ", ".join(f"{c['dim']} {c['model_mm']:.3f} mm (datasheet {c['datasheet_min']:.2f} to {c['datasheet_max']:.2f})" for c in check["checks"])
card_three = (f"The footprint is KiCad's standard `{P['fp']}`, and this guide lays its pads over YAGEO's recommended reflow land, at true scale. "
+ ("It matches YAGEO closely. " if land_status == "matches" else "KiCad's pads are shorter and wider than YAGEO's nominal land, and the guide shows by how much. ")
+ "Use it to decide whether to keep the KiCad pads or change them to YAGEO's numbers before layout.")
v_rated, v_pr = P["v_rated"], P["v_pr"]
if v_pr >= P["vmax"]:
volt_para = (f"For this value the voltage limit governs, not power: sqrt(P x R) = sqrt({P['power']} W x {P['value']}) = {v_pr:.0f} V, "
f"so the {sz} size's maximum working voltage of **{P['vmax']} V** is the continuous limit. At {P['vmax']} V the resistor dissipates only "
f"{P['vmax'] ** 2 / P['ohms'] * 1000:.1f} mW. The maximum overload voltage is {P['vover']} V; the short time overload test applies "
f"{min(2.5 * v_rated, P['vover']):.0f} V for 5 s (p.9).")
else:
volt_para = (f"For this value power governs: sqrt(P x R) = sqrt({P['power']} W x {P['value']}) = **{v_pr:.1f} V** continuous, below the {sz} size's "
f"{P['vmax']} V maximum working voltage. The maximum overload voltage is {P['vover']} V; the short time overload test applies "
f"{min(2.5 * v_rated, P['vover']):.0f} V for 5 s (p.9).")
mark_para = (f"YAGEO marks RC0603 1 % parts with the three-character EIA-96 code (p.3, Fig. 3). For {P['value']} the code is **{code}**: "
f"{P['marking_short'].split('(')[1].rstrip(')')}. The code is printed light on the black top coat and may read either way round on a board."
if code else "YAGEO does not mark RC0402 parts (p.3, Fig. 1): the top coat is plain.")
model_para = (f"No YAGEO STEP for this exact part number could be downloaded by plain HTTP: YAGEO's product pages build their CAD links in the "
f"browser and expose no direct STEP link. The page therefore uses KiCad's library model for the package, `{P['fp']}.step`, with its "
f"bytes unchanged, renamed `{STEP}`, after checking it against the datasheet table (next section). ")
if code:
model_para += (f"Because the real part carries the marking {code}, a display copy `{MARKED}` adds that code as a flat solid group "
"(`Adom.LaserEtch`) 5 um above the top coat, made with the step2glb service's laser-etch endpoint; the body is untouched. "
"The GLB, the hero and the high and medium board LODs come from the marked copy; the unmarked STEP stays the board CAD file.")
else:
model_para += "The part is unmarked, so the model shows a plain top coat."
hero_para = (f"""
The page viewer shows `{HERO}`: the clean model plus nonphysical reference artwork drawn under it to the adom-hero
standard (adom/component-hero): the footprint's pads as teal dashed outlines at 50 % opacity, its silkscreen at 70 %
transparency and the pad numbers 1 and 2 (the terminals have no names). The part is non-polar, so no pin-1 dot is added.
The artwork never goes into the STEP, `package-reference.glb` or the board LODs.

""" if have_hero else "")
cad_rows = [(f"`{SYM}`", "KiCad symbol (standard resistor graphic, pins on the 2.54 mm grid) with MPN, Manufacturer, Mouser, DigiKey and LCSC fields"),
(f"`{FP}`", f"KiCad footprint (KiCad library `{P['fp']}`, renamed; model path `${{KIPRJMOD}}/{STEP}`)")]
if have_lbr: cad_rows.append((f"`{LBR}`", "Fusion / EAGLE library made with `adom-lbr generate` (attributes MPN, MANUFACTURER, MOUSER_PN, DIGIKEY_PN, LCSC_PN)"))
if have_alt: cad_rows.append((f"`{SCH}`, `{PCB}`", f"Altium symbol and footprint libraries (native binary) made with `adom-lbr import-kicad` and `assemble-altium` (the PcbLib embeds the STEP body); `{HUB}` is the adom-lbr hub record"))
cad_rows.append((f"`{STEP}`", "3D package model, STEP (KiCad library bytes)"))
if code: cad_rows.append((f"`{MARKED}`", f"3D package model with the marking {code}, STEP"))
cad_rows.append(("`package-reference.glb`", "3D package model, GLB (clean, for board viewers)"))
if have_hero: cad_rows.append((f"`{HERO}`", "the page's 3D view: package plus footprint pad outlines, silkscreen and pad labels"))
cad_rows.append(("`lod/`", "board-use GLBs in four levels of detail, with previews and manifest"))
cad_tbl = "| File | What it is |\n|---|---|\n" + "".join(f"| {a} | {b} |\n" for a, b in cad_rows)
fig_tbl = "| Figure | Source |\n|---|---|\n" + "".join(f"| [{f['caption']}]({f['file']}) | {f['document']}, p.{f['page']} |\n" for f in figs)
readme = f"""# {MPN}
YAGEO {MPN}: {P['brief']}. A general purpose thick film chip resistor from YAGEO's RC_L series.
::adom-verified{{src="/{OWNER}/{slug}/render/verification.json"}}
| Field | Value |
|---|---|
| Manufacturer | {P['mfr_full']} |
| Manufacturer part number | {MPN} |
| Type | {P['subcategory']} |
| Value | {P['value']} |
| Tolerance | {P['tol']} |
| Voltage | {P['voltage']}; {v_rated:.1f} V continuous at this value |
| {P['rating_row'][0]} | {P['rating_row'][1]} |
| Operating temperature | {P['op_temp']} |
| Package | {P['package']} |
| Marking | {P['marking_short']} |
| Datasheet | [{ds['title']}]({ds['file']}) |
## Key specifications
{spec_tbl}
All page numbers refer to the datasheet PDF in [docs/]({ds['file']}).
## Voltage rating
YAGEO rates the continuous working voltage as sqrt(P x R) or the maximum working voltage, whichever is less (p.7).
{volt_para}


## Notes
{notes}
## Ordering
{dist_tbl}
Stock figures are a snapshot from the Adom parts search on {TODAY}; check the distributor before ordering. Packaging code
R with reel code 07 is a 7 inch paper tape reel of {P['reel']:,} pieces (p.7 Table 4).
## Manufacturer and resources
{res_tbl}
## Pins
| Pin | Function |
|---|---|
| 1 | terminal (non-polar) |
| 2 | terminal (non-polar) |
A resistor has no polarity and no pin 1 orientation: either terminal may face either way.
## Marking
{mark_para}

## Land pattern: KiCad footprint vs YAGEO
<table>
<tr>
<td width="104"><a href="land-pattern/README.md"><img src="land-pattern/land-pattern-icon.png" width="112" alt="Land pattern"></a><br><sub> Land pattern </sub></td>
<td>{card_three}<br><br><a href="land-pattern/README.md">The comparison, with the numbers</a></td>
</tr>
</table>
## 3D model
{model_para}
{hero_para}
::adom-models{{src="/{OWNER}/{slug}/render/models.json"}}
## Model checked against the datasheet
The KiCad model was rendered in orthographic top, bottom, side and end views at true scale and laid over a drawing made
at the same scale from the printed table (nominal outline, tolerance limits, allowed terminal band). Every dimension is
inside the printed range: {fail_bits}. The model is Z-up, seated on z = 0, centred on the footprint origin, long axis on X.

Source: {ds['title']}, {P['dims_text']}.
## Board levels of detail
Clean board-use GLBs (no footprint pads, outlines, labels or silkscreen) in four levels, all in the same Z-up, metre,
footprint-origin pose as the STEP. {('The marking ' + code + ' shows in high and medium and is left out of low and super-low, where it cannot be read. ') if code else ''}Previews are rendered from each GLB.
::adom-component-lod{{src="/{OWNER}/{slug}/render/lod/manifest.json"}}
## CAD files
{cad_tbl}
## Datasheet figures
The pages this record cites, cropped from the PDFs:
{fig_tbl}
## Sources and license
- YAGEO: {ds['title']} ({ds['url']})
- YAGEO: {MOUNT['title']} ({MOUNT['url']})
- KiCad libraries: [{P['fp_lib']}.pretty/{P['fp']}.kicad_mod]({GL}/kicad-footprints/-/blob/master/{P['fp_lib']}.pretty/{P['fp']}.kicad_mod), [{P['fp_lib']}.3dshapes/{P['fp']}.step]({GL}/kicad-packages3D/-/blob/master/{P['fp_lib']}.3dshapes/{P['fp']}.step)
- Distributor numbers: Mouser, DigiKey and JLCPCB/LCSC through the Adom parts search, {TODAY}
Original Adom content is CC-BY-4.0. The KiCad footprint and 3D files keep their upstream license (CC-BY-SA 4.0 with the
KiCad library exception) and the PDFs remain YAGEO's documents; see [LICENSE](LICENSE).
[provenance.json](provenance.json) records every source and file hash; the scripts that built the checks are in `provenance/tools/`.
This is a catalog record for the part, not a manufacturing approval: check YAGEO's current datasheet for your design.
"""
readme = re.sub(r"\n{3,}", "\n\n", readme)
for bad in ("—", "–"):
assert bad not in readme and bad not in land_readme, "dash in README"
open(p_("README.md"), "w").write(readme)
# ---------------- page.json / package.json ----------------
title = f"{MPN} - {P['mfr']}"
parts_ = {"symbol": SYM, "footprint": FP, "step": STEP, "model_3d": HERO if have_hero else "package-reference.glb",
"model_3d_plain": "package-reference.glb", "datasheet": ds["file"]}
if have_lbr: parts_["lbr"] = LBR
if code: parts_["step_marked"] = MARKED
if have_alt: parts_.update({"altium_schlib": SCH, "altium_pcblib": PCB})
component = {
"mpn": MPN, "manufacturer": P["mfr"], "package": P["package"], "category": P["category"], "subcategory": P["subcategory"],
"pin_count": 2, "body_size": P["body_mm"],
"value": P["value"], "tolerance": P["tol"], "rating": P["voltage"], "power": P["power_txt"] + " at 70 C",
"max_working_voltage_v": P["vmax"], "max_overload_voltage_v": P["vover"], "continuous_voltage_at_value_v": round(v_rated, 1),
"pins": [{"number": "1", "name": "~"}, {"number": "2", "name": "~"}],
"parts": parts_,
"manufacturer_links": {"product": P["product_url"], "datasheet_pdf": ds["url"], "mounting_pdf": MOUNT["url"]},
"distributor_links": {kk: {"part": D[kk][0], "url": D[kk][1]} for kk in ("mouser", "digikey", "lcsc")},
"marking": {"text": code, "statement": P["marking"], "source": P["marking_src"]},
"provenance": {"model_3d": "KiCad library model, checked against the datasheet table" + (f"; marking {code} added from the datasheet" if code else ""),
"footprint": "KiCad standard library", "land_pattern_check": f"land-pattern/README.md ({land_status})", "omitted": []},
}
tags = ["hardware", "component", "passive", "resistor", sz, "yageo", "thick-film"]
triggers = [MPN, MPN.lower(), f"{P['value']} {sz} resistor", f"{P['value_sym']} {sz} 1%"]
eda = {"kicad": {"symbol": SYM, "footprint": FP, "model": STEP, "provenance": "generated"}}
if have_lbr: eda["fusion"] = {"lbr": LBR, "provenance": "generated"}
if have_alt: eda["altium"] = {"schlib": SCH, "pcblib": PCB, "provenance": "generated"}
page = {"slug": slug, "title": title, "eda_assets": eda, "type": "hardware", "kind": "component", "version": "0.1.0",
"description": P["brief"], "brief": P["brief"], "tags": tags, "discovery_triggers": triggers, "dependencies": {},
"license": "CC-BY-4.0", "hero": {"path": "docs/hero.png", "chrome": False},
"component": component, "visibility": {"public": True}}
json.dump(page, open(p_("page.json"), "w"), indent=1)
pkg = {"name": slug, "title": title, "version": "0.1.0", "description": P["brief"], "type": "hardware", "kind": "component",
"license": "CC-BY-4.0", "files": []}
json.dump(pkg, open(p_("package.json"), "w"), indent=1)
# ---------------- provenance.json (hashes of everything except itself) ----------------
files = {}
for dp, dn, fn in os.walk(OUT):
for f in fn:
rel = os.path.relpath(os.path.join(dp, f), OUT)
if rel != "provenance.json":
files[rel] = sha(rel)
finp = os.path.join(ROOT, "work", f"{slug}-finish.json")
fin = json.load(open(finp)) if os.path.exists(finp) else {}
prov = {
"manufacturer_reference": P["product_url"],
"symbol_source": "Original, written for this page (standard resistor graphic, non-polar, pin ends on the 2.54 mm grid). CC-BY-4.0.",
"footprint_source": KICAD_FP_SRC + f"; renamed {P['fp']} -> {FP[:-10]}, model path set to ${{KIPRJMOD}}/{STEP}; copper unchanged",
"footprint_upstream_sha256": hashlib.sha256(open(os.path.join(ROOT, "dl/kicad", P["fp"] + ".kicad_mod"), "rb").read()).hexdigest(),
"footprint_upstream_url": f"{GL}/kicad-footprints/-/raw/master/{P['fp_lib']}.pretty/{P['fp']}.kicad_mod",
"package_source": KICAD_SRC,
"package_upstream_url": f"{GL}/kicad-packages3D/-/raw/master/{P['fp_lib']}.3dshapes/{P['fp']}.step",
"package_upstream_sha256": hashlib.sha256(open(os.path.join(ROOT, "dl/kicad", P["fp"] + ".step"), "rb").read()).hexdigest(),
"package_bytes_unchanged": True,
"manufacturer_step": {"found": False, "searched": TODAY,
"note": f"The YAGEO product page ({P['product_url']}) was fetched by plain HTTP: it contains no STEP, STP or CAD-model link (its CAD links are built in the browser). No browser was used, so KiCad's library model was used and checked against the datasheet."},
"geometry_status": "KiCad library package geometry, every printed dimension checked against the datasheet (docs/verify). Not manufacturer-issued CAD.",
"marking": {"real_marking": code, "statement": P["marking"], "source": P["marking_src"],
**({"display_step": MARKED, "tool": B["etch"]} if code else {})},
"frame": {"units": "mm (STEP), metres (GLB)", "up_axis": "Z", "seat_z": 0, "origin": "footprint origin", "transform": "none"},
"glb": {"tool": "step2glb convert", "source": MARKED or STEP, "exit": 0, "stderr_tail": B["glb_stderr"]},
"hero_image": {"tool": "step2glb thumbnail --width 1600 --height 1000 (iso, 16:10)", "source": MARKED or STEP, "path": "docs/hero.png"},
"hero_glb": fin.get("hero"),
"fusion_lbr": fin.get("lbr"),
"altium": fin.get("altium"),
"datasheet": {"file": ds["file"], "sha256": sha(ds["file"]), "url": ds["url"], "title": ds["title"], "retrieved": TODAY},
"supporting_documents": [{"file": MOUNT["file"], "sha256": sha(MOUNT["file"]), "url": MOUNT["url"], "title": MOUNT["title"], "retrieved": TODAY}],
"datasheet_figures": figs,
"datasheet_check": {"overlay": f"docs/verify/{slug}-overlay.png", "numbers": f"docs/verify/{slug}-check.json",
"tools": "provenance/tools/ (ortho.py, overlay_chip.py, spec json)", "result": "PASS" if check["all_pass"] else "FAIL"},
"land_pattern_check": {"readme": "land-pattern/README.md", "numbers": "land-pattern/land-check.json", "source": L["source"], "result": land_status},
"distributors": {"tool": "adom-parts-search search " + MPN, "date": TODAY,
**{kk: {"part": D[kk][0], "url": D[kk][1], "stock": D[kk][2]} for kk in ("mouser", "digikey", "lcsc")}},
"lod": {"manifest": "lod/manifest.json", "generator": "provenance/tools/lod.py", "source": MARKED or STEP, "source_sha256": sha(MARKED or STEP)},
"tools_note": ("Scripts come from the rc0402fr-074k7l page (adom/rc0402fr-074k7l). Changes for this page: the ortho.py end view and the lod.py iso "
"preview were mirror images (left-handed axes) and are corrected; lod.py keeps a datasheet marking in high and medium, drops it "
"in low and super-low, splits the terminal colour into two boxes and stops the body box under the top coat in super-low; "
"build.py puts the symbol pins on the 2.54 mm grid and adds the marking (etch.py) and the figure crops (figures.py); finish.py makes "
"the .lbr, the Altium libraries and the hero GLB."),
"files": files,
"files_note": "provenance.json itself is not listed.",
"built_by": "Claude (AI agent) for John Lauer", "date": TODAY,
}
json.dump(prov, open(p_("provenance.json"), "w"), indent=1)
print("records written", slug, land_status, "hero" if have_hero else "-", "altium" if have_alt else "-", "lbr" if have_lbr else "-")