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.
- primvaria-0.1.0b1/LICENSE +21 -0
- primvaria-0.1.0b1/PKG-INFO +141 -0
- primvaria-0.1.0b1/README.md +94 -0
- primvaria-0.1.0b1/pyproject.toml +81 -0
- primvaria-0.1.0b1/setup.cfg +4 -0
- primvaria-0.1.0b1/src/primvaria/__init__.py +12 -0
- primvaria-0.1.0b1/src/primvaria/__main__.py +3 -0
- primvaria-0.1.0b1/src/primvaria/cli.py +63 -0
- primvaria-0.1.0b1/src/primvaria/suite.py +64 -0
- primvaria-0.1.0b1/src/primvaria.egg-info/PKG-INFO +141 -0
- primvaria-0.1.0b1/src/primvaria.egg-info/SOURCES.txt +14 -0
- primvaria-0.1.0b1/src/primvaria.egg-info/dependency_links.txt +1 -0
- primvaria-0.1.0b1/src/primvaria.egg-info/entry_points.txt +2 -0
- primvaria-0.1.0b1/src/primvaria.egg-info/requires.txt +23 -0
- primvaria-0.1.0b1/src/primvaria.egg-info/top_level.txt +1 -0
- primvaria-0.1.0b1/tests/test_cli.py +45 -0
|
@@ -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://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://github.com/drscaon/maillage) | towels, napkins, tablecloths, sheets, scarves, flags; real sizes, fabrics and masses | cloth meshes; drape test in Blender |
|
|
81
|
+
|  | [**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://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://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://github.com/drscaon/maillage) | towels, napkins, tablecloths, sheets, scarves, flags; real sizes, fabrics and masses | cloth meshes; drape test in Blender |
|
|
34
|
+
|  | [**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://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,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,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://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://github.com/drscaon/maillage) | towels, napkins, tablecloths, sheets, scarves, flags; real sizes, fabrics and masses | cloth meshes; drape test in Blender |
|
|
81
|
+
|  | [**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://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 @@
|
|
|
1
|
+
|
|
@@ -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
|