Instructions to use noahclark556/mesh-to-cad-14b with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use noahclark556/mesh-to-cad-14b with MLX:
# Make sure mlx-lm is installed # pip install --upgrade mlx-lm # Generate text with mlx-lm from mlx_lm import load, generate model, tokenizer = load("noahclark556/mesh-to-cad-14b") prompt = "Write a story about Einstein" messages = [{"role": "user", "content": prompt}] prompt = tokenizer.apply_chat_template( messages, add_generation_prompt=True ) text = generate(model, tokenizer, prompt=prompt, verbose=True) - Transformers
How to use noahclark556/mesh-to-cad-14b with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="noahclark556/mesh-to-cad-14b") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("noahclark556/mesh-to-cad-14b") model = AutoModelForCausalLM.from_pretrained("noahclark556/mesh-to-cad-14b", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- vLLM
How to use noahclark556/mesh-to-cad-14b with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "noahclark556/mesh-to-cad-14b" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "noahclark556/mesh-to-cad-14b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/noahclark556/mesh-to-cad-14b
- SGLang
How to use noahclark556/mesh-to-cad-14b with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "noahclark556/mesh-to-cad-14b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "noahclark556/mesh-to-cad-14b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "noahclark556/mesh-to-cad-14b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "noahclark556/mesh-to-cad-14b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Pi
How to use noahclark556/mesh-to-cad-14b with Pi:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "noahclark556/mesh-to-cad-14b"
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "mlx-lm": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "noahclark556/mesh-to-cad-14b" } ] } } }Run Pi
# Start Pi in your project directory: pi
- MLX LM
How to use noahclark556/mesh-to-cad-14b with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Interactive chat REPL mlx_lm.chat --model "noahclark556/mesh-to-cad-14b"
Run an OpenAI-compatible server
# Install MLX LM uv tool install mlx-lm # Start the server mlx_lm.server --model "noahclark556/mesh-to-cad-14b" # Calling the OpenAI-compatible server with curl curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "noahclark556/mesh-to-cad-14b", "messages": [ {"role": "user", "content": "Hello"} ] }' - Docker Model Runner
How to use noahclark556/mesh-to-cad-14b with Docker Model Runner:
docker model run hf.co/noahclark556/mesh-to-cad-14b
- Hermes Agent
How to use noahclark556/mesh-to-cad-14b with Hermes Agent:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "noahclark556/mesh-to-cad-14b"
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default noahclark556/mesh-to-cad-14b
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use noahclark556/mesh-to-cad-14b with OpenClaw:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "noahclark556/mesh-to-cad-14b"
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "noahclark556/mesh-to-cad-14b" \ --custom-provider-id mlx-lm \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Mesh-to-CAD 14B
Successor:
noahclark556/mesh-to-cad-14b-v2is the current recommended checkpoint (corrected six-run SFT stack merged with the fixed ORPO train). This v1 page stays up as the earlier public baseline.
An experimental model that turns an STL mesh or point cloud into editable CadQuery Python.
The goal is a program you can read and change, not just another mesh that looks similar. Multiple scripts can describe the same shape, so exact source recovery is not the bar.
License: CC BY-NC 4.0. Non-commercial use with attribution is welcome. Commercial use needs a separate license.
This is not a normal text chat model. Geometry is sampled, encoded, and
passed through a point projector into inputs_embeds. The language model
then writes CadQuery after a <|gen|> boundary token.
Why I built this
My initial reason for building this model was to use it within my web platform SliceFoundry (SliceFoundry.com), as well as within my desktop application Draftr (draftrcad.com). A lot of users come to these platforms trying to "remix" an existing STL, which is a supported feature in both applications. However, the system currently in place hits a wall that cannot be crossed without a custom trained model. The idea moving forward, which is currently working well with model versions that have not yet been released, is to have the mesh-to-cad model produce the geometry from the uploaded mesh, then run that geometry through the existing parametric fine-tune pipeline alongside a detailed analysis of the mesh.
This system has proven to be far more accurate than I initially anticipated, and should save a lot of time and spending for me as development continues. The process of training this model has been a relatively large (but informative) undertaking, as the training setup had to be almost entirely custom to support a project built in this way. Over the course of multiple months, I have built a massive and streamlined local pipeline for this training process.
From dataset generation modules to training and deployment scripts for both GCP and RunPod, as well as full support for training the model entirely locally. A lot of the training that occurred was done locally, and I bought a new MacBook partly so I could do this. Over the course of 12 SFT sessions, 4-5 GRPO sessions, 16 ORPO sessions, and an absurdly large amount of training data built using data extracted from the aforementioned platforms and synthetically produced, mesh-to-cad was born through the forge of trial and error.
Try it (Apple Silicon / MLX)
huggingface-cli download noahclark556/mesh-to-cad-14b --local-dir ./mesh-to-cad-14b
cd mesh-to-cad-14b
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python chat.py --input /path/to/part.stl
python chat.py --input /path/to/part.stl --render
| Flag | Default | Notes |
|---|---|---|
--model |
. |
Folder with weights + projector.pt |
--temp |
0.2 |
Lower is more deterministic |
--top-k |
0 (off) |
|
--top-p |
0.0 (off) |
|
--max-tokens |
2048 |
Raise if long scripts get cut off |
--repetition-penalty |
1.08 |
Helps avoid loops |
--render |
off | Exec CadQuery, write STL, open it |
A few things happen automatically so the path matches training:
- Input is resized so the longest bbox edge is 100.
mesh_sigis derived from the mesh when possible and inserted in the prefix (points + sig +<|gen|>).- Dense sampling uses fine tessellation and feature-aware points, then split FPS down to 1024 tokens.
--render runs the generated script, writes infer_out/<stem>.stl, and opens
it. If CadQuery fails, the script errors after a light local cleanup (trimming
an incomplete trailing line). There is no external repair API.
CadQuery is recommended for sampling that matches training, and required for
--render:
mamba install -c conda-forge cadquery
Use conda-forge / OCP. Avoid pip-only CadQuery on Mac.
MLX and other stacks
chat.py is written for Apple Silicon via MLX / mlx-lm. That is the supported
easy path.
The weights themselves are standard Transformers safetensors plus
projector.pt, so other runtimes can load them. You will need to rebuild the
geometry prefix yourself (Fourier features -> projector -> inputs_embeds).
Plain generate(), llama.cpp, and text-only servers will not see the point
cloud and will not work for this model as-is.
Pipeline
STL / point cloud
-> fine tessellation
-> 8192 feature-aware surface samples
-> split FPS (768 global + 256 feature) = 1024 tokens
-> 12-frequency Fourier encoding (75D) + linear projector
-> optional mesh_sig tokens (compact geometry summary)
-> <|gen|>
-> CadQuery Python
The model does not see a chat-style system prompt. Conditioning is the
prefix itself: projected point tokens, then (when available) a short
mesh_sig string embedded as normal text tokens, then <|gen|>.
How this model was built
Early versions used a single FPS pass at 512 tokens on coarser surface samples. That was enough for simple blocks, but pockets, holes, and thin local detail tended to disappear before the model ever saw them.
What made a real difference:
- Finer tessellation when exporting STL for sampling, so edges and small faces survive into the point cloud.
- Feature-aware dense sampling (8192 points), so sharp edges and small faces are not starved by area weighting alone.
- Split FPS to 1024 tokens: most of the budget for global coverage
(
768), with a reserved feature pool (256) so local detail still gets tokens. Same count as a plain 1024 FPS, better retention of pockets/holes. - Mesh signature (
mesh_sig) - a compact discrete summary of the part (family / topology-ish cues in a shortSIG v1 ...string). It sits in the prefix between the point embeddings and<|gen|>, so the model gets an explicit high-level read of the shape before it starts writing code. In practice it plays a similar role to a system prompt (steering the generation with structured context), but it is geometry conditioning in the input prefix, not a chat system message. Adding it helped a lot on harder parts where points alone were ambiguous. - SFT on Qwen3-14B-Base with a Fourier point projector and a dedicated
<|gen|>generation boundary. - Additional ORPO preference passes to sharpen CadQuery quality on harder cases.
The training corpus is not released with this checkpoint. Provenance and licensing for the data are still private; this repo is the model and the inference helpers only.
What's in the repo
model*.safetensors- language model weightsprojector.pt- point-cloud -> embedding projector- tokenizer / config (includes
<|gen|>) chat.py+mesh_to_cad/- MLX test pathrequirements.txt
Limits
This is still research software. Generated Python can fail to run or produce empty / invalid solids. Even when geometry looks close, the construction history may be very different from the original CAD.
Thin walls, hidden cavities, threads, assemblies, organic surfaces, and tiny features are difficult from exterior samples alone. Small holes, pockets, and fillets are often simplified or dropped. Absolute scale is normalized unless your own pipeline restores it.
Citation
If you use Mesh-to-CAD, please credit the project and link this model page. For commercial licensing, contact me.
Continuation
If you find this model interesting or want to see more in the future, drop a like so I know there is some interest in the project. Thanks!
Prior work
The point-cloud soft-token idea (sample points, Fourier-encode them, project into the LM embedding space, then generate CAD code) is not mine. I first saw that setup in:
- CAD-Recode (Rukhovich et al., ICCV 2025)
- cadrille (Kolodiazhnyi et al., ICLR 2026)
Credit to those authors for that geometry-prefix approach. Everything else here (data, training stack, mesh signatures, split FPS, CadQuery target, ORPO, etc.) is my own work. Citing them so nobody thinks I invented the soft-token pattern.
- Downloads last month
- 157
6-bit
Model tree for noahclark556/mesh-to-cad-14b
Base model
Qwen/Qwen3-14B-Base