# How model_width Controls STL Output Dimensions in MCP 3D Relief

> Understand how model_width directly controls STL output dimensions in MCP 3D Relief. Learn how it sets X-axis width and scales Y-axis proportionally for your designs.

- Repository: [bigchx/mcp_3d_relief](https://github.com/bigchx/mcp_3d_relief)
- Tags: deep-dive
- Published: 2026-02-26

---

**The `model_width` parameter directly sets the physical X-axis width of the generated STL file in millimeters, automatically scaling the Y-axis proportionally to preserve the source image's aspect ratio.**

The `bigchx/mcp_3d_relief` repository converts depth maps into 3D printable STL files. Understanding how the `model_width` parameter translates digital pixels into physical millimeters is essential for producing accurately sized 3D relief models.

## How model_width Maps Pixels to Millimeters

Inside [`relief.py`](https://github.com/bigchx/mcp_3d_relief/blob/main/relief.py), the code calculates a scaling factor called `pixel_size` that bridges the gap between image resolution and physical dimensions:

```python
pixel_size = model_width / width          # relief.py, line 57

```

- `width` represents the number of pixels in the depth map's horizontal axis.
- `pixel_size` determines exactly how many millimeters each pixel occupies in the final STL geometry.

This single calculation drives all dimensional scaling for the X and Y axes, ensuring the output matches your specified `model_width` exactly.

## X and Y Axis Scaling Behavior

### X-Axis Dimensions

The X-coordinates of the generated mesh vertices are multiplied by `pixel_size` during STL generation. The outermost X-coordinates span from `0` to `(width - 1) * pixel_size`, resulting in a total X-axis span that equals `model_width` millimeters exactly.

### Y-Axis Dimensions

The Y-axis uses the same `pixel_size` factor to maintain the source image's aspect ratio:

```python
y0 = (height - y - 1) * pixel_size
y1 = (height - (y + 1) - 1) * pixel_size

```

The resulting Y-extent calculates to `height * pixel_size`, which simplifies to `height * model_width / width`. This preserves the original image proportions while fitting the larger dimension to your specified `model_width`.

## Z-Axis Independence

The Z-axis (height/thickness) operates independently of `model_width`. The depth map values (0-255) are scaled by `model_thickness` (default 5mm) to determine relief height, while `base_thickness` adds a constant flat base below the relief surface. These parameters control vertical dimensions without affecting the X-Y plane scaling.

## Practical Code Examples

### Generate a 100mm Wide Model

```python
import asyncio
from relief import relief

async def run():
    result = await relief(
        input_image_path="uploads/demo.png",
        model_width=100.0,          # Request exactly 100mm width

        model_thickness=5.0,
        base_thickness=2.0,
    )
    print(result)

asyncio.run(run())

```

For an 800×600 pixel source image, this produces an STL file measuring **100mm wide** by approximately **75mm tall** (600/800 × 100), preserving the 4:3 aspect ratio.

### Verify Output Dimensions Programmatically

```python
import trimesh
import pathlib

stl_path = pathlib.Path("output/abcd1234.stl")
mesh = trimesh.load_mesh(stl_path)

x_size = mesh.bounds[1][0] - mesh.bounds[0][0]
y_size = mesh.bounds[1][1] - mesh.bounds[0][1]
z_size = mesh.bounds[1][2] - mesh.bounds[0][2]

print(f"X: {x_size:.2f}mm (should match model_width)")
print(f"Y: {y_size:.2f}mm (scaled by aspect ratio)")
print(f"Z: {z_size:.2f}mm (model_thickness + base_thickness)")

```

## Summary

- **`model_width`** sets the exact physical width (X-axis) of the STL output in millimeters via the calculation `pixel_size = model_width / width` in [`relief.py`](https://github.com/bigchx/mcp_3d_relief/blob/main/relief.py).
- **Aspect ratio preservation** occurs automatically because the same `pixel_size` scales the Y-axis, resulting in `height * model_width / width`.
- **Z-axis dimensions** remain independent, controlled by `model_thickness` and `base_thickness` rather than `model_width`.
- **Validation** confirms that setting `model_width=100.0` produces an STL with exactly 100mm X-axis span regardless of source image resolution.

## Frequently Asked Questions

### Does model_width affect the height of the relief?

No, `model_width` only controls the horizontal X and Y dimensions. The relief height (Z-axis) is determined by `model_thickness`, which scales the depth map values, and `base_thickness`, which adds a flat foundation. These parameters operate independently of the width scaling logic in [`relief.py`](https://github.com/bigchx/mcp_3d_relief/blob/main/relief.py).

### How do I maintain the aspect ratio when setting model_width?

The aspect ratio is preserved automatically. When you specify `model_width`, the code calculates `pixel_size = model_width / width` and applies this same factor to the Y-axis coordinates. This ensures the Y-dimension becomes `height * model_width / width`, maintaining the original image proportions without manual calculation.

### What happens if I don't specify model_width?

The repository requires `model_width` as a mandatory parameter in the `relief()` function signature. If omitted, the function call will raise a TypeError. There is no default value, ensuring users explicitly define the desired physical scale for every generated STL file.

### Can I set different widths for X and Y dimensions?

No, the current implementation in [`relief.py`](https://github.com/bigchx/mcp_3d_relief/blob/main/relief.py) uses a single `pixel_size` factor derived from `model_width` to scale both axes uniformly. This design enforces proportional scaling to prevent distortion of the relief pattern. To achieve non-uniform scaling, you would need to modify the source code to accept separate `model_width` and `model_height` parameters.