Sand3D: 106,094 3D objects in one code substrate for language models
Sand3D is a set of 106,094 3D objects, each written as a short Python program in sand3d, our open library. Objaverse assets, CAD parts, articulated mechanisms and assemblies all follow the same rules of writing, so a language model can learn 3D from one consistent body of code. 10,456 of the objects are articulated.

| Dataset | Objects | Source |
|---|---|---|
| Sandflow/sand3d-objaverse | 66,887 | Objaverse |
| Sandflow/sand3d-cad | 24,495 | Zero-To-CAD (16,766), CADFS (7,729) |
| Sandflow/sand3d-articraft | 9,209 | Articraft |
| Sandflow/sand3d-automate | 3,169 | AutoMate (872 assemblies, 2,297 parts) |
| Sandflow/sand3d-simready | 2,334 | NVIDIA SimReady |
| Total | 106,094 | |
| All five datasets | Collection | Browse the objects and their code in the Explorer |
![]() sand3d-objaverse | ![]() sand3d-cad | ![]() sand3d-articraft |
![]() sand3d-simready | ![]() sand3d-automate |
Every object ships with its program, the OpenUSD file the program exports (it opens in the Hub's 3D viewer, joints included), and a render. The library is on PyPI (pip install sand3d), with its documentation at sand3d.sandflow.ai.
A library written for models
Blender's Python API, bpy, was designed to drive an editor and procedural pipelines: it selects objects, switches modes and edits whatever is active. CAD libraries and web 3D engines each bring their own conventions. A model that learns 3D through these tools has to learn the tools before it learns the shapes.
sand3d gives a model one regular structure. Every part has a name, every dimension is a parameter, each part is placed in its parent's frame, and articulated objects declare their joints. The same verbs cover a fastener, a chair and a cable machine. On 30 CAD parts, the same part takes 3.8 times fewer tokens in sand3d, written by hand, than in the Blender Python a language model writes for it. We built sand3d on the bet that this pays at every model size. A small model has little capacity to spend on a tool's conventions. A larger one can write long scripts, but a long script full of literals is hard to read back, edit and iterate on, for the model and for the person working with it. A short program of named parts and parameters is not.
Structure first, details after
Code written by people, Python especially, often declares its details first: constants at the top, helper functions next, and the assembly of the object at the bottom. For a model that writes code from left to right, this order is costly. It has to commit to details before it knows what the object is made of.
sand3d programs open with a table of contents. The first function is named after the object, holds no geometry, and lists the parts and how they fit together. The details follow, one function per part. Here is the head of a weight stack from the repository's examples:
def weight_stack(n_plates=14, selected=9):
"""The plates, then each detail on their anchors. Any `add_` line can be deleted:
the rest of the object does not change."""
stack = plate_column(n_plates)
add_bumpers(stack)
add_guide_rods(stack)
add_selector(stack, selected)
return stack.root
A model that writes this head knows where it is going. It can keep adding detail inside each function, and it knows when the object is complete: every part in the list has been written. The rules behind this layout are in the writing guidelines.
Knowing when to stop is a known difficulty in 3D code generation. The 3DCodeVerse authors report that their fine-tuned models could fall into repetitive loops under greedy decoding, and trained them with a dedicated preference step to make them terminate. Our internal experiments point the same way: when the structure comes first, the model settles on a plan and commits to it sooner. More in an upcoming preprint.
A recipe for the object
A mesh file describes a surface with a list of coordinates. A sand3d program holds few raw coordinates. It describes the object as a recipe: which parts it has, their dimensions, and where each one sits on another. Change a value in the recipe, run it again, and the object is rebuilt with that change. Remove an add_ line and that detail disappears while the rest stays in place.
This gives people and models a shared place to work. A person can read the program and edit one parameter; a model can propose a change to the recipe and the result can be checked by running it.
Clean by construction
Objaverse is open, and most of open 3D research has trained on it. It is also messy: triangle soups, broken meshes, objects with no parts. Teams either adapted their models to noisy data or cleaned it with heavy pre- and post-processing, and most of the cleaned versions were never released. Clean 3D data has largely stayed behind closed doors.
The objects in Sand3D are clean by construction, because each one is produced by running its program. Parts are separate and named. The programs build quad-dominant topology by construction (the OpenUSD files published today are triangulated at export). Articulated objects carry their joints.
This matters for artists. The meshes produced by surface generation models mostly serve them as a reference or a layout. A program split into parts lets an artist iterate on the parts they care about, with the decomposition that suits them, and it gives a model a place to learn the rules artists apply in their trade.

How the data was made
Each program rebuilds an existing 3D asset from one of the five sources. The programs were written by Sandflow's iterative agentic reconstruction pipeline, described in upcoming releases, then run again under sand3d to write the dataset's files. Each object carries an F-score that measures how closely the surface its program builds matches the source object, computed at 1% of the bounding-box diagonal. Objects below a floor were left out: 0.70 for Objaverse and static SimReady assets, 0.90 for CAD parts and rigid Articraft programs, and for articulated objects every part at 0.90 with every joint right. The dataset cards give the details per source.
Limitations
This release covers mostly hard-surface objects: furniture, tools, machines, mechanical parts, appliances. Characters, animals and organic shapes are not covered yet. They will need new verbs in the library. Candidates we are looking at:
- implicit surfaces that blend smoothly into each other, such as metaballs;
- subdivision surfaces driven by a control cage;
- sweeps and lofts along curves with a varying section, for limbs and stems;
- a skeleton with skinning, to pose a shape;
- procedural displacement for sculpted detail.
At the fidelity floors above, a program can also drop small details or noise that the source mesh carried.
This is a first release. More objects and more domains are coming.
Licence
The dataset is released under CC BY 4.0, commercial use allowed, with each object keeping the licence of its source; the sand3d library is released under Apache 2.0.
Links
- Datasets: huggingface.co/collections/Sandflow/sand3d
- Explorer: huggingface.co/spaces/Sandflow/sand3d-explorer
- Library: github.com/Sandflow-ai/sand3d
- Documentation: sand3d.sandflow.ai
- PyPI:
pip install sand3d(1.6.2)




