A body is one folder. CI enforces the rest, so the fastest way to learn the standard is to run it on your branch.
A pack is ten-odd files that have to agree with each other. Rather than start from nothing, copy one that already works — then change it a part at a time and watch what breaks.
npm install npm run new-body -- my-body "My Body" # copies Scout: 1 board, 19 parts, no serial servos npm run sync && npm run emit && npm run site-data npm run check
That gives you a complete, valid pack that already shows up in the catalog, and exactly one failing check:
That is the whole job, stated as a test. Pass --from to start from a body closer to what you are building — --from biped-mini for legs, --from lamp for an arm.
bodies/<slug>/ <Name> Design Brief.dc.html the full brief, sections 01-06 <Name> Viewer.html three.js viewer <Name> Print Parts.html live CSG generator — the geometric source of truth stl/<slug>-<part>-x<qty>.stl print files, quantity in the name parts-list.csv part,qty,where,link,notes firmware/hangar_bay_<slug>.yaml the body manifest — the one authored copy hangar-bay/<slug>.template.yaml generated from it generated/manifest.json generated — what Meckie OS consumes generated/build.json generated README.txt maker instructions LICENSE.txt CERN-OHL-S-2.0 + MIT
Everything screws into heat-set inserts or snaps together. Press-fits only where a screw or clamp retains them. CI reads the 05c assembly table: every joint's method must come from a mechanical vocabulary, and an adhesive word may appear in a joint description only in a sentence that rules it out.
A body with drives: true declares a peripheral with role: obstacle and at least two with role: drop_off, and every drop-off sensor must be wired into the edge reflex. A fixed base says why the rule does not apply rather than leaving the exemption implicit. Enforced by role, not by name — the names varied between packs and the rule silently passed bodies that only looked compliant.
On heartbeat loss (~500 ms), low battery or servo over-temperature the body stops, brakes, waits about 2 s, moves slowly to a safe rest pose, lowers torque and shows a lost-connection face. It resumes only on a fresh command. And the calibration wizard ends in a required safety_test — the one check that proves it parks itself when Central goes away.
Partitioned by host, because a two-board body has two independent GPIO spaces and merging them invents collisions that do not exist. One pin may carry two signals only where shared_pins declares it, names every signal on it, and says how it is shared.
Fits a 220 × 220 mm bed. PLA shells and structure, TPU bumpers and tyres. Bearings at every pivot, metal servo horns, hidden fasteners. Insert bores: M2 Ø3.2 · M2.5 Ø3.6 · M3 Ø4.0 · M4 Ø5.6 · M5 Ø6.4. Supplier links stay plain — no affiliate tags, and prefer a search URL to a specific listing, because listings rot and searches do not.
The constraint that decided this was not strength. It was that a stock printer with no modifications should be able to make every rigid part. PLA needs no hardened nozzle, no dry box, no enclosure and no 260 °C hotend, which is the difference between a pack most people can print and a pack most people can only read. Contributed packs are held to the same rule.
everything rigid
Shells, structure, brackets, bezels. Stiff, dimensionally accurate, prints unsupported on more surfaces than anything else, and stocked in every colour the briefs name.
only where flex is the function
Tyres, tracks, soles, feet, bumpers, grommets, straps. Parts a rigid version would not perform at all. Nothing is TPU for toughness alone — if a rigid part would do, it is PLA.
Snap hooks are the weak point. The snap features in these packs were drawn to stay under 2.5% strain, which suits PETG. PLA's safe cantilever strain is nearer 1.5%, so the hooks work harder than the geometry assumed. Print them with the layer lines running across the hook rather than along it, and treat a hook as a part you may have to reprint. Nothing in this catalogue has been test-printed, so this is the first place to look for trouble, and a report that a hook snapped is worth more to us than a report that one held.
Heat is a storage rule, not a running problem. PLA's glass transition is about 55 to 60 °C and the serial-servo bodies do not warn until 65 °C. Indoors that gap never opens: the shell sits near room temperature and the servos are the only thing that gets hot. Left in a closed car in summer, or on a sill in direct sun, a shell can soften while the electronics still consider themselves fine.
Heat-set inserts want a cooler iron. Every screw lands in a brass insert, and PLA's window is narrower than PETG's: run the iron around 180 to 200 °C, go in slowly, and let the boss cool before loading it. Rushing one slumps the wall around it.
If you want the margin back: the geometry does not change. Print the shells in PETG and the load-bearing structure in CF-nylon and every part still fits, because that was the original specification and the only thing that changed is which spool is on the shelf. The cost is a hardened nozzle, a dry box and a printer that holds 260 °C. Each body's brief carries this argument with that body's own numbers, in section 06b.
git checkout -b my-body npm run new-body -- my-body "My Body" # design it: geometry, manifest, brief, buy list npm run sync && npm run emit && npm run site-data npm run check # validate + generators current + the gates still fail on bad input # drop "scaffolded_from" from your bodies.json entry, then open a PR
Hardware must be CERN-OHL-S-2.0 and code MIT, and the pack must include a Hangar Bay template. A community body gets a known template — pick it by name in Hangar Bay, flash, go — once it is accepted into the catalog. Until then it uses Hangar Bay's builder, which can already build whatever you design.
The catalog is readable as JSON, which is how Hangar Bay fills its body picker: it reads the feed to list the official bodies, then fetches one template to get that body's manifest, pin map and calibration wizard. If you are writing something that needs the catalog, read these rather than scraping the pages.
GET /bodies.json
every body: slug, class, servos, brains, mass_g, bom_usd,
total_prints, materials, status, plus template_url and page_url
GET /api/bodies/<slug>/template
the Hangar Bay template, pre-rendered by this repo. Served
byte-for-byte as published, so the `hardware` text you hash
is the text the pack signed.
GET /api/bodies/<slug>/stl.zip
every STL for one body, in one zip.
The feed sends Access-Control-Allow-Origin: * on purpose — another app on your own machine reading it is the point — and no-cache, so a body you scaffold shows up the moment it exists. While the catalog is in private preview it also accepts the access token as ?t= or an X-Meckie-Bodies-Token header, because Hangar Bay has no browser session to carry a cookie.