TRELLIS.2 on Replicate with a MacBook Controller
May 20, 2026 · View on GitHub
This guide explains how to call a TRELLIS.2 model hosted on Replicate while your MacBook stays the orchestrator: spec parsing, OpenAI concept image, optimization, QA, review, and exports remain local.
It assumes you already have the 3D Asset Factory CLI working with the mock runner.
Architecture
MacBook (you) Replicate (cloud)
----------------------------------------- ----------------------------------
python -m asset_factory generate ... ----> model: owner/trellis2 or your fork
OpenAI GPT Image 2.0 concept NVIDIA A100 / H100 (managed)
TRELLIS2_COMMAND wrapper <---- glb cog-packaged predict()
optimize + preview returns raw.glb (file or url)
QA + review + exports
The MacBook never touches CUDA. Replicate hosts the model as a Cog package and exposes a stable
HTTP API. Your laptop integrates through the existing TRELLIS2_COMMAND seam — a small Python
wrapper runs the Replicate prediction, downloads the returned GLB, and writes it to
{output}/raw.glb.
When to choose Replicate
Pick Replicate when you want:
- The fewest moving parts on the laptop — one API key, one HTTP call, no Docker registry.
- A model registry that handles versioning, autoscaling, and a public/private toggle out of the box.
- An existing community model (when one for TRELLIS.2 is available and trusted), or to publish your own packaged model.
- Predictable per-second GPU pricing without managing workers.
Skip Replicate if you need fine-grained container control (RunPod Serverless) or if you want to ship a tightly-coupled Python function alongside the rest of your code (Modal).
Prerequisites
On the MacBook:
- macOS with Python 3.11+ (matches
pyproject.toml). - This repo cloned and installed with
python -m pip install -e ".[dev]". OPENAI_API_KEYset.- The
replicatePython SDK installed:python -m pip install replicate. - (Only if you publish your own model) the
cogCLI from https://github.com/replicate/cog and Docker. Cog targetslinux/amd64; on Apple Silicon usecog push --platform linux/amd64.
Cloud side:
- A Replicate account at https://replicate.com.
- A Replicate API token (Account → API tokens).
- Either:
- A community TRELLIS.2 model on Replicate that you trust, or
- Your own Cog-packaged TRELLIS.2 model published as
your-handle/trellis2.
One-time Replicate setup
-
Get an API token at https://replicate.com/account/api-tokens.
-
Export it locally:
export REPLICATE_API_TOKEN="r8_your_token" -
Pick a model identifier. Either copy the slug of an existing community model (
some-user/trellis2) or publish your own (next section).
Publishing your own model (template)
If no public TRELLIS.2 model meets your needs, package one with Cog. Add infra/cog/ with the
following template files.
infra/cog/cog.yaml:
build:
gpu: true
cuda: "12.4"
python_version: "3.11"
python_packages:
- "torch==2.4.0"
- "torchvision==0.19.0"
# add the rest of the TRELLIS.2 deps here
system_packages:
- "git"
- "ffmpeg"
- "libgl1"
run:
- "git clone https://github.com/microsoft/TRELLIS.git /opt/trellis2"
- "pip install -e /opt/trellis2"
predict: "predict.py:Predictor"
infra/cog/predict.py:
# Template Cog predictor. Adapt to the actual TRELLIS.2 entrypoint.
import pathlib
import tempfile
from cog import BasePredictor, Input, Path
class Predictor(BasePredictor):
def setup(self):
from trellis2.inference import load_model # placeholder import
self.model = load_model()
def predict(
self,
image: Path = Input(description="Concept image PNG/JPG"),
resolution: int = Input(default=1024, ge=256, le=2048),
) -> Path:
out_dir = pathlib.Path(tempfile.mkdtemp())
out_path = out_dir / "raw.glb"
self.model.image_to_glb(str(image), str(out_path), resolution=resolution)
return Path(out_path)
Build and push:
cog login
cog push r8.im/your-handle/trellis2 --platform linux/amd64
The first push creates the model. Subsequent pushes create new versions.
Local wrapper script (template)
TRELLIS2_COMMAND expects a process that reads {image}, writes {output}/raw.glb, and exits
with status 0. Add scripts/replicate_trellis_runner.py:
# scripts/replicate_trellis_runner.py
# Template: invoked by TRELLIS2_COMMAND.
# Usage: replicate_trellis_runner.py {image} {output} [resolution]
import os
import pathlib
import sys
import urllib.request
import replicate
MODEL = os.environ["REPLICATE_MODEL"] # e.g. "your-handle/trellis2:VERSION_HASH"
def main() -> int:
if len(sys.argv) < 3:
print("usage: replicate_trellis_runner.py <image_path> <output_dir> [resolution]",
file=sys.stderr)
return 2
image_path = pathlib.Path(sys.argv[1])
output_dir = pathlib.Path(sys.argv[2])
resolution = int(sys.argv[3]) if len(sys.argv) > 3 else 1024
output_dir.mkdir(parents=True, exist_ok=True)
with image_path.open("rb") as f:
output = replicate.run(
MODEL,
input={"image": f, "resolution": resolution},
)
raw_glb = output_dir / "raw.glb"
# Replicate returns either a URL string, a FileOutput-like object, or a list of them.
item = output[0] if isinstance(output, list) else output
if hasattr(item, "read"):
raw_glb.write_bytes(item.read())
elif isinstance(item, str) and item.startswith(("http://", "https://")):
urllib.request.urlretrieve(item, raw_glb)
else:
raise RuntimeError(f"unexpected replicate output: {type(item).__name__}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Pin REPLICATE_MODEL to a specific version hash, not a floating tag, so reruns are
reproducible.
Environment variables
On the MacBook before each run:
export OPENAI_API_KEY="sk-your-development-key"
export REPLICATE_API_TOKEN="r8_your_token"
export REPLICATE_MODEL="your-handle/trellis2:0123abcd...the_version_hash"
export TRELLIS2_COMMAND='python scripts/replicate_trellis_runner.py {image} {output} {resolution}'
The runner expands {image}, {output}, and {resolution} as defined in
src/asset_factory/runners/trellis.py. The wrapper must write {output}/raw.glb and exit 0.
Example end-to-end command
export OPENAI_API_KEY="sk-your-development-key"
export REPLICATE_API_TOKEN="r8_your_token"
export REPLICATE_MODEL="your-handle/trellis2:0123abcd..."
export TRELLIS2_COMMAND='python scripts/replicate_trellis_runner.py {image} {output} {resolution}'
python -m asset_factory generate assets/seeds/chloroplast_conceptual.yaml --runner trellis
What happens, in order:
- Laptop renders the concept image with OpenAI GPT Image 2.0.
TrellisCommandRunnerexpandsTRELLIS2_COMMANDand launches the wrapper.- The wrapper streams the image to Replicate as the
imageinput. - Replicate runs the prediction on a managed GPU and returns the GLB.
- The wrapper writes
runs/<asset_id>/<timestamp>/trellis/raw.glb. - Local steps continue: optimize, previews, QA, review HTML, export packages, manifest.
Expected output contract
After a successful run:
runs/<asset_id>/<timestamp>/trellis/raw.glb
runs/<asset_id>/<timestamp>/trellis/raw_report.json
raw_report.json is written by TrellisCommandRunner and contains the expanded command,
stdout, stderr, return code, and timing.
Debugging tips
replicate.predictions.list()from a Python shell shows recent runs and statuses.- Every prediction has a web URL like
https://replicate.com/p/<id>with logs and the input image. Bookmark it from the prediction object:prediction.urls["web"]. cog predict -i image=@local.pngruns the predictor locally before pushing — fastest way to catch dependency errors.- If you get
MissingRawGlbError, the wrapper exited 0 without writingraw.glb. Inspectraw_report.jsonplus the prediction's logs. NonZeroReturnCodeErrorusually means the wrapper itself errored — bad token, missingREPLICATE_MODEL, or a model version that no longer exists. Thestderrinraw_report.jsonidentifies which.- For large GLBs prefer the URL output path.
urllib.request.urlretrievestreams to disk and avoids holding the file in memory.
Cost and latency notes
- Per-second GPU billing. The exact rate depends on the hardware Replicate routes you to (A100, H100, etc.); check the model's hardware setting.
- Cold starts can take 30–60 s while the image and weights load. After that, warm predictions are quick.
- Public models incur a per-prediction setup cost the first time you call them after a long idle period.
- OpenAI image cost is separate and stays on the laptop side.
When Replicate is the right choice
Pick Replicate when you want the simplest possible integration: one token, one HTTP call, no
container ops. The wrapper above is the only code you maintain on the laptop, and it slots
directly into the existing TRELLIS2_COMMAND seam.
If you need fine-grained container or scaling control, see RunPod Serverless. If you want a Python-decorator deploy model with code colocated next to the rest of the pipeline, see Modal.