Clean-room Rust 3D inference toolkit for Pi3, Pi3X, and TripoSR (Lux3D / candle-3d): contract inspection, canonical weight tooling, and CLI runtime
Rust
1
57 commits
updated Sep 9, 2026
Rust workspace for clean-room 3D inference, contract inspection, and weight canonicalization.
CUDA-first runtime for Pi3, Pi3X, and TripoSR.
Lux3D / candle-3d is a Rust 2024 workspace that provides:
Supported model families:
pi3pi3xtriposrlux3d-core implements contracts, runtime loading, export logic, and weight validation.lux3d-cli exposes inspect, weights normalize, and run.lux3d-server-core exposes an OpenAI-style async HTTP API for Pi3, Pi3X, and TripoSR generation.tools/python_baseline/README.md.--device vulkan / --device wgpu (build with --features vulkan / --features wgpu). Not production-ready — may be unstable, produce wrong results, or not work at all depending on hardware and drivers. CUDA is the only verified backend.https://github.com/user-attachments/assets/0a9f766f-68d3-482a-9c94-c55d0c355808
| Path | Purpose |
|---|---|
crates/lux3d-core | Core runtime, contracts, geometry/export code, and weight validation |
crates/lux3d-cli | CLI front-end for inspection, normalization, and inference runs |
crates/lux3d-server-core | Embeddable Axum router and HTTP API for external applications |
crates/lux3d-server | Standalone HTTP server binary |
tools/python_baseline | Python parity tooling and canonical-weight normalization scripts |
.github/assets | Project documentation assets |
cargo metadata --no-deps
cargo run -p lux3d-cli -- --help
cargo run -p lux3d-cli -- inspect --repo-root <runtime-root> pi3
cargo run -p lux3d-cli -- inspect --repo-root <runtime-root> pi3x
cargo run -p lux3d-cli -- inspect --repo-root <runtime-root> triposr
cargo run -p lux3d-cli -- weights normalize --repo-root <runtime-root> --raw-model-dir <raw-pi3-dir> --output-dir <canonical-pi3-dir> pi3
cargo run -p lux3d-cli -- weights normalize --repo-root <runtime-root> --raw-model-dir <raw-pi3x-dir> --output-dir <canonical-pi3x-dir> pi3x
cargo run -p lux3d-cli -- weights normalize --repo-root <runtime-root> --raw-model-dir <raw-triposr-dir> --output-dir <canonical-triposr-dir> triposr
# Pi3 -> PLY with an explicit canonical package directory (layout matches 3d/canonical-weights/pi3)
cargo run -p lux3d-cli -- run pi3 --model-path <canonical-pi3-dir> --source <input-sequence> --output <output-file.ply>
# Pi3X core -> PLY with an explicit canonical package directory (layout matches 3d/canonical-weights/pi3x)
cargo run -p lux3d-cli -- run pi3x --model-path <canonical-pi3x-dir> --source <input-sequence> --conditions <conditions-file> --output <output-file.ply>
# Pi3X VO -> PLY with an explicit canonical package directory (layout matches 3d/canonical-weights/pi3x)
cargo run -p lux3d-cli -- run pi3x --model-path <canonical-pi3x-dir> --source <input-video> --vo --chunk-size 8 --overlap 4 --conf-threshold 0.05 --inject-condition pose,depth,ray --output <output-file.ply>
# TripoSR -> OBJ with an explicit canonical package directory (layout matches 3d/canonical-weights/triposr)
cargo run -p lux3d-cli -- run triposr --model-path <canonical-triposr-dir> --source <input-image> --mc-resolution 256 --mc-threshold 25.0 --output <output-file.obj>
# Auto-download canonical packages from Hugging Face into the user cache
cargo run -p lux3d-cli -- run pi3 --source <input-sequence> --output <output-file.ply>
Experimental backends (Vulkan / WGPU): select a non-CUDA device with
--device:cargo run -p lux3d-cli --features vulkan -- run triposr --device vulkan --source <input-image> --output <output-file.obj> cargo run -p lux3d-cli --features wgpu -- run pi3 --device wgpu --source <input-sequence> --output <output-file.ply>These paths are experimental and not verified in CI. Inference may be unstable, produce incorrect output, or fail entirely depending on your GPU, driver, and OS. Use CUDA for production workloads.
cargo run -p lux3d-server -- --host 127.0.0.1 --port 8080
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/v1/models
Generation endpoints accept multipart/form-data and return 202 Accepted with an async job object:
| Endpoint | Models | Output |
|---|---|---|
POST /v1/point-clouds/generations | pi3, pi3x | PLY |
POST /v1/meshes/generations | triposr | OBJ |
Common fields:
model — required for point clouds (pi3 or pi3x), optional for meshes (triposr default)source — required upload (.zip frame archive, .mp4 video, or image)conditions — optional Pi3X conditions fileoptions — optional JSON string with family-specific parametersWorkflow:
# 1. Create a mesh generation job
curl -X POST http://127.0.0.1:8080/v1/meshes/generations `
-F "model=triposr" `
-F "source=@input.png" `
-F "options={\"mc_resolution\":256,\"mc_threshold\":25.0}"
# 2. Poll job status
curl http://127.0.0.1:8080/v1/generations/gen_...
# 3. Download completed asset
curl http://127.0.0.1:8080/v1/generations/gen_.../content --output mesh.obj
Embed the router in another Axum app:
use lux3d_server_core::{
lux3d_for_server_builder::Lux3dForServerBuilder,
lux3d_server_router_builder::Lux3dServerRouterBuilder,
};
let lux3d = Lux3dForServerBuilder::new().build()?;
let routes = Lux3dServerRouterBuilder::new()
.with_lux3d(lux3d)
.build()
.await?;
let app = axum::Router::new().nest("/api/lux3d", routes);
Measured inference time ([stage] infer: preprocessing + neural pass, single iteration per process, weights excluded) on an NVIDIA GeForce RTX 3060 12 GiB, Windows (WDDM), candle wgpu/vulkan fork rev efb506c9, candle-3d (2026-09-06):
| model | CUDA | Vulkan | WGPU | Vulkan/CUDA | WGPU/CUDA |
|---|---|---|---|---|---|
| pi3 (5 frames, 518×518) | 4.82 s | 7.83 s | 13.96 s | 1.62× | 2.90× |
| pi3x (6 frames, 518×518) | 7.00 s | 11.10 s | 31.84 s | 1.59× | 4.55× |
| triposr (single image) | 1.23 s | 3.36 s | 4.89 s | 2.73× | 3.98× |
Warm-loop criterion (10 samples, steady state — the candle-bench protocol, one back-to-back window): vulkan 3.14 s / 4.90 s per iter (1.16×/1.20× of CUDA 2.72 s / 4.09 s), wgpu 8.21 s / 24.0 s (3.0×/5.9×). The biggest single lever was a fused LayerNorm+RoPE kernel (rope_layernorm.comp/.wgsl in the fork): one dispatch per q/k replaces the slow-path LayerNorm, both surrounding copies, and the 8-op rope chain at every rope site, cutting wgpu pi3 from 54.9 s to 8.21 s warm.
Correctness: outputs of every backend × model combination were verified against the CUDA reference meshes (bounding box / center / mean delta within 1% of max extent, vertex/face counts within 0.5% — all PASS); the fused kernel is additionally unit-tested exact to 0.0 diff against the composed form on both backends.
Memory behavior under repeated inference (10-iteration loop, same process):
LUX3D_MAX_SDPA_SCORES_BYTES), which removes a ~4 GiB transient that previously fragmented the CUDA memory pool and stalled a 12 GiB card ~100×.CANDLE_VK_INFLIGHT_GRACE, CANDLE_VK_POOL_MAX_BYTES). Batch caps are tuned from flush-reason profiling: transfer bytes 512 MiB (CANDLE_VK_MAX_BATCH_TRANSFER_BYTES), descriptor sets 8× dispatches — closing the batch per big activation copy cost ~4-9 ms of WDDM fence-signal latency per submission.CANDLE_WGPU_POOL_MAX_BYTES, CANDLE_WGPU_INFLIGHT_MAX_BYTES).Known gaps: the remaining Vulkan/CUDA warm gap (1.16–1.20×) is the structural WDDM submit tax (~4-9 ms per submission on a strictly dependent op chain) — a platform property code cannot reach; Linux without WDDM would close it. WGPU remains 3.0–5.9× behind warm (down from 13.9–19.5×), dominated by WGSL GEMM quality plus the same inter-pass WDDM gaps. A criterion harness for whole-model benches lives in crates/lux3d-core/benches/ (run one (backend, model) pair per process: LUX3D_BENCH_DEVICE=… LUX3D_BENCH_MODEL=… cargo bench -p lux3d-core --bench bench_main --features vulkan,wgpu).
edition = "2024"wgpu/vulkan fork): verified for correctness and memory stability on RTX 3060 (see Performance); slower than CUDA, WGPU substantially so.--model-path, or downloadable from Hugging Face into the user cacheThe code and documentation in this repository are licensed under Apache 2.0. See LICENSE.
Upstream model assets and canonicalized model artifacts keep their original licenses and usage restrictions. Review model-family-specific terms before redistribution.
57 commits
Rust
86.7%
Python
9.2%
PowerShell
3.4%
Clean-room Rust 3D inference toolkit for Pi3, Pi3X, and TripoSR (Lux3D / candle-3d): contract inspection, canonical weight tooling, and CLI runtime
Rust
1
57 commits
updated Sep 9, 2026
Rust workspace for clean-room 3D inference, contract inspection, and weight canonicalization.
CUDA-first runtime for Pi3, Pi3X, and TripoSR.
Lux3D / candle-3d is a Rust 2024 workspace that provides:
Supported model families:
pi3pi3xtriposrlux3d-core implements contracts, runtime loading, export logic, and weight validation.lux3d-cli exposes inspect, weights normalize, and run.lux3d-server-core exposes an OpenAI-style async HTTP API for Pi3, Pi3X, and TripoSR generation.tools/python_baseline/README.md.--device vulkan / --device wgpu (build with --features vulkan / --features wgpu). Not production-ready — may be unstable, produce wrong results, or not work at all depending on hardware and drivers. CUDA is the only verified backend.https://github.com/user-attachments/assets/0a9f766f-68d3-482a-9c94-c55d0c355808
| Path | Purpose |
|---|---|
crates/lux3d-core | Core runtime, contracts, geometry/export code, and weight validation |
crates/lux3d-cli | CLI front-end for inspection, normalization, and inference runs |
crates/lux3d-server-core | Embeddable Axum router and HTTP API for external applications |
crates/lux3d-server | Standalone HTTP server binary |
tools/python_baseline | Python parity tooling and canonical-weight normalization scripts |
.github/assets | Project documentation assets |
cargo metadata --no-deps
cargo run -p lux3d-cli -- --help
cargo run -p lux3d-cli -- inspect --repo-root <runtime-root> pi3
cargo run -p lux3d-cli -- inspect --repo-root <runtime-root> pi3x
cargo run -p lux3d-cli -- inspect --repo-root <runtime-root> triposr
cargo run -p lux3d-cli -- weights normalize --repo-root <runtime-root> --raw-model-dir <raw-pi3-dir> --output-dir <canonical-pi3-dir> pi3
cargo run -p lux3d-cli -- weights normalize --repo-root <runtime-root> --raw-model-dir <raw-pi3x-dir> --output-dir <canonical-pi3x-dir> pi3x
cargo run -p lux3d-cli -- weights normalize --repo-root <runtime-root> --raw-model-dir <raw-triposr-dir> --output-dir <canonical-triposr-dir> triposr
# Pi3 -> PLY with an explicit canonical package directory (layout matches 3d/canonical-weights/pi3)
cargo run -p lux3d-cli -- run pi3 --model-path <canonical-pi3-dir> --source <input-sequence> --output <output-file.ply>
# Pi3X core -> PLY with an explicit canonical package directory (layout matches 3d/canonical-weights/pi3x)
cargo run -p lux3d-cli -- run pi3x --model-path <canonical-pi3x-dir> --source <input-sequence> --conditions <conditions-file> --output <output-file.ply>
# Pi3X VO -> PLY with an explicit canonical package directory (layout matches 3d/canonical-weights/pi3x)
cargo run -p lux3d-cli -- run pi3x --model-path <canonical-pi3x-dir> --source <input-video> --vo --chunk-size 8 --overlap 4 --conf-threshold 0.05 --inject-condition pose,depth,ray --output <output-file.ply>
# TripoSR -> OBJ with an explicit canonical package directory (layout matches 3d/canonical-weights/triposr)
cargo run -p lux3d-cli -- run triposr --model-path <canonical-triposr-dir> --source <input-image> --mc-resolution 256 --mc-threshold 25.0 --output <output-file.obj>
# Auto-download canonical packages from Hugging Face into the user cache
cargo run -p lux3d-cli -- run pi3 --source <input-sequence> --output <output-file.ply>
Experimental backends (Vulkan / WGPU): select a non-CUDA device with
--device:cargo run -p lux3d-cli --features vulkan -- run triposr --device vulkan --source <input-image> --output <output-file.obj> cargo run -p lux3d-cli --features wgpu -- run pi3 --device wgpu --source <input-sequence> --output <output-file.ply>These paths are experimental and not verified in CI. Inference may be unstable, produce incorrect output, or fail entirely depending on your GPU, driver, and OS. Use CUDA for production workloads.
cargo run -p lux3d-server -- --host 127.0.0.1 --port 8080
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/v1/models
Generation endpoints accept multipart/form-data and return 202 Accepted with an async job object:
| Endpoint | Models | Output |
|---|---|---|
POST /v1/point-clouds/generations | pi3, pi3x | PLY |
POST /v1/meshes/generations | triposr | OBJ |
Common fields:
model — required for point clouds (pi3 or pi3x), optional for meshes (triposr default)source — required upload (.zip frame archive, .mp4 video, or image)conditions — optional Pi3X conditions fileoptions — optional JSON string with family-specific parametersWorkflow:
# 1. Create a mesh generation job
curl -X POST http://127.0.0.1:8080/v1/meshes/generations `
-F "model=triposr" `
-F "source=@input.png" `
-F "options={\"mc_resolution\":256,\"mc_threshold\":25.0}"
# 2. Poll job status
curl http://127.0.0.1:8080/v1/generations/gen_...
# 3. Download completed asset
curl http://127.0.0.1:8080/v1/generations/gen_.../content --output mesh.obj
Embed the router in another Axum app:
use lux3d_server_core::{
lux3d_for_server_builder::Lux3dForServerBuilder,
lux3d_server_router_builder::Lux3dServerRouterBuilder,
};
let lux3d = Lux3dForServerBuilder::new().build()?;
let routes = Lux3dServerRouterBuilder::new()
.with_lux3d(lux3d)
.build()
.await?;
let app = axum::Router::new().nest("/api/lux3d", routes);
Measured inference time ([stage] infer: preprocessing + neural pass, single iteration per process, weights excluded) on an NVIDIA GeForce RTX 3060 12 GiB, Windows (WDDM), candle wgpu/vulkan fork rev efb506c9, candle-3d (2026-09-06):
| model | CUDA | Vulkan | WGPU | Vulkan/CUDA | WGPU/CUDA |
|---|---|---|---|---|---|
| pi3 (5 frames, 518×518) | 4.82 s | 7.83 s | 13.96 s | 1.62× | 2.90× |
| pi3x (6 frames, 518×518) | 7.00 s | 11.10 s | 31.84 s | 1.59× | 4.55× |
| triposr (single image) | 1.23 s | 3.36 s | 4.89 s | 2.73× | 3.98× |
Warm-loop criterion (10 samples, steady state — the candle-bench protocol, one back-to-back window): vulkan 3.14 s / 4.90 s per iter (1.16×/1.20× of CUDA 2.72 s / 4.09 s), wgpu 8.21 s / 24.0 s (3.0×/5.9×). The biggest single lever was a fused LayerNorm+RoPE kernel (rope_layernorm.comp/.wgsl in the fork): one dispatch per q/k replaces the slow-path LayerNorm, both surrounding copies, and the 8-op rope chain at every rope site, cutting wgpu pi3 from 54.9 s to 8.21 s warm.
Correctness: outputs of every backend × model combination were verified against the CUDA reference meshes (bounding box / center / mean delta within 1% of max extent, vertex/face counts within 0.5% — all PASS); the fused kernel is additionally unit-tested exact to 0.0 diff against the composed form on both backends.
Memory behavior under repeated inference (10-iteration loop, same process):
LUX3D_MAX_SDPA_SCORES_BYTES), which removes a ~4 GiB transient that previously fragmented the CUDA memory pool and stalled a 12 GiB card ~100×.CANDLE_VK_INFLIGHT_GRACE, CANDLE_VK_POOL_MAX_BYTES). Batch caps are tuned from flush-reason profiling: transfer bytes 512 MiB (CANDLE_VK_MAX_BATCH_TRANSFER_BYTES), descriptor sets 8× dispatches — closing the batch per big activation copy cost ~4-9 ms of WDDM fence-signal latency per submission.CANDLE_WGPU_POOL_MAX_BYTES, CANDLE_WGPU_INFLIGHT_MAX_BYTES).Known gaps: the remaining Vulkan/CUDA warm gap (1.16–1.20×) is the structural WDDM submit tax (~4-9 ms per submission on a strictly dependent op chain) — a platform property code cannot reach; Linux without WDDM would close it. WGPU remains 3.0–5.9× behind warm (down from 13.9–19.5×), dominated by WGSL GEMM quality plus the same inter-pass WDDM gaps. A criterion harness for whole-model benches lives in crates/lux3d-core/benches/ (run one (backend, model) pair per process: LUX3D_BENCH_DEVICE=… LUX3D_BENCH_MODEL=… cargo bench -p lux3d-core --bench bench_main --features vulkan,wgpu).
edition = "2024"wgpu/vulkan fork): verified for correctness and memory stability on RTX 3060 (see Performance); slower than CUDA, WGPU substantially so.--model-path, or downloadable from Hugging Face into the user cacheThe code and documentation in this repository are licensed under Apache 2.0. See LICENSE.
Upstream model assets and canonicalized model artifacts keep their original licenses and usage restrictions. Review model-family-specific terms before redistribution.
57 commits
Rust
86.7%
Python
9.2%
PowerShell
3.4%