Generated props (TRELLIS)
The settlement furniture and loose items under public/props/ were generated from reference
images with TRELLIS.2, then prepared in the
prop workshop. The shipped packages do not need anything on this page: you
only need it to generate new props or regenerate existing ones.
Everything here runs in an isolated Python environment under .gear-work/, which is a local
workbench directory and not part of the repository. It uses the
Windows community port pinned to
revision d5d38f1e033a881e2c00e3137822ef8aa4e193de; the official project targets Linux.
Install uv, then run:
./scripts/setup-trellis.ps1The script:
- clones the port into
.gear-work/trellis2-sourceat the pinned revision (and refuses an existing checkout at a different revision); - applies
scripts/trellis2-sdpa.patch, which switches the port from FlashAttention (no supported Windows wheel) to PyTorch SDPA for sparse windowed and variable-length attention; - creates a Python 3.11 environment in
.gear-work/trellis2-envwith PyTorch 2.8 for CUDA 12.8; - installs the port’s
cumesh,flex_gemmando_voxelwheels andutils3dat a pinned commit, but not the port’s nvdiffrast or nvdiffrec_render wheels (see Licensing); - runs
scripts/trellis/patch_o_voxel_import.pyto remove theo_voxelinitializer’s eager import of its unused upstream baker (it keeps a backup, refuses an unexpected initializer, and is safe to rerun); - finishes with
scripts/trellis-assets.py --check.
It downloads code and Python packages only, never model weights (those come from Hugging Face the first time you generate), and it does not run the port’s own installer.
Model access
Section titled “Model access”The image encoder is Meta’s gated DINOv3 ViT-L checkpoint. Request access with your own Hugging Face account, then log the isolated environment in once:
& .gear-work/trellis2-env/Scripts/hf.exe auth loginLater downloads reuse that credential. Never put a token in source files. Use the ViT-L checkpoint above even if the access email links a larger one: TRELLIS was trained against it.
Two checks are available:
# CUDA, extensions and gated model access, without loading weights:& .gear-work/trellis2-env/Scripts/python.exe scripts/trellis-assets.py --check# Extension and bake imports only; no CUDA, no model access. Fails if nvdiffrast is imported:& .gear-work/trellis2-env/Scripts/python.exe scripts/trellis-assets.py --check-imports --offlineGenerate one prop
Section titled “Generate one prop”The input must be an RGBA PNG with real transparency around the object; the script rejects an opaque or fully transparent image. No background-removal model is used.
& .gear-work/trellis2-env/Scripts/python.exe scripts/trellis-assets.py ` --image path/to/my-prop.png ` --out .gear-work/trellis2-output/my-prop-01.glb ` --seed 1337 --triangles 5000 --texture 1024| Flag | Meaning |
|---|---|
--pipeline 512 (default) or 1024_cascade | The cascade also loads the 1024 shape and texture models for more detail. |
--steps N | Overrides the step count of all three samplers (4 to 50). |
--triangles N | Target of the exported, remeshed GLB (100 to 50,000). |
--texture 512|1024|2048 | Size of the baked texture maps. |
--keep-source | Also saves the native reconstruction as <id>.source.pt (see below). |
--offline | Uses the cached checkpoints only and fails if a file is missing. |
--seed N | Sampler seed (default 1337). |
The script always loads models in low-VRAM mode with SDPA attention. The output must be a new
.glb: existing files are never overwritten. Geometry is checked for finite, non-empty data
before export, which is not a substitute for looking at it. A <id>.recipe.json beside the GLB
records the input hash, source revision, seed, pipeline, sampler parameters, triangle and texture
settings, timings, peak PyTorch CUDA allocation (not total board VRAM), the bake used and the
licensing toolchain block. Close the game while generating to leave VRAM free.
With --keep-source, the archive holds the native mesh and material voxels before
remeshing (vertices, faces, attrs, coords, layout, voxel_size, origin,
voxel_shape, plus input hash, seed, pipeline, model and revision). It lets textures be re-baked
later without running inference again, and is large (hundreds of megabytes for a chair). It is a PyTorch
pickle: only load archives you made.
A larger output texture does not raise the reconstruction resolution. For best results generate a high-budget raw mesh first (the settlement batch used 50,000 triangles and 2048 px textures), inspect it from every side, and build LODs in the workshop. That separates reconstruction defects from simplification damage.
For thin objects such as folded cloth, make a low-triangle LOD by exporting again from the native archive instead of decimating the review export:
& .gear-work/trellis2-env/Scripts/python.exe scripts/trellis/rebake-from-source.py ` --source .gear-work/trellis2-output/<batch>/<id>.source.pt ` --out .gear-work/trellis2-output/<batch>/<id>.t4800.glb --triangles 4800 --texture 1024It runs the generator’s own export (remesh, decimation inside the remesher, texture bake) without inference, in under a minute. TRELLIS reconstructs thin cloth as a closed thin shell, and collapse decimation of the exported mesh folds the two walls through each other: a folded shirt comes out as crumpled paper at any budget, while the re-export keeps its collar and seams. It needs CUDA, so do not run it beside a batch job that is using most of the card: on Windows the two then share memory through the system and the job slows several times over.
Reference images
Section titled “Reference images”Ask for one physically plausible object in a clear three-quarter view, with soft neutral lighting, a genuinely transparent background including the negative spaces, substantial structural members and restrained surface detail. Include the whole silhouette. Avoid painted perspective, thin floating details, several views in one image, floor shadows and dramatic baked lighting. Leave out liquids, flames, foliage, light and text: those belong to the engine’s runtime systems. The result is a reconstruction, not an exact copy: small details such as carvings will differ from the reference.
A generator without transparency (Midjourney, for example) shoots the object on a flat
backdrop, and scripts/trellis/matte-reference.ts cuts it out:
npx tsx scripts/trellis/matte-reference.ts downloads/tunic.png ` art-input/trellis/wardrobe-drops-v2/tunic/reference.pngIt grows the backdrop inward from the image border, taking in the soft contact shadow that generators add even when told not to (a shadow is the backdrop’s hue made darker), drops small specks, estimates each edge pixel’s coverage against its own neighbouring backdrop and frees its colour of it, then centres the object on a transparent 1024 px square. It refuses an object that touches the image border. Name a backdrop colour far from the object’s in the prompt: pale or sky blue behind browns and creams, warm yellow behind blues, deep blue behind gold. A grey or steel object on a pale backdrop can be taken for shadow. Look at every result before generating from it, because whatever stays opaque becomes geometry.
Two options take a hard shadow’s core, too dark to carry the backdrop’s hue:
--shadow-min 0.12 accepts darker shadow of the same hue, and --dark 40 accepts any
near-black pixel the backdrop reaches. --dark is only for a light object: on dark leather it
eats the gaps between plates. --debug mask.png writes the decision itself, which is also
how to find where a refused image touches its border.
Batch generation
Section titled “Batch generation”The shipped props came from two manifests:
docs/settlement-props-generation.json(batchsettlement-props-v1): 84 jobs. Six styles (medieval, Grey, Skell, Nacre, Vesper and tree-bough) each have a chair, bench, bed, table, counter, workbench, shelf, storage barrel, planter, lamp, vessel and hearth, and twelve extra medieval village and farm props complete the set.docs/settlement-prop-variants-generation.json(batchsettlement-props-v2): 96 jobs, 84 alternate forms (variantOflinks each to its original) and 12 loose items such as books, bread, cutlery and plates.
Wearable items have their own manifest, docs/wardrobe-drops-v2-generation.json (batch
wardrobe-drops-v2): the dropped form of each garment, matching how it is worn, a gold
nugget, and the worn hood and pauldron. Its jobs also record imageSource (openai or
midjourney), which the recipe’s toolchain block carries so the notices name the right
source; a single --image run takes --image-source instead. Their drops are re-exported at
4800 triangles, prepared by scripts/blender/prepare-wardrobe-drop.py and promoted by
scripts/promote-wardrobe-drops.ts, which moves each texture onto the colour the item is worn
in (scripts/trellis/recolour-glb.ts). The worn pieces (hood, pauldron, helm, cuirass, belt,
plate legs and sabatons) are worn on every body instead: scripts/build-character-worn-gear.mjs
fits each into each body’s publication from assets/character/worn-gear.json. A generated model
that holds two worn pieces is cut first: scripts/trellis/split-glb.ts cuts along a plane (the
plate legs came with their sabatons, cut at the ankle), and scripts/trellis/mirror-half-glb.ts
rebuilds a half TRELLIS never made. Legs drawn pressed together are reconstructed as their union,
so one leg has no inner wall from the hip to the knee; the tool clips the leg exactly at its
middle plane and mirrors the outer half into its place. Before that, scripts/trellis/fill-texture-holes.ts fills the
black texels a bake leaves inside the UV charts of a thin closed shell, from the colour around
them, and for a single colour fabric scripts/trellis/even-texture.ts removes the stains TRELLIS
paints on the sides the reference never showed (the hood uses --radius 8 --strength 1 --max-gain 10 --fill-below 0.45 --chroma 0.8 at 2048 px), keeping only the fabric’s grain. Do not
use it on leather or plate, whose tonal variation is part of the look. Worn pieces are re-exported
from their native source at around ten thousand triangles with 2048 px textures: the fitter
handles that density, and it holds folds and rivets the 4800 triangle cut lost. The finished
source then goes to 1024 px JPEG with scripts/trellis/texture-size-glb.ts: the fitter copies
a source’s texture into the part it writes for every body, and packing only compresses a part’s
file (the 1024 px WebP pass covers a body’s own textures), so a 2048 px PNG shipped at about
4.5 MB per part per body.
Plate is fitted differently from cloth. A TRELLIS plate is a closed shell a few millimetres
thick, and pushing it out of the body moves both walls onto the same surface, where the lining
shows through the steel in patches; a recipe’s wall moves every vertex by the deepest push
within that distance, so the shell keeps its thickness. The stride sweep and the lift that let
cloth give way to a moving limb shred a rigid shell, so plate turns them off (sweep: false,
lift: false) and follows its carrier bones. A cuirass leaves the arms out of its limit
(exclude), or an idle arm resting against the torso pushes the plate’s side out past it, and
names the garment drawn beneath it (beneath: a gambeson under the cuirass, padded hose under
the plate legs), whose cut it is fitted over.
A TRELLIS shell’s outer wall and lining also pinch together along seams and share vertices
there, and an exported or averaged normal at such a vertex points the wrong way: the model shows
spots lit from behind, lit patches on a dark side and black ones on a lit side. The winding is
consistent, so normals are rebuilt from the faces (scripts/lib/shell-normals.mjs): a pinched
vertex gets one copy per side, and a normal averages only faces on its own side. The fitter does
this for every worn piece, and scripts/trellis/fix-shell-normals.ts does it for a drop model.
Each job records its id, style, type, intended height, LOD0 target, seed, reference image path,
output path and the prompt used for the reference. scripts/plan-settlement-props.mjs and
scripts/plan-settlement-prop-variants.mjs wrote these once; the variants planner refuses to
overwrite its manifest. Do not regenerate them over existing work, because job ids tie the
outputs, packages and workshop together.
Run a batch with:
& .gear-work/trellis2-env/Scripts/python.exe -u scripts/trellis-assets.py ` --batch docs/settlement-props-generation.json ` --pipeline 1024_cascade --steps 20 --triangles 50000 --texture 2048 ` --keep-source --offlineThe generation settings come from these flags, not from the manifest. One worker keeps the
models loaded, generates one job at a time, and polls every 15 seconds for reference images that
have not appeared yet. Only run one worker per GPU. Its state is in
.gear-work/trellis2-output/<batch>/status.json: per-job status (waiting-image, running,
complete, failed), counts and the worker’s PID.
- A job whose GLB and recipe already exist is marked complete and skipped, so a stopped batch resumes with the same command.
- A job left
runningby an interrupted worker goes back towaiting-imageon restart. waiting-imagealso covers queued jobs whose image already exists.- Failed jobs keep their error and are skipped. Fix the cause, then reset only those entries
to
waiting-image. - The worker exits when every job is complete or failed, or when nothing is left to do and an
inputs-complete.jsonmarker exists in the batch directory. Write that marker once all reference images are in place. - Write reference PNGs atomically (write elsewhere, then move), so the worker never reads a half-written file.
Other review tools
Section titled “Other review tools”These Blender scripts work on any GLB, outside the workshop:
scripts/blender/preview-glb.pyrenders clay and texture contact sheets.scripts/blender/render-prop-review.pyrenders four PBR material views under neutral lighting without changing materials or geometry, so reconstruction defects stay visible (--source,--out,--resolution, and--nodefor one LOD of a packed model).scripts/blender/optimize-settlement-prop.pyis a standalone review preparation: metre scale, a base-centred Y-up origin, three triangle-budgeted LODs, a convex hull of at most 128 vertices and anasset.jsonwith provenance. It refuses an existing output directory. The workshop uses its own preparation instead.
blender -b -t 2 --python-exit-code 1 --python scripts/blender/render-prop-review.py -- ` --source .gear-work/props/review/my-prop-01/lod0.glb ` --out .gear-work/props/review/my-prop-01-renders --resolution 900A whole-object convex hull is only a first collision proxy: it fills the space above a chair seat. Usable furniture needs separate colliders and measured sockets, which the workshop provides.
Licensing of the toolchain
Section titled “Licensing of the toolchain”Every stage that touches a shipped prop is permissively licensed or never redistributed:
| Stage | Tool | Licence | Redistributed |
|---|---|---|---|
| Generator | TRELLIS.2 code and microsoft/TRELLIS.2-4B weights | MIT | no (weights) |
| Image encoder | facebook/dinov3-vitl16-pretrain-lvd1689m | DINOv3 License (royalty-free, with use restrictions and a “Built with DINOv3” attribution for redistribution), gated | never; you need your own Hugging Face grant |
| Mesh extraction | cumesh, FlexGEMM, utils3d | MIT | no |
| Texture bake | Microsoft-derived scripts/trellis/o_voxel_bake.py with the original Pinionfall scripts/trellis/uv_rasterize.py | MIT; see the adjacent LICENSE-o-voxel.txt and LICENSE-uv-rasterize.txt notices | yes |
| Reference images | OpenAI gpt-image (API) | output owned by the author under OpenAI’s Services Agreement | no |
| Reference images | Midjourney (paid plan) | output owned by the author under the Midjourney Terms of Service | no |
The port’s own texture export (o_voxel.postprocess.to_glb) rasterises the UV layout through
nvdiffrast, and the port also ships nvdiffrec_render. Both are under NVIDIA’s Source Code
License, which is non-commercial. Neither is installed or needed. scripts/trellis/o_voxel_bake.py
is a vendored copy of to_glb whose rasteriser calls go through scripts/trellis/uv_rasterize.py
(pure PyTorch; uv_rasterize_test.py checks it against a naive reference). Do not install the
port’s nvdiffrast wheels.
Every shipped package’s textures come from this bake. Assets generated before the change were
re-baked from their native archives and their LOD maps rebuilt; the one asset that had no
archive, medieval-chair-01, was regenerated from its recorded reference image and seed and
prepared again.
Each package’s preparation.json carries the toolchain block that the third-party notices
summarise.
Written by release:site-sync from docs/trellis-assets.md at v2026.10.04. Edit the engine document, not this page.