# 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.

Source: https://rack-maker.cbnsndwch.dev/docs/catalog/authoring

## Two ways to add hardware

- **Model a device** opens the [device modeler](https://rack-maker.cbnsndwch.dev/docs/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](https://rack-maker.cbnsndwch.dev/catalog). You need to be [signed in](https://rack-maker.cbnsndwch.dev/docs/getting-started/accounts).

## 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](#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](https://rack-maker.cbnsndwch.dev/docs/catalog/entries-and-revisions).

![The catalog editor for a new part: the New device quick form, the Definition card with the entry as JSON, the 3D preview, and the Model file section](https://rack-maker.cbnsndwch.dev/docs/shots/catalog/editor-light.webp)

*The catalog editor.*

> **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:

```json
{
    "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** `ears` says 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's `pitch`, so it takes one position on a whole-U rack and two on the half-U RackMate T0.
- The **socket** `deck` accepts 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.
- **`derived`** values are worked out once per part in a project, and anything below can read them. `on.deck.h` is the height of whatever sits on the deck, or 0 when it is empty.
- The **constraint** shows up in the project's [checks](https://rack-maker.cbnsndwch.dev/docs/editor/checks). With `blocksFabrication`, a failing check holds back the STL export until the user overrides it.
- **`geometry`** draws 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](https://rack-maker.cbnsndwch.dev/docs/catalog/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](#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](#sockets-and-plugs))                                                                                                                                                                   |
| `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](https://rack-maker.cbnsndwch.dev/docs/editor/bom-and-quote): `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's `occupies.span` says how many positions it takes, and overlaps are reported.
- `surface`: a `w × d` area. Parts on it are placed by x and y in mm.
- `grid`: `nx × ny` cells at `pitchX` and `pitchY` (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`, `tan` and `atan2` (in degrees), `hypot`, `near(a, b, tol)`, `fixed(x, decimals)` (as text), and `ulabel(pos, perU)` (a rail position as a U label).
- **Constants:** `U19` (44.45 mm, one rack unit) and `PI`.
- **Names:**
  - a bare name is the part's own param, derived value, exposed value, envelope size (`w`, `d`, `h`) or `name`;
  - `parent.x` is the enclosing assembly, `root.x` the project's top part, and `host.x` the part whose socket this one is mounted on;
  - `child.<id>.x` reads a child of an assembly (the first one, when it is repeated);
  - `on.<socket>.x` reads the first part on a socket, or 0 when it is empty;
  - `on.<socket>.count`, `top`, `used`, `overlaps`, `tallest` and `n.<category>` summarise a socket (`tallest` is the height of the tallest part on it);
  - `mate.pos` is this part's position on its socket.

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](https://rack-maker.cbnsndwch.dev/docs/editor/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](https://rack-maker.cbnsndwch.dev/docs/catalog/contributing).

- **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](https://rack-maker.cbnsndwch.dev/credits) page. See [Licences and credits](https://rack-maker.cbnsndwch.dev/docs/catalog/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](https://rack-maker.cbnsndwch.dev/docs/editor/bom-and-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 `USD` or `EUR`), 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.
