> For the complete documentation index, see [llms.txt](https://docs.projectsim.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.projectsim.ai/creating-assets/procedural-variation-set.md).

# Procedural variation set

`POST /v1/variation-sets/procedural`

Generate related variants from one procedural object class. Use this endpoint for changes to shape, proportions, and configuration within an object family, such as desks or containers. It supports **articulated** objects with moving parts and jointless objects. Both use **rigid** bodies.

<figure><img src="https://70818391-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWnQtI3aVPkZHPVyrjjFG%2Fuploads%2Fgit-blob-60ea696248fcb75c3c6c2ea07463b9c6d3c79bf9%2Fprocedural-examples.png?alt=media" alt="Ten articulated desk variants with different dimensions, materials, and drawer configurations, including open drawers"><figcaption><p>Articulated desk variants for drawer-opening and manipulation tasks.</p></figcaption></figure>

A nonblank text brief is required; a reference image is optional. It is best suited to primitive and geometric shapes; intricate or organic objects may produce less faithful results. The brief guides generation; it does not expose a fixed set of dimension controls.

See the [desk example](/creating-assets/choosing-an-endpoint/worked-use-cases.md#articulated-desks-with-drawers) for an articulated generation workflow.

## Input

| Field                      | Notes                                                                                                       |
| -------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `count` (required)         | How many variants, `10`–`500`.                                                                              |
| `seed` (required)          | Provide **`seed.text`**, optionally with `seed.images`.                                                     |
| `seed.text` (required)     | A nonblank brief describing the object — its parts and how they move, materials, rough size (≤ 2000 chars). |
| `seed.images`              | A reference image (max 1).                                                                                  |
| `name`                     | Display label (≤ 100 chars).                                                                                |
| `params`                   | Optional output settings; see [Parameters that apply](#parameters-that-apply).                              |
| `Idempotency-Key` (header) | Without one, a timed-out retry duplicates the whole order.                                                  |

Image-only seeds and missing, null, empty, or whitespace-only `seed.text` return `422`.

## Parameters that apply

Set body behavior and articulation under **`params.physics`**. A top-level `body`, `body: articulated`, or `body: deformable` returns `422`.

Set **`params.physics.body: rigid`** and choose **`params.physics.articulated`** independently. The articulation flag guides generation of moving parts. Mesh, texture, and variation settings are not forwarded by this endpoint, so they are hidden from its reference. See [Parameters](/creating-assets/parameters.md).

| Field                        | Allowed values                                                                   | Built-in default  |
| ---------------------------- | -------------------------------------------------------------------------------- | ----------------- |
| `params.physics.body`        | `rigid`                                                                          | `rigid`           |
| `params.physics.articulated` | `true`, `false`                                                                  | `true`            |
| `params.physics.simulator`   | `isaac_sim_physx`, `isaac_sim_newton`, `mujoco`, `sapien`, `genesis`, `agnostic` | `isaac_sim_physx` |
| `params.physics.collision`   | `auto`, `convex_hull`, `convex_decomposition`, `coacd`, `bounding_box`, `sdf`    | `auto`            |

`params` is optional. `sdf` collision is accepted only with `isaac_sim_physx` or `isaac_sim_newton`; unsupported combinations return `422`.

Procedural currently exports **rigid-body USD** using its own collision construction. Although `simulator` and `collision` are accepted and forwarded, changing them does not yet select another output format or collision method.

## Writing a text prompt

Describe **one object and its construction**: the main body, attached parts, materials, and the proportions or features that may vary. For moving parts, name what moves, how it moves, and its starting position. “Articulated box” alone leaves the mechanism unclear; “four top flaps hinged along the upper rim, initially closed” gives a concrete construction brief.

Keep the prompt about one object per variant; avoid asking for a pile, a pair, or a scene containing several objects. If you supply an image, use a reference showing one object clearly. Background, lighting, camera, and image-layout instructions are unnecessary for describing the procedural object's construction.

Describe motion consistently. For opening lids, hinged doors, or sliding drawers, explain how they move and avoid conflicting phrases such as “no moving parts,” “fused shut,” or “sealed top.” For a fixed prop, describe its fixed construction without asking for functional hinges or sliding parts.

Prompts guide generation; they do not guarantee exact dimensions, motion limits, or a particular joint count.

### Example procedural prompts

Use these examples as a starting point for describing the object you need.

| Asset                                  | Example prompt                                                                                                                                                                                                                                                                                                                                              |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Sealed parcel for picking and stacking | One closed corrugated cardboard shipping box with a taped, sealed top and bottom. Vary its width, depth, height, and cardboard colour within ordinary parcel proportions. All panels are fixed; no moving parts.                                                                                                                                            |
| Shipping box that opens                | One corrugated cardboard shipping box with a hollow interior, a permanently sealed bottom, and four independently opening top flaps. Each flap rotates about its attachment along the upper rim, from closed to approximately 120 degrees open. Start with the flaps closed and leave clearance for opening. Vary the box proportions and cardboard colour. |
| Desk with sliding drawers              | One freestanding desk with a fixed worktop, supporting legs, and drawers beneath the worktop. Each drawer slides outward horizontally and starts closed. Handles move with their drawers. Vary the desk proportions, drawer configuration, handle shape, and wood finish.                                                                                   |
| Roll cage with an opening gate         | One warehouse roll cage with a rectangular base, three fixed mesh sides, and one front mesh gate. The gate swings outward around a vertical hinge on its left edge and starts closed. Keep its handle attached to the gate. Vary cage height, width, and mesh spacing.                                                                                      |
| Drawer unit                            | One freestanding drawer unit with a fixed outer frame and three separate drawers. Each drawer slides straight forward from the frame and starts fully closed. Handles move with their drawers. Vary the frame proportions, drawer heights, and finish.                                                                                                      |

For detailed creases, crushed corners, printed labels, or surface wear from a photo, use the [High-fidelity prompt examples](/creating-assets/high-fidelity-variation-set.md#writing-a-text-prompt). That route varies appearance and geometry but does not create functional joints.

## Example

Install the Python SDK and set `PROJECTSIM_TOKEN` as shown in the [Quickstart](/getting-started/quickstart.md).

{% tabs %}
{% tab title="Python" %}

```python
import os
import uuid

import httpx
from projectsim import AuthenticatedClient
from projectsim.api.variation_sets import create_procedural_variation_set
from projectsim.models import CreateProceduralVariationSetRequest

body = CreateProceduralVariationSetRequest.from_dict(
    {'name': 'desk with drawers',
     'count': 50,
     'seed': {'text': 'One freestanding desk with a fixed worktop, supporting legs, and '
                      'drawers beneath the worktop. Each drawer slides outward '
                      'horizontally and starts closed. Handles move with their drawers. '
                      'Vary the desk proportions, drawer configuration, handle shape, '
                      'and wood finish.'},
     'params': {'physics': {'body': 'rigid',
                            'articulated': True,
                            'simulator': 'isaac_sim_physx',
                            'collision': 'auto'}}}
)
client = AuthenticatedClient(
    base_url="https://api.projectsim.ai",
    token=os.environ["PROJECTSIM_TOKEN"],
    timeout=httpx.Timeout(30.0),
    raise_on_unexpected_status=True,
)
with client:
    response = create_procedural_variation_set.sync_detailed(
        client=client, body=body, idempotency_key=str(uuid.uuid4()),
    )
if response.status_code != 202 or response.parsed is None:
    raise RuntimeError(response.content.decode("utf-8"))
print(response.parsed.job_id)
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X POST "https://api.projectsim.ai/v1/variation-sets/procedural" \
  -H "Authorization: Bearer $PROJECTSIM_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '
{
  "name": "desk with drawers",
  "count": 50,
  "seed": {
    "text": "One freestanding desk with a fixed worktop, supporting legs, and drawers beneath the worktop. Each drawer slides outward horizontally and starts closed. Handles move with their drawers. Vary the desk proportions, drawer configuration, handle shape, and wood finish."
  },
  "params": {
    "physics": {
      "body": "rigid",
      "articulated": true,
      "simulator": "isaac_sim_physx",
      "collision": "auto"
    }
  }
}'
```

{% endtab %}
{% endtabs %}

Creation returns `202` with the set's `id` and `job_id`. Exactly `count` member assets are created at once, each a full [`/v1/assets`](/guides/jobs-and-assets.md) citizen with a stable `variant_index` from 1 to `count`.

{% hint style="info" %}
Limits: `count` is 10–500, and at most **5 sets** may be queued or running at once (`409` `too-many-sets` beyond that). If the account has a lifetime [asset limit](/guides/jobs-and-assets.md#account-limit), every member counts toward it, so a set that would cross it returns `429` (`asset-limit-reached`). Members cannot be deleted individually — delete the set once it is no longer active; deleting an active set returns `409` (`job-in-progress`), so cancel it first.
{% endhint %}

For a jointless asset, change `params.physics.articulated` to `false` while keeping `params.physics.body` set to `rigid`.

## Pulling the set

* **Get the assets:** `GET /v1/variation-sets/{set_id}/assets` returns member assets with presigned download URLs (valid for 24 hours), ordered by `variant_index`. It is paginated: `limit` defaults to 50 (max 100); pass the returned `next_cursor` (the last `variant_index` on the page) as `cursor` until it is `null`. Filter by member job with `status`.
* **Check set status:** `GET /v1/variation-sets/{set_id}` returns status and member counts, derived from member jobs on every read, plus the manifest once terminal.
* **Cancel the set:** `POST /v1/jobs/{job_id}/cancel` with the set's `job_id` cancels the set and its members until any member starts generating; after that, or once the set has finished, it returns `409` (`job-started` or `job-finished`). A member's own job cannot be canceled (`409` `variation-set-member`).

See also: [High-fidelity variation set](/creating-assets/high-fidelity-variation-set.md).
