primvaria 0.1.0b1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Régis Sarmento Caon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.4
2
+ Name: primvaria
3
+ Version: 0.1.0b1
4
+ Summary: Physics-ready variability for Physical AI, in OpenUSD: one install for the Granulaire, Maillage, Filaire and Quincaillerie asset generators, with a single command line.
5
+ Author: Daniel Régis Sarmento Caon
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/drscaon/primvaria
8
+ Project-URL: Issues, https://github.com/drscaon/primvaria/issues
9
+ Project-URL: Changelog, https://github.com/drscaon/primvaria/blob/main/CHANGELOG.md
10
+ Project-URL: Granulaire, https://github.com/drscaon/granulaire
11
+ Project-URL: Maillage, https://github.com/drscaon/maillage
12
+ Project-URL: Filaire, https://github.com/drscaon/filaire
13
+ Project-URL: Quincaillerie, https://github.com/drscaon/quincaillerie
14
+ Keywords: openusd,physical-ai,robot-learning,simulation,synthetic-data,procedural,isaac-sim,mujoco,blender
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: granulaire>=0.2.0b2
29
+ Requires-Dist: maillage>=0.1.0b1
30
+ Requires-Dist: filaire>=0.1.0b1
31
+ Requires-Dist: quincaillerie>=0.1.0b2
32
+ Provides-Extra: render
33
+ Requires-Dist: granulaire[render]; extra == "render"
34
+ Requires-Dist: maillage[render]; extra == "render"
35
+ Requires-Dist: filaire[render]; extra == "render"
36
+ Provides-Extra: sim
37
+ Requires-Dist: filaire[sim]; extra == "sim"
38
+ Requires-Dist: quincaillerie[sim]; extra == "sim"
39
+ Provides-Extra: materialx
40
+ Requires-Dist: quincaillerie[materialx]; extra == "materialx"
41
+ Provides-Extra: all
42
+ Requires-Dist: primvaria[materialx,render,sim]; extra == "all"
43
+ Provides-Extra: dev
44
+ Requires-Dist: pytest>=7; extra == "dev"
45
+ Requires-Dist: ruff>=0.5; extra == "dev"
46
+ Dynamic: license-file
47
+
48
+ <h1 align="center">Primvaria</h1>
49
+
50
+ <p align="center"><strong>Physics-ready variability for Physical AI, in OpenUSD.</strong></p>
51
+
52
+ <p align="center">
53
+ <a href="https://github.com/drscaon/primvaria/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/drscaon/primvaria/actions/workflows/ci.yml/badge.svg"></a>
54
+ <img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-3776AB">
55
+ <img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-green">
56
+ </p>
57
+
58
+ Primvaria is a suite of procedural asset generators for the objects robots
59
+ struggle with most: grains, cloth, cables and small mechanical parts. Every
60
+ generator follows the same approach: **distributions instead of one shape**
61
+ (no two generated instances are the same, and what was drawn is written down
62
+ as ground truth), **measured outputs** (mass, shape, stiffness are measured on
63
+ what was generated, not trusted from the inputs) and **honest limits** (each
64
+ asset is checked in real engines, and what was not tested is said).
65
+
66
+ Every output is **OpenUSD** with standard `UsdPhysics` schemas, plus PhysX
67
+ attributes for **NVIDIA Omniverse and Isaac Sim**: one file format for
68
+ Blender, usdview, Omniverse and the other OpenUSD-aware tools, read back into
69
+ MuJoCo for the checks. Each generator's README says in which engines its
70
+ assets have been tested so far. Everything can run on CPU.
71
+
72
+ The name comes from *primvar*, OpenUSD's primitive variable, and *varia*,
73
+ Latin for "diverse things".
74
+
75
+ ## The generators
76
+
77
+ | | Generator | Assets | Physics |
78
+ |---|---|---|---|
79
+ | ![Granulaire](https://raw.githubusercontent.com/drscaon/granulaire/main/docs/images/moisture_gallery.png) | [**Granulaire**](https://github.com/drscaon/granulaire) | sand, gravel, pebbles, seeds, fruit, pellets, packing peanuts; measured shapes, masses and moisture | rigid bodies; deformables for OmniPhysics (not tested yet) |
80
+ | ![Maillage](https://raw.githubusercontent.com/drscaon/maillage/main/docs/images/blender_drape.jpg) | [**Maillage**](https://github.com/drscaon/maillage) | towels, napkins, tablecloths, sheets, scarves, flags; real sizes, fabrics and masses | cloth meshes; drape test in Blender |
81
+ | ![Filaire](https://raw.githubusercontent.com/drscaon/filaire/main/docs/images/hero.jpg) | [**Filaire**](https://github.com/drscaon/filaire) | standard cables with male and female connectors and the receptacles they plug into | rigid-segment chains with joints; drop, sag and insertion tests in MuJoCo |
82
+ | ![Quincaillerie](https://raw.githubusercontent.com/drscaon/quincaillerie/main/docs/images/fasteners.jpg) | [**Quincaillerie**](https://github.com/drscaon/quincaillerie) | metric screws, nuts and washers with modelled threads; battery cells and their holders | rigid bodies, springs and clips; drop, screwing and insertion tests in MuJoCo and Blender |
83
+
84
+ Each generator is its own package, released on its own schedule. Primvaria
85
+ installs them together and gives them one command line.
86
+
87
+ ## Installation
88
+
89
+ ```bash
90
+ pip install primvaria # the four generators
91
+ pip install "primvaria[all]" # + renders, MuJoCo checks, MaterialX
92
+ ```
93
+
94
+ | Extra | Adds |
95
+ |---|---|
96
+ | `render` | previews and renders (matplotlib, Pillow) |
97
+ | `sim` | the MuJoCo checks of Filaire and Quincaillerie |
98
+ | `materialx` | MaterialX materials of Quincaillerie |
99
+ | `all` | all of the above |
100
+
101
+ Blender as a Python module is installed with `pip install "maillage[blender]"`
102
+ (Python 3.13 only, as the `bpy` wheels exist for one Python version). Only one
103
+ generator? Install it alone: `pip install granulaire`.
104
+
105
+ ## Usage
106
+
107
+ ```bash
108
+ primvaria list # generators and installed versions
109
+ primvaria granulaire generate --preset beach_sand
110
+ primvaria maillage generate --preset tea_towel
111
+ primvaria filaire generate --preset usb_c --length 2
112
+ primvaria quincaillerie generate screw M10 --with nut,washer --count 10
113
+ ```
114
+
115
+ `primvaria <generator> ...` runs that generator's own command line: it is the
116
+ same as typing `granulaire ...`, `maillage ...`, which keep working. From
117
+ Python, import the generators directly:
118
+
119
+ ```python
120
+ from granulaire import generate_scene, write_outputs
121
+
122
+ write_outputs(generate_scene("beach_sand"), "output")
123
+ ```
124
+
125
+ ## Development
126
+
127
+ The project follows **GitHub Flow**, like the four generators: `main` is
128
+ protected, every change goes through a pull request from a short-lived branch
129
+ (`feat/<name>`, `fix/<name>`, …), and CI must be green before merging.
130
+ Enable the pre-push hook once per clone with
131
+ `git config core.hooksPath .githooks`.
132
+
133
+ Releasing: on a `chore/release-X.Y.Z` branch, bump `version` in
134
+ `pyproject.toml` and move the `Unreleased` entries of `CHANGELOG.md` under
135
+ the new version; merge, then tag `vX.Y.Z` on `main`. The release workflow
136
+ tests, builds, creates the GitHub release and publishes the package on PyPI
137
+ through Trusted Publishing.
138
+
139
+ ## License
140
+
141
+ [MIT](https://github.com/drscaon/primvaria/blob/main/LICENSE) © 2026 Daniel Régis Sarmento Caon
@@ -0,0 +1,94 @@
1
+ <h1 align="center">Primvaria</h1>
2
+
3
+ <p align="center"><strong>Physics-ready variability for Physical AI, in OpenUSD.</strong></p>
4
+
5
+ <p align="center">
6
+ <a href="https://github.com/drscaon/primvaria/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/drscaon/primvaria/actions/workflows/ci.yml/badge.svg"></a>
7
+ <img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-3776AB">
8
+ <img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-green">
9
+ </p>
10
+
11
+ Primvaria is a suite of procedural asset generators for the objects robots
12
+ struggle with most: grains, cloth, cables and small mechanical parts. Every
13
+ generator follows the same approach: **distributions instead of one shape**
14
+ (no two generated instances are the same, and what was drawn is written down
15
+ as ground truth), **measured outputs** (mass, shape, stiffness are measured on
16
+ what was generated, not trusted from the inputs) and **honest limits** (each
17
+ asset is checked in real engines, and what was not tested is said).
18
+
19
+ Every output is **OpenUSD** with standard `UsdPhysics` schemas, plus PhysX
20
+ attributes for **NVIDIA Omniverse and Isaac Sim**: one file format for
21
+ Blender, usdview, Omniverse and the other OpenUSD-aware tools, read back into
22
+ MuJoCo for the checks. Each generator's README says in which engines its
23
+ assets have been tested so far. Everything can run on CPU.
24
+
25
+ The name comes from *primvar*, OpenUSD's primitive variable, and *varia*,
26
+ Latin for "diverse things".
27
+
28
+ ## The generators
29
+
30
+ | | Generator | Assets | Physics |
31
+ |---|---|---|---|
32
+ | ![Granulaire](https://raw.githubusercontent.com/drscaon/granulaire/main/docs/images/moisture_gallery.png) | [**Granulaire**](https://github.com/drscaon/granulaire) | sand, gravel, pebbles, seeds, fruit, pellets, packing peanuts; measured shapes, masses and moisture | rigid bodies; deformables for OmniPhysics (not tested yet) |
33
+ | ![Maillage](https://raw.githubusercontent.com/drscaon/maillage/main/docs/images/blender_drape.jpg) | [**Maillage**](https://github.com/drscaon/maillage) | towels, napkins, tablecloths, sheets, scarves, flags; real sizes, fabrics and masses | cloth meshes; drape test in Blender |
34
+ | ![Filaire](https://raw.githubusercontent.com/drscaon/filaire/main/docs/images/hero.jpg) | [**Filaire**](https://github.com/drscaon/filaire) | standard cables with male and female connectors and the receptacles they plug into | rigid-segment chains with joints; drop, sag and insertion tests in MuJoCo |
35
+ | ![Quincaillerie](https://raw.githubusercontent.com/drscaon/quincaillerie/main/docs/images/fasteners.jpg) | [**Quincaillerie**](https://github.com/drscaon/quincaillerie) | metric screws, nuts and washers with modelled threads; battery cells and their holders | rigid bodies, springs and clips; drop, screwing and insertion tests in MuJoCo and Blender |
36
+
37
+ Each generator is its own package, released on its own schedule. Primvaria
38
+ installs them together and gives them one command line.
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install primvaria # the four generators
44
+ pip install "primvaria[all]" # + renders, MuJoCo checks, MaterialX
45
+ ```
46
+
47
+ | Extra | Adds |
48
+ |---|---|
49
+ | `render` | previews and renders (matplotlib, Pillow) |
50
+ | `sim` | the MuJoCo checks of Filaire and Quincaillerie |
51
+ | `materialx` | MaterialX materials of Quincaillerie |
52
+ | `all` | all of the above |
53
+
54
+ Blender as a Python module is installed with `pip install "maillage[blender]"`
55
+ (Python 3.13 only, as the `bpy` wheels exist for one Python version). Only one
56
+ generator? Install it alone: `pip install granulaire`.
57
+
58
+ ## Usage
59
+
60
+ ```bash
61
+ primvaria list # generators and installed versions
62
+ primvaria granulaire generate --preset beach_sand
63
+ primvaria maillage generate --preset tea_towel
64
+ primvaria filaire generate --preset usb_c --length 2
65
+ primvaria quincaillerie generate screw M10 --with nut,washer --count 10
66
+ ```
67
+
68
+ `primvaria <generator> ...` runs that generator's own command line: it is the
69
+ same as typing `granulaire ...`, `maillage ...`, which keep working. From
70
+ Python, import the generators directly:
71
+
72
+ ```python
73
+ from granulaire import generate_scene, write_outputs
74
+
75
+ write_outputs(generate_scene("beach_sand"), "output")
76
+ ```
77
+
78
+ ## Development
79
+
80
+ The project follows **GitHub Flow**, like the four generators: `main` is
81
+ protected, every change goes through a pull request from a short-lived branch
82
+ (`feat/<name>`, `fix/<name>`, …), and CI must be green before merging.
83
+ Enable the pre-push hook once per clone with
84
+ `git config core.hooksPath .githooks`.
85
+
86
+ Releasing: on a `chore/release-X.Y.Z` branch, bump `version` in
87
+ `pyproject.toml` and move the `Unreleased` entries of `CHANGELOG.md` under
88
+ the new version; merge, then tag `vX.Y.Z` on `main`. The release workflow
89
+ tests, builds, creates the GitHub release and publishes the package on PyPI
90
+ through Trusted Publishing.
91
+
92
+ ## License
93
+
94
+ [MIT](https://github.com/drscaon/primvaria/blob/main/LICENSE) © 2026 Daniel Régis Sarmento Caon
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "primvaria"
7
+ version = "0.1.0b1"
8
+ description = "Physics-ready variability for Physical AI, in OpenUSD: one install for the Granulaire, Maillage, Filaire and Quincaillerie asset generators, with a single command line."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [{ name = "Daniel Régis Sarmento Caon" }]
14
+ keywords = [
15
+ "openusd",
16
+ "physical-ai",
17
+ "robot-learning",
18
+ "simulation",
19
+ "synthetic-data",
20
+ "procedural",
21
+ "isaac-sim",
22
+ "mujoco",
23
+ "blender",
24
+ ]
25
+ classifiers = [
26
+ "Development Status :: 4 - Beta",
27
+ "Intended Audience :: Science/Research",
28
+ "Intended Audience :: Developers",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
35
+ "Topic :: Multimedia :: Graphics :: 3D Modeling",
36
+ ]
37
+ # A plain `pip install primvaria` installs the whole suite.
38
+ # Install a single generator on its own with `pip install granulaire` (etc.).
39
+ dependencies = [
40
+ "granulaire>=0.2.0b2",
41
+ "maillage>=0.1.0b1",
42
+ "filaire>=0.1.0b1",
43
+ "quincaillerie>=0.1.0b2",
44
+ ]
45
+
46
+ [project.optional-dependencies]
47
+ # previews and renders (matplotlib, Pillow)
48
+ render = ["granulaire[render]", "maillage[render]", "filaire[render]"]
49
+ # MuJoCo checks of Filaire and Quincaillerie
50
+ sim = ["filaire[sim]", "quincaillerie[sim]"]
51
+ # MaterialX materials of Quincaillerie
52
+ materialx = ["quincaillerie[materialx]"]
53
+ # everything above (Blender as a Python module stays separate: maillage[blender], Python 3.13 only)
54
+ all = ["primvaria[render,sim,materialx]"]
55
+ dev = ["pytest>=7", "ruff>=0.5"]
56
+
57
+ [project.urls]
58
+ Homepage = "https://github.com/drscaon/primvaria"
59
+ Issues = "https://github.com/drscaon/primvaria/issues"
60
+ Changelog = "https://github.com/drscaon/primvaria/blob/main/CHANGELOG.md"
61
+ Granulaire = "https://github.com/drscaon/granulaire"
62
+ Maillage = "https://github.com/drscaon/maillage"
63
+ Filaire = "https://github.com/drscaon/filaire"
64
+ Quincaillerie = "https://github.com/drscaon/quincaillerie"
65
+
66
+ [project.scripts]
67
+ primvaria = "primvaria.cli:main"
68
+
69
+ [tool.setuptools.packages.find]
70
+ where = ["src"]
71
+
72
+ [tool.pytest.ini_options]
73
+ testpaths = ["tests"]
74
+ addopts = "-q"
75
+
76
+ [tool.ruff]
77
+ line-length = 110
78
+ target-version = "py310"
79
+
80
+ [tool.ruff.lint]
81
+ select = ["E", "F", "W", "I", "UP", "B"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,12 @@
1
+ """Primvaria: physics-ready variability for Physical AI, in OpenUSD."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("primvaria")
7
+ except PackageNotFoundError: # running from a source tree without installing
8
+ __version__ = "0.0.0+unknown"
9
+
10
+ from .suite import MEMBERS, Member, get_member
11
+
12
+ __all__ = ["MEMBERS", "Member", "get_member", "__version__"]
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,63 @@
1
+ """Command line of the suite.
2
+
3
+ ``primvaria list`` shows the generators and their installed versions;
4
+ ``primvaria <generator> ...`` runs that generator's own command line, so
5
+ ``primvaria granulaire generate --preset beach_sand`` is the same as
6
+ ``granulaire generate --preset beach_sand``.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import sys
12
+
13
+ from . import __version__
14
+ from .suite import MEMBERS, get_member
15
+
16
+ USAGE = f"""\
17
+ usage: primvaria [--version] <command> [args...]
18
+
19
+ Physics-ready variability for Physical AI, in OpenUSD.
20
+
21
+ commands:
22
+ list the generators of the suite and their installed versions
23
+ <generator> [args] run a generator's command line ({", ".join(m.name for m in MEMBERS)})
24
+
25
+ examples:
26
+ primvaria list
27
+ primvaria granulaire generate --preset beach_sand
28
+ primvaria filaire --help
29
+ """
30
+
31
+
32
+ def _list() -> int:
33
+ width = max(len(m.name) for m in MEMBERS)
34
+ for m in MEMBERS:
35
+ installed = m.installed_version or "not installed"
36
+ print(f"{m.name:<{width}} {installed:<14} {m.summary}")
37
+ return 0
38
+
39
+
40
+ def main(argv: list[str] | None = None) -> int:
41
+ args = list(sys.argv[1:] if argv is None else argv)
42
+ if not args or args[0] in ("-h", "--help", "help"):
43
+ print(USAGE, end="")
44
+ return 0
45
+ command, rest = args[0], args[1:]
46
+ if command in ("-V", "--version"):
47
+ print(f"primvaria {__version__}")
48
+ return 0
49
+ if command == "list":
50
+ return _list()
51
+ try:
52
+ member = get_member(command)
53
+ except KeyError as e:
54
+ print(f"error: {e.args[0]}", file=sys.stderr)
55
+ return 2
56
+ if member.installed_version is None:
57
+ print(f"error: {member.name} is not installed (pip install {member.name})", file=sys.stderr)
58
+ return 2
59
+ return member.cli_main()(rest) or 0
60
+
61
+
62
+ if __name__ == "__main__":
63
+ raise SystemExit(main())
@@ -0,0 +1,64 @@
1
+ """The generators of the Primvaria suite and how to reach them."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib
6
+ from collections.abc import Callable
7
+ from dataclasses import dataclass
8
+ from importlib.metadata import PackageNotFoundError, version
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class Member:
13
+ """One generator of the suite: a separate package with its own command line."""
14
+
15
+ name: str
16
+ summary: str
17
+ repository: str
18
+
19
+ @property
20
+ def installed_version(self) -> str | None:
21
+ """Installed version of the package, or None when it is not installed."""
22
+ try:
23
+ return version(self.name)
24
+ except PackageNotFoundError:
25
+ return None
26
+
27
+ def cli_main(self) -> Callable[[list[str] | None], int]:
28
+ """The member's command-line entry point, ``<name>.cli:main``."""
29
+ return importlib.import_module(f"{self.name}.cli").main
30
+
31
+
32
+ MEMBERS: tuple[Member, ...] = (
33
+ Member(
34
+ "granulaire",
35
+ "granular assets: sand, gravel, pebbles, seeds, pellets",
36
+ "https://github.com/drscaon/granulaire",
37
+ ),
38
+ Member(
39
+ "maillage",
40
+ "textile assets: towels, napkins, tablecloths, sheets, flags",
41
+ "https://github.com/drscaon/maillage",
42
+ ),
43
+ Member(
44
+ "filaire",
45
+ "cable assets: standard cables with mating connectors",
46
+ "https://github.com/drscaon/filaire",
47
+ ),
48
+ Member(
49
+ "quincaillerie",
50
+ "hardware assets: threaded fasteners, battery cells and holders",
51
+ "https://github.com/drscaon/quincaillerie",
52
+ ),
53
+ )
54
+
55
+ _BY_NAME = {m.name: m for m in MEMBERS}
56
+
57
+
58
+ def get_member(name: str) -> Member:
59
+ """Look a member up by name; raises KeyError with the known names."""
60
+ try:
61
+ return _BY_NAME[name]
62
+ except KeyError:
63
+ known = ", ".join(_BY_NAME)
64
+ raise KeyError(f"unknown generator {name!r} (known: {known})") from None
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.4
2
+ Name: primvaria
3
+ Version: 0.1.0b1
4
+ Summary: Physics-ready variability for Physical AI, in OpenUSD: one install for the Granulaire, Maillage, Filaire and Quincaillerie asset generators, with a single command line.
5
+ Author: Daniel Régis Sarmento Caon
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/drscaon/primvaria
8
+ Project-URL: Issues, https://github.com/drscaon/primvaria/issues
9
+ Project-URL: Changelog, https://github.com/drscaon/primvaria/blob/main/CHANGELOG.md
10
+ Project-URL: Granulaire, https://github.com/drscaon/granulaire
11
+ Project-URL: Maillage, https://github.com/drscaon/maillage
12
+ Project-URL: Filaire, https://github.com/drscaon/filaire
13
+ Project-URL: Quincaillerie, https://github.com/drscaon/quincaillerie
14
+ Keywords: openusd,physical-ai,robot-learning,simulation,synthetic-data,procedural,isaac-sim,mujoco,blender
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
25
+ Requires-Python: >=3.10
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: granulaire>=0.2.0b2
29
+ Requires-Dist: maillage>=0.1.0b1
30
+ Requires-Dist: filaire>=0.1.0b1
31
+ Requires-Dist: quincaillerie>=0.1.0b2
32
+ Provides-Extra: render
33
+ Requires-Dist: granulaire[render]; extra == "render"
34
+ Requires-Dist: maillage[render]; extra == "render"
35
+ Requires-Dist: filaire[render]; extra == "render"
36
+ Provides-Extra: sim
37
+ Requires-Dist: filaire[sim]; extra == "sim"
38
+ Requires-Dist: quincaillerie[sim]; extra == "sim"
39
+ Provides-Extra: materialx
40
+ Requires-Dist: quincaillerie[materialx]; extra == "materialx"
41
+ Provides-Extra: all
42
+ Requires-Dist: primvaria[materialx,render,sim]; extra == "all"
43
+ Provides-Extra: dev
44
+ Requires-Dist: pytest>=7; extra == "dev"
45
+ Requires-Dist: ruff>=0.5; extra == "dev"
46
+ Dynamic: license-file
47
+
48
+ <h1 align="center">Primvaria</h1>
49
+
50
+ <p align="center"><strong>Physics-ready variability for Physical AI, in OpenUSD.</strong></p>
51
+
52
+ <p align="center">
53
+ <a href="https://github.com/drscaon/primvaria/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/drscaon/primvaria/actions/workflows/ci.yml/badge.svg"></a>
54
+ <img alt="Python 3.10+" src="https://img.shields.io/badge/python-3.10%2B-3776AB">
55
+ <img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-green">
56
+ </p>
57
+
58
+ Primvaria is a suite of procedural asset generators for the objects robots
59
+ struggle with most: grains, cloth, cables and small mechanical parts. Every
60
+ generator follows the same approach: **distributions instead of one shape**
61
+ (no two generated instances are the same, and what was drawn is written down
62
+ as ground truth), **measured outputs** (mass, shape, stiffness are measured on
63
+ what was generated, not trusted from the inputs) and **honest limits** (each
64
+ asset is checked in real engines, and what was not tested is said).
65
+
66
+ Every output is **OpenUSD** with standard `UsdPhysics` schemas, plus PhysX
67
+ attributes for **NVIDIA Omniverse and Isaac Sim**: one file format for
68
+ Blender, usdview, Omniverse and the other OpenUSD-aware tools, read back into
69
+ MuJoCo for the checks. Each generator's README says in which engines its
70
+ assets have been tested so far. Everything can run on CPU.
71
+
72
+ The name comes from *primvar*, OpenUSD's primitive variable, and *varia*,
73
+ Latin for "diverse things".
74
+
75
+ ## The generators
76
+
77
+ | | Generator | Assets | Physics |
78
+ |---|---|---|---|
79
+ | ![Granulaire](https://raw.githubusercontent.com/drscaon/granulaire/main/docs/images/moisture_gallery.png) | [**Granulaire**](https://github.com/drscaon/granulaire) | sand, gravel, pebbles, seeds, fruit, pellets, packing peanuts; measured shapes, masses and moisture | rigid bodies; deformables for OmniPhysics (not tested yet) |
80
+ | ![Maillage](https://raw.githubusercontent.com/drscaon/maillage/main/docs/images/blender_drape.jpg) | [**Maillage**](https://github.com/drscaon/maillage) | towels, napkins, tablecloths, sheets, scarves, flags; real sizes, fabrics and masses | cloth meshes; drape test in Blender |
81
+ | ![Filaire](https://raw.githubusercontent.com/drscaon/filaire/main/docs/images/hero.jpg) | [**Filaire**](https://github.com/drscaon/filaire) | standard cables with male and female connectors and the receptacles they plug into | rigid-segment chains with joints; drop, sag and insertion tests in MuJoCo |
82
+ | ![Quincaillerie](https://raw.githubusercontent.com/drscaon/quincaillerie/main/docs/images/fasteners.jpg) | [**Quincaillerie**](https://github.com/drscaon/quincaillerie) | metric screws, nuts and washers with modelled threads; battery cells and their holders | rigid bodies, springs and clips; drop, screwing and insertion tests in MuJoCo and Blender |
83
+
84
+ Each generator is its own package, released on its own schedule. Primvaria
85
+ installs them together and gives them one command line.
86
+
87
+ ## Installation
88
+
89
+ ```bash
90
+ pip install primvaria # the four generators
91
+ pip install "primvaria[all]" # + renders, MuJoCo checks, MaterialX
92
+ ```
93
+
94
+ | Extra | Adds |
95
+ |---|---|
96
+ | `render` | previews and renders (matplotlib, Pillow) |
97
+ | `sim` | the MuJoCo checks of Filaire and Quincaillerie |
98
+ | `materialx` | MaterialX materials of Quincaillerie |
99
+ | `all` | all of the above |
100
+
101
+ Blender as a Python module is installed with `pip install "maillage[blender]"`
102
+ (Python 3.13 only, as the `bpy` wheels exist for one Python version). Only one
103
+ generator? Install it alone: `pip install granulaire`.
104
+
105
+ ## Usage
106
+
107
+ ```bash
108
+ primvaria list # generators and installed versions
109
+ primvaria granulaire generate --preset beach_sand
110
+ primvaria maillage generate --preset tea_towel
111
+ primvaria filaire generate --preset usb_c --length 2
112
+ primvaria quincaillerie generate screw M10 --with nut,washer --count 10
113
+ ```
114
+
115
+ `primvaria <generator> ...` runs that generator's own command line: it is the
116
+ same as typing `granulaire ...`, `maillage ...`, which keep working. From
117
+ Python, import the generators directly:
118
+
119
+ ```python
120
+ from granulaire import generate_scene, write_outputs
121
+
122
+ write_outputs(generate_scene("beach_sand"), "output")
123
+ ```
124
+
125
+ ## Development
126
+
127
+ The project follows **GitHub Flow**, like the four generators: `main` is
128
+ protected, every change goes through a pull request from a short-lived branch
129
+ (`feat/<name>`, `fix/<name>`, …), and CI must be green before merging.
130
+ Enable the pre-push hook once per clone with
131
+ `git config core.hooksPath .githooks`.
132
+
133
+ Releasing: on a `chore/release-X.Y.Z` branch, bump `version` in
134
+ `pyproject.toml` and move the `Unreleased` entries of `CHANGELOG.md` under
135
+ the new version; merge, then tag `vX.Y.Z` on `main`. The release workflow
136
+ tests, builds, creates the GitHub release and publishes the package on PyPI
137
+ through Trusted Publishing.
138
+
139
+ ## License
140
+
141
+ [MIT](https://github.com/drscaon/primvaria/blob/main/LICENSE) © 2026 Daniel Régis Sarmento Caon
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/primvaria/__init__.py
5
+ src/primvaria/__main__.py
6
+ src/primvaria/cli.py
7
+ src/primvaria/suite.py
8
+ src/primvaria.egg-info/PKG-INFO
9
+ src/primvaria.egg-info/SOURCES.txt
10
+ src/primvaria.egg-info/dependency_links.txt
11
+ src/primvaria.egg-info/entry_points.txt
12
+ src/primvaria.egg-info/requires.txt
13
+ src/primvaria.egg-info/top_level.txt
14
+ tests/test_cli.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ primvaria = primvaria.cli:main
@@ -0,0 +1,23 @@
1
+ granulaire>=0.2.0b2
2
+ maillage>=0.1.0b1
3
+ filaire>=0.1.0b1
4
+ quincaillerie>=0.1.0b2
5
+
6
+ [all]
7
+ primvaria[materialx,render,sim]
8
+
9
+ [dev]
10
+ pytest>=7
11
+ ruff>=0.5
12
+
13
+ [materialx]
14
+ quincaillerie[materialx]
15
+
16
+ [render]
17
+ granulaire[render]
18
+ maillage[render]
19
+ filaire[render]
20
+
21
+ [sim]
22
+ filaire[sim]
23
+ quincaillerie[sim]
@@ -0,0 +1 @@
1
+ primvaria
@@ -0,0 +1,45 @@
1
+ import pytest
2
+
3
+ from primvaria import MEMBERS, __version__, get_member
4
+ from primvaria.cli import main
5
+
6
+
7
+ def test_four_members():
8
+ assert [m.name for m in MEMBERS] == ["granulaire", "maillage", "filaire", "quincaillerie"]
9
+
10
+
11
+ def test_unknown_member():
12
+ with pytest.raises(KeyError, match="known: granulaire"):
13
+ get_member("sable")
14
+
15
+
16
+ def test_version(capsys):
17
+ assert main(["--version"]) == 0
18
+ assert capsys.readouterr().out.strip() == f"primvaria {__version__}"
19
+
20
+
21
+ def test_help(capsys):
22
+ assert main([]) == 0
23
+ assert "primvaria list" in capsys.readouterr().out
24
+
25
+
26
+ def test_list_shows_every_member(capsys):
27
+ assert main(["list"]) == 0
28
+ out = capsys.readouterr().out
29
+ for m in MEMBERS:
30
+ assert m.name in out
31
+
32
+
33
+ def test_unknown_command(capsys):
34
+ assert main(["sable"]) == 2
35
+ assert "unknown generator" in capsys.readouterr().err
36
+
37
+
38
+ @pytest.mark.parametrize("member", MEMBERS, ids=lambda m: m.name)
39
+ def test_dispatch_to_member(member, capsys):
40
+ if member.installed_version is None:
41
+ pytest.skip(f"{member.name} not installed")
42
+ with pytest.raises(SystemExit) as exc:
43
+ main([member.name, "--version"])
44
+ assert exc.value.code == 0
45
+ assert member.installed_version in capsys.readouterr().out