Authoring parts
Write a catalog entry in the catalog editor, from a quick device to a full part with sockets, checks and expressions; attach model files and add listings.
Two ways to add hardware
- Model a device opens the device modeler. It is the easiest way to add a device you own: it builds the entry, and its 3D model, from measurements and a photo.
- New part opens the catalog editor, described here. Use it for anything else (shelves, trays, mounts, brackets, panels, racks) or when you want full control over an entry's definition.
Both buttons are at the top of the catalog. You need to be signed in.
The catalog editor
The editor at /catalog/new has four parts:
- New device: the quick way in. Give a Name, a Namespace (your handle), a Description, and the Width, Depth and Height in mm. This fills in the definition for a box-shaped device that stands on shelves and trays. The id is shown below the form, made from the namespace and the name.
- Definition: the entry as JSON. Edit it directly for anything the quick form doesn't cover, or paste a whole entry. The card's title says valid, or how many issues there are, and each issue is listed with the field it is about.
- Preview: the entry in 3D with its default values, updated as you type.
- Model file: upload a GLB or STL to draw the part with (contributors only; see Model files).
Save draft keeps the draft in your namespace. Submit for review saves it and sends it for review in one go. Both are available once the definition is valid. To change a saved draft later, use Edit on its row on the entry's page. See Entries and revisions.
Start from an existing entry
The quickest way to write a part is to copy one that is close. Every entry's page has a Definition card with its
full JSON. Copy it into the editor, change the id to your namespace, set rev to 1, and adjust from there. Keep
the original's attribution and add yours.
A worked example
A printed 1U tray for a 10″ rack, holding one mini PC:
{
"id": "alice/mini-pc-tray",
"rev": 1,
"kind": "part",
"name": "Mini PC tray (1U)",
"category": "tray",
"params": [{ "key": "depth", "label": "Depth", "kind": "length", "default": 160, "min": 80, "max": 220 }],
"derived": {
"units": 1,
"faceH": { "expr": "U19 - 1.25" },
"devH": { "expr": "on.deck.count > 0 ? on.deck.h : 0" }
},
"envelope": { "w": 250, "d": { "expr": "depth" }, "h": { "expr": "faceH" } },
"plugs": [
{
"id": "ears",
"provides": "rail/10in/eia",
"frame": { "at": [125, 3, 0] },
"occupies": { "kind": "linear", "span": { "expr": "max(1, round(units * U19 / host.pitch))" } }
}
],
"sockets": [
{
"id": "deck",
"label": "Deck",
"accepts": [{ "iface": "surface/flat" }],
"frame": { "at": [18, 3.6, 3] },
"shape": { "kind": "surface", "w": 214, "d": { "expr": "depth - 6" } },
"capacity": 1
}
],
"geometry": {
"kind": "generator",
"id": "core/faceplate-tray@1",
"args": { "faceH": { "expr": "faceH" }, "plateD": { "expr": "depth" } }
},
"constraints": [
{
"id": "height",
"level": "error",
"title": "Device fits under the next tray",
"when": { "expr": "on.deck.count > 0" },
"assert": { "expr": "devH + 3 <= faceH" },
"message": "{fixed(devH, 1)} mm device in a {fixed(faceH, 1)} mm (1U) tray",
"blocksFabrication": true
}
],
"fabrication": { "method": "fdm", "material": { "default": "PETG" } },
"license": "CC-BY-SA-4.0",
"attribution": [{ "name": "alice", "role": "author" }]
}What each part of it does:
- The plug
earssays the tray mounts on 10″ EIA rails. Its frame is the point that lands on the rails' socket: the middle of the faceplate, 3 mm back. Its span uses the host'spitch, so it takes one position on a whole-U rack and two on the half-U RackMate T0. - The socket
deckaccepts anything that stands on its feet (surface/flat). Devices dropped on it are placed by x and y in millimetres, and can be centred across it. derivedvalues are worked out once per part in a project, and anything below can read them.on.deck.his the height of whatever sits on the deck, or 0 when it is empty.- The constraint shows up in the project's checks. With
blocksFabrication, a failing check holds back the STL export until the user overrides it. geometrydraws the tray with one of the app's built-in generators. Without geometry, a part is drawn as its envelope box.
Entry reference
| Field | What it is |
|---|---|
id, rev | <namespace>/<slug> in lowercase, and the revision number (see Namespaces) |
kind | part (one thing) or assembly (made of other entries) |
name, description, tags | what people see and search for |
category | rack, frame, rail, shelf, tray, mount, printed, device, power, fastener, panel, accessory or material |
params | values users can edit in the inspector: length, angle, count, number, boolean, enum, string; measurable adds a "measured" toggle |
derived | computed values (expressions) |
envelope | the bounding box w × d × h in mm, from the part's own origin (left, front, bottom); parts only |
plugs / sockets | how parts attach (below) |
constraints | checks: level (error, warning or info), when, assert, message or failMessage, order, blocksFabrication |
kpis | headline numbers for the project's summary row: value, detail, tone (ok, warn or bad) |
props | facts such as mass, power, heat, airflow and ports |
geometry | how it is drawn: envelope (a box), generator (a built-in generator and its arguments), mesh (an uploaded model file; fit: "envelope" scales it to the envelope) or composite |
fabrication | method (fdm, sla, laser, cnc or bought), material, estimate (filament and print time), and for printable parts the generator and its export values |
bom | how it appears in the BOM: self (the default for parts), children (list its parts instead), all (both: a shelf and its screws) or none |
collision | none leaves the part out of the overlap check (rails inside posts, parts that hook over an edge) |
children | for assemblies: each child's ref (id and rev), its params, where it goes (at or mate), repeat, when and locked |
license | always CC-BY-SA-4.0 for catalog entries |
attribution | who made or measured the entry: name, role (author, contributor, measured or forked-from), url (their page), source (where the facts come from), permission (where the author allowed the use) |
When you save, you are added to attribution as a contributor if you aren't there already.
Sockets and plugs
A part's plug fits another part's socket when the plug's interface id matches one of the socket's accepts patterns. A pattern ending in /* matches any id that begins with it: rail/10in/* accepts rail/10in/eia.
A socket has a frame (where it is on its part), a shape and the interfaces it accepts. The shapes are:
linear: positions along an axis (pitch,count,origin0). Rails are linear, running up the rack. A plug'soccupies.spansays how many positions it takes, and overlaps are reported.surface: aw × darea. Parts on it are placed by x and y in mm.grid:nx × nycells atpitchXandpitchY(pegboards, hole grids).point: exactly one place.
capacity limits how many parts a socket takes. An accept may add a where expression, for example to accept 19″ parts only when the rack's standard is 19in.
The interfaces in use today:
| Interface | What it is |
|---|---|
rail/10in/eia | 10″ rails with the EIA-310 hole pattern. Panels up to 254 mm wide. The rack gives pitch: a whole U on most racks, half a U on the RackMate T0. |
rail/19in/eia | the same pattern on 19″ rails: 482.6 mm panels |
rail/deskpi-tl1 | RackMate TL1 rails, with holes evenly spaced in thirds of a U. Not EIA-310: TL1 parts don't fit generic 10″ rails, and the other way round. |
caddy/deskpi-tl1-top | the TL1 top plate between the carry handles |
post-leg/deskpi-tl1 | the rear leg of a TL1 post, which the cable comb clip grips |
surface/flat | a flat deck that carries something standing on its feet: shelves and trays offer it, every device uses it |
post/wire-shelving-1in | a wire shelf's collars on 1″ round posts, clamping at any 1″ groove |
fan/80mm | an 80 mm fan lying on a floor grille |
Two parts should fit only when they really do. If your part is mechanically different from what an interface describes, don't reuse that interface.
Racks that are only a model file
A rack can be drawn entirely by an uploaded GLB or STL. Give the entry an envelope and declare its rail socket yourself: the rails' frame sits on their centre line, just in front of the flanges, at the bottom of U1. The entry cbnsndwch/rack-19in-12u-mesh is an example to copy.
Expressions
Wherever a number, a true/false value or a text is allowed, you can write an expression instead, as { "expr": "…" }. Text fields (title, message, detail) take expressions in curly-brace holes, like the message in the example above.
- Operators:
+ - * / %, comparisons,&& || !,a ? b : c, and text in single quotes. - Functions:
min,max,abs,floor,ceil,round(x[, decimals]),clamp(x, lo, hi),sqrt,sin,cos,tanandatan2(in degrees),hypot,near(a, b, tol),fixed(x, decimals)(as text), andulabel(pos, perU)(a rail position as a U label). - Constants:
U19(44.45 mm, one rack unit) andPI. - Names:
- a bare name is the part's own param, derived value, exposed value, envelope size (
w,d,h) orname; parent.xis the enclosing assembly,root.xthe project's top part, andhost.xthe part whose socket this one is mounted on;child.<id>.xreads a child of an assembly (the first one, when it is repeated);on.<socket>.xreads the first part on a socket, or 0 when it is empty;on.<socket>.count,top,used,overlaps,tallestandn.<category>summarise a socket (tallestis the height of the tallest part on it);mate.posis this part's position on its socket.
- a bare name is the part's own param, derived value, exposed value, envelope size (
A mistake in an expression doesn't break a project. It shows up in the project's Problems card, naming the entry and the field it came from. Loops between values are reported the same way.
Printable parts
A part whose fabrication names a printable generator can be exported as an STL from a project. The printable generators are built into the app, so you can use the ones that exist but not add your own. See Exports and printing.
Model files
A model file draws a part from a 3D file instead of a generator or a box. Uploading one needs contributor access.
- Formats: GLB (binary glTF) or STL. glTF is read Y-up with the front facing +Z; STL is read Z-up, in millimetres.
- Size: up to 15 MB.
- Scale: files come in any unit, so Scale the model to fit the part's size is on by default. It scales the model evenly to fit the entry's envelope, centred and standing on its floor.
In the Model file section of the catalog editor, choose the file, then fill in where it comes from:
| Field | Notes |
|---|---|
| Who made the model | I made it or Someone else made it |
| Licence | CC0 1.0, CC BY 4.0, CC BY-SA 4.0, CC BY 3.0, CC BY-SA 3.0, MIT or Apache 2.0 |
| Title, author, source page | required when someone else made it; the author defaults to you when you made it |
| Author page | optional: a link to the author's profile |
| Model site | when someone else made it: where you found it, such as Sketchfab or Printables |
| Changes made | optional: what you changed from the original (Creative Commons licences ask for this) |
| Acknowledgements | optional: the credit or licence notice the author asks for, thanks, upstream notices |
Tick I may share this file under this licence, and the credits above are complete, then Upload and attach. The file becomes the entry's geometry. Save the draft to keep it.
Only upload files you may share under one of those licences. For anything else, link to the page it is on (in the entry's description, for example) instead of uploading it.
The same file uploaded twice is stored once. Upload your own file again to correct its licence or credits. If someone else uploaded it first, their upload and credits are used.
Each model file's licence and credits appear on the entries that use it and on the Credits page. See Licences and credits.
Listings
Listings say where to get a part: online shops and physical stores, each with a dated price and stock report. They feed the BOM & quote. Anyone can see them on an entry's Where to get it card; adding them needs contributor access.
To add one, fill in the form at the bottom of Where to get it:
- Online shop or Physical store, and the shop or store's name.
- For a shop, the product page (required). For a store, its address or city (required), and optionally its page.
- Optionally a price with its three-letter currency (such as
USDorEUR), the pack size (items per purchase), and the stock: in stock, few left or out of stock.
Then Add listing. Later, contributors can add a New price or report the stock on any listing. Prices and stock reports are dated, and a price older than 90 days is marked as stale.
Checklist before submitting
- Dimensions come from a datasheet, a drawing or calipers. Say which in the
description, or in a parameter's hint. - The interfaces you use describe how the part really mounts.
- The part behaves in a project: it mounts, its checks read sensibly when they pass and when they fail, and it doesn't collide with its neighbours when it shouldn't. Your draft works in your own projects, so try it there first.
- Model files are yours to share, or carry an allowed licence with full credits. Otherwise link to them instead of uploading.
Limits
- An entry's definition can be up to 128 KB.
- You can make up to 120 catalog changes (saving, submitting, deleting) in 10 minutes.
- Contributors can upload up to 30 model files an hour.