models/Pixal3D/run_pixal3d.py — our own runner. Upstream's argparse forwards only 7 of run_inference()'s ~20 kwargs, so the entire three-phase sampler surface is unreachable from the CLI. Also neutralises upstream's lossy extension_webp=True export.
src/artpipe/models/pixal3d.py — Pixal3DBackend, modelled on trellis_mac.py: pure build_inference_command, bounded monotonic scan_progress_line, require_cuda_linux() guard, watchdog + stderr drain, output sanity check.
src/artpipe/config.py — TIMEOUT_PIXAL3D = 2700; pixal3d added to the CUDA profiles' allowed_models["modeling"] (NOT the default — hunyuan3d stays).
tests/test_pixal3d_backend.py — 33 pure-function tests, runnable on any host.
Setup-command ordering matters and is not the README's order: clone TRELLIS.2 → its setup.sh --basic --nvdiffrast --nvdiffrec --cumesh --o-voxel --flexgemm (verified: conda is only touched under --new-env; every other flag is plain pip) → Pixal3D requirements.txt → natten==0.21.0 → the utils3d wheel LAST, since it deliberately overrides the copy TRELLIS.2's --basic installs from git.
--flash-attn is skipped: ATTN_BACKEND=sdpa is read from env at import of pixal3d/modules/attention/config.py, and flash_attn is only imported inside functions. That legitimately avoids a multi-hour build.
Full suite unaffected — 734 passed; the 18 test_batch_stages errors are a pre-existing missing-flask gap, confirmed identical with the changes stashed
scripts/validate_model_manifests.py clean (only the known MediaPipe resource dir)
artpipe setup --model Pixal3D on the 4090 — the first real test of the setup-command chain
POST /jobs {model: "pixal3d", action: "image_to_3d"} on the 4090; record wall-clock + peak VRAM to confirm the 18000 declaration and TIMEOUT_PIXAL3D
Import the resulting GLB through Blender 5.1 import_gltf_compat() and confirm all PBR channels survive
Part of #833.
Add the `pixal3d` model to `spikersoft-artpipe`:
- `models/Pixal3D/artpipe.json` — `image_to_3d`, `vram_mb: 18000`, python 3.10 / cu128, `ATTN_BACKEND=sdpa`, `install.repo` + `extra_weights` (MoGe-2, DINOv3, BiRefNet), `verify_imports` for the compiled extensions.
- `models/Pixal3D/run_pixal3d.py` — our own runner. Upstream's argparse forwards only 7 of `run_inference()`'s ~20 kwargs, so the entire three-phase sampler surface is unreachable from the CLI. Also neutralises upstream's lossy `extension_webp=True` export.
- `src/artpipe/models/pixal3d.py` — `Pixal3DBackend`, modelled on `trellis_mac.py`: pure `build_inference_command`, bounded monotonic `scan_progress_line`, `require_cuda_linux()` guard, watchdog + stderr drain, output sanity check.
- `src/artpipe/config.py` — `TIMEOUT_PIXAL3D = 2700`; `pixal3d` added to the CUDA profiles' `allowed_models["modeling"]` (NOT the default — hunyuan3d stays).
- `tests/test_pixal3d_backend.py` — 33 pure-function tests, runnable on any host.
**Setup-command ordering matters** and is not the README's order: clone TRELLIS.2 → its `setup.sh --basic --nvdiffrast --nvdiffrec --cumesh --o-voxel --flexgemm` (verified: conda is only touched under `--new-env`; every other flag is plain pip) → Pixal3D `requirements.txt` → `natten==0.21.0` → **the utils3d wheel LAST**, since it deliberately overrides the copy TRELLIS.2's `--basic` installs from git.
`--flash-attn` is skipped: `ATTN_BACKEND=sdpa` is read from env at import of `pixal3d/modules/attention/config.py`, and flash_attn is only imported inside functions. That legitimately avoids a multi-hour build.
## Verification
- [x] `pytest tests/test_pixal3d_backend.py` — 33 passed (Mac)
- [x] Full suite unaffected — 734 passed; the 18 `test_batch_stages` errors are a pre-existing missing-`flask` gap, confirmed identical with the changes stashed
- [x] `scripts/validate_model_manifests.py` clean (only the known MediaPipe resource dir)
- [ ] `artpipe setup --model Pixal3D` on the 4090 — the first real test of the setup-command chain
- [ ] `POST /jobs {model: "pixal3d", action: "image_to_3d"}` on the 4090; record wall-clock + peak VRAM to confirm the 18000 declaration and `TIMEOUT_PIXAL3D`
- [ ] Import the resulting GLB through Blender 5.1 `import_gltf_compat()` and confirm all PBR channels survive
⚠️ Export the gate knobs before the :9100 run, or it looks like a Pixal3D hang
artpipe serve + POST /jobs on the 4090 needs #835's overrides exported, otherwise _acquire_gpu waits out TIMEOUT_VRAM_WAIT (120s) and gives up with "GPU admit timeout" — nothing about that message points at the admission gate:
(18000 × 1.4 = 25200 exceeds the card's total 24576, so the default factor alone makes it unadmittable.) Merge #34 first, or the constants aren't overridable at all.
Two review findings fixed in a follow-up commit on PR #33
1. The lossless-texture guarantee wasn't actually guaranteed.force_png_textures() patches trimesh.Scene / trimesh.Trimesh, but o_voxel.postprocess.to_glb() returns whatever it returns — a wrapper type or a subclass registered elsewhere would slip past the patch, extension_webp=True would reach the exporter, and every PBR map would come out lossy q80 while the log still said "PNG (lossless)". The original test only exercised the mechanism against classes the test itself defined, so it could never have caught that.
Replaced with a postcondition on the real artifact: parse the GLB's JSON chunk and fail if EXT_texture_webp is declared while texture_format=png. Unparseable input is treated as "couldn't tell", never as "contains WebP".
2. TRELLIS.2's --basic would have clobbered Pixal3D's pins.venv_setup pip-installs the cloned repo's requirements.txtbeforesetup_commands run (Pixal3D ships requirements.txt but no setup.py, so the editable branch is skipped). --basic then installed unpinned transformers/trimesh over Pixal3D's transformers==4.57.3 / trimesh==4.10.1, plus abandoned pillow-simd (conflicts with pillow==12.0.0, wants sudo apt). Dropped --basic; ninja is installed explicitly as the only piece the extension builds still need.
Also confirmed rather than assumed: cumesh is the correct import name (pyproject.tomlname = "cumesh"), and NATTEN_CUDA_ARCH takes the dotted form — _check_cuda_arch does float(arch) * 10, so 8.6;8.9 is right and 86;89 would have built for SM860.
Tests now 43 passed, 1 skipped.
### ⚠️ Export the gate knobs before the `:9100` run, or it looks like a Pixal3D hang
`artpipe serve` + `POST /jobs` on the 4090 needs #835's overrides exported, otherwise `_acquire_gpu` waits out `TIMEOUT_VRAM_WAIT` (120s) and gives up with "GPU admit timeout" — nothing about that message points at the admission gate:
```bash
export ARTPIPE_VRAM_OVERHEAD_FACTOR=1.15
export ARTPIPE_VRAM_MAX_UTILIZATION=0.95
artpipe serve --root .
```
(18000 × 1.4 = 25200 exceeds the card's *total* 24576, so the default factor alone makes it unadmittable.) Merge #34 first, or the constants aren't overridable at all.
### Two review findings fixed in a follow-up commit on PR #33
**1. The lossless-texture guarantee wasn't actually guaranteed.** `force_png_textures()` patches `trimesh.Scene` / `trimesh.Trimesh`, but `o_voxel.postprocess.to_glb()` returns whatever it returns — a wrapper type or a subclass registered elsewhere would slip past the patch, `extension_webp=True` would reach the exporter, and every PBR map would come out lossy q80 **while the log still said "PNG (lossless)"**. The original test only exercised the mechanism against classes the test itself defined, so it could never have caught that.
Replaced with a postcondition on the real artifact: parse the GLB's JSON chunk and fail if `EXT_texture_webp` is declared while `texture_format=png`. Unparseable input is treated as "couldn't tell", never as "contains WebP".
**2. TRELLIS.2's `--basic` would have clobbered Pixal3D's pins.** `venv_setup` pip-installs the cloned repo's `requirements.txt` *before* `setup_commands` run (Pixal3D ships `requirements.txt` but no `setup.py`, so the editable branch is skipped). `--basic` then installed unpinned `transformers`/`trimesh` over Pixal3D's `transformers==4.57.3` / `trimesh==4.10.1`, plus abandoned `pillow-simd` (conflicts with `pillow==12.0.0`, wants `sudo apt`). Dropped `--basic`; `ninja` is installed explicitly as the only piece the extension builds still need.
Also confirmed rather than assumed: `cumesh` is the correct import name (`pyproject.toml` `name = "cumesh"`), and `NATTEN_CUDA_ARCH` takes the **dotted** form — `_check_cuda_arch` does `float(arch) * 10`, so `8.6;8.9` is right and `86;89` would have built for SM860.
Tests now 43 passed, 1 skipped.
Merged in spikersoft-artpipe PR #33 (main, commits 9993347 + fe0a1ff).
⚠️main currently ships a known bug — the two review fixes above were pushed ~8 minutes after #33 merged, so they missed the window. They're now in PR #35:
TRELLIS.2's --basic clobbers Pixal3D's transformers==4.57.3 / trimesh==4.10.1 pins and pulls abandoned pillow-simd. Do not build the pixal3d env image until #35 merges — the venv it produces would have the wrong dependency set.
The lossless-texture guarantee has no artifact-level check, so a missed patch would produce lossy q80 maps silently.
Keeping this open until #35 lands and the 4090 verification steps are done.
Merged in spikersoft-artpipe PR #33 (`main`, commits `9993347` + `fe0a1ff`).
**⚠️ `main` currently ships a known bug** — the two review fixes above were pushed ~8 minutes after #33 merged, so they missed the window. They're now in **PR #35**:
- TRELLIS.2's `--basic` clobbers Pixal3D's `transformers==4.57.3` / `trimesh==4.10.1` pins and pulls abandoned `pillow-simd`. **Do not build the `pixal3d` env image until #35 merges** — the venv it produces would have the wrong dependency set.
- The lossless-texture guarantee has no artifact-level check, so a missed patch would produce lossy q80 maps silently.
Keeping this open until #35 lands and the 4090 verification steps are done.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part of #833.
Add the
pixal3dmodel tospikersoft-artpipe:models/Pixal3D/artpipe.json—image_to_3d,vram_mb: 18000, python 3.10 / cu128,ATTN_BACKEND=sdpa,install.repo+extra_weights(MoGe-2, DINOv3, BiRefNet),verify_importsfor the compiled extensions.models/Pixal3D/run_pixal3d.py— our own runner. Upstream's argparse forwards only 7 ofrun_inference()'s ~20 kwargs, so the entire three-phase sampler surface is unreachable from the CLI. Also neutralises upstream's lossyextension_webp=Trueexport.src/artpipe/models/pixal3d.py—Pixal3DBackend, modelled ontrellis_mac.py: purebuild_inference_command, bounded monotonicscan_progress_line,require_cuda_linux()guard, watchdog + stderr drain, output sanity check.src/artpipe/config.py—TIMEOUT_PIXAL3D = 2700;pixal3dadded to the CUDA profiles'allowed_models["modeling"](NOT the default — hunyuan3d stays).tests/test_pixal3d_backend.py— 33 pure-function tests, runnable on any host.Setup-command ordering matters and is not the README's order: clone TRELLIS.2 → its
setup.sh --basic --nvdiffrast --nvdiffrec --cumesh --o-voxel --flexgemm(verified: conda is only touched under--new-env; every other flag is plain pip) → Pixal3Drequirements.txt→natten==0.21.0→ the utils3d wheel LAST, since it deliberately overrides the copy TRELLIS.2's--basicinstalls from git.--flash-attnis skipped:ATTN_BACKEND=sdpais read from env at import ofpixal3d/modules/attention/config.py, and flash_attn is only imported inside functions. That legitimately avoids a multi-hour build.Verification
pytest tests/test_pixal3d_backend.py— 33 passed (Mac)test_batch_stageserrors are a pre-existing missing-flaskgap, confirmed identical with the changes stashedscripts/validate_model_manifests.pyclean (only the known MediaPipe resource dir)artpipe setup --model Pixal3Don the 4090 — the first real test of the setup-command chainPOST /jobs {model: "pixal3d", action: "image_to_3d"}on the 4090; record wall-clock + peak VRAM to confirm the 18000 declaration andTIMEOUT_PIXAL3Dimport_gltf_compat()and confirm all PBR channels survive⚠️ Export the gate knobs before the
:9100run, or it looks like a Pixal3D hangartpipe serve+POST /jobson the 4090 needs #835's overrides exported, otherwise_acquire_gpuwaits outTIMEOUT_VRAM_WAIT(120s) and gives up with "GPU admit timeout" — nothing about that message points at the admission gate:(18000 × 1.4 = 25200 exceeds the card's total 24576, so the default factor alone makes it unadmittable.) Merge #34 first, or the constants aren't overridable at all.
Two review findings fixed in a follow-up commit on PR #33
1. The lossless-texture guarantee wasn't actually guaranteed.
force_png_textures()patchestrimesh.Scene/trimesh.Trimesh, buto_voxel.postprocess.to_glb()returns whatever it returns — a wrapper type or a subclass registered elsewhere would slip past the patch,extension_webp=Truewould reach the exporter, and every PBR map would come out lossy q80 while the log still said "PNG (lossless)". The original test only exercised the mechanism against classes the test itself defined, so it could never have caught that.Replaced with a postcondition on the real artifact: parse the GLB's JSON chunk and fail if
EXT_texture_webpis declared whiletexture_format=png. Unparseable input is treated as "couldn't tell", never as "contains WebP".2. TRELLIS.2's
--basicwould have clobbered Pixal3D's pins.venv_setuppip-installs the cloned repo'srequirements.txtbeforesetup_commandsrun (Pixal3D shipsrequirements.txtbut nosetup.py, so the editable branch is skipped).--basicthen installed unpinnedtransformers/trimeshover Pixal3D'stransformers==4.57.3/trimesh==4.10.1, plus abandonedpillow-simd(conflicts withpillow==12.0.0, wantssudo apt). Dropped--basic;ninjais installed explicitly as the only piece the extension builds still need.Also confirmed rather than assumed:
cumeshis the correct import name (pyproject.tomlname = "cumesh"), andNATTEN_CUDA_ARCHtakes the dotted form —_check_cuda_archdoesfloat(arch) * 10, so8.6;8.9is right and86;89would have built for SM860.Tests now 43 passed, 1 skipped.
Merged in spikersoft-artpipe PR #33 (
main, commits9993347+fe0a1ff).⚠️
maincurrently ships a known bug — the two review fixes above were pushed ~8 minutes after #33 merged, so they missed the window. They're now in PR #35:--basicclobbers Pixal3D'stransformers==4.57.3/trimesh==4.10.1pins and pulls abandonedpillow-simd. Do not build thepixal3denv image until #35 merges — the venv it produces would have the wrong dependency set.Keeping this open until #35 lands and the 4090 verification steps are done.