# 3D Model Renderer: STL, 3MF, OBJ, GLB & OpenSCAD to PNG (`jumblemog/3d-model-renderer`) Actor

Render STL, 3MF, OBJ, GLB/glTF, PLY and OpenSCAD models to PNG images, four-view sheets and turntable GIF or MP4, measure size, volume and watertightness, and convert between STL, 3MF, OBJ and GLB. OpenSCAD errors come back with line numbers for people and AI agents.

- **URL**: https://apify.com/jumblemog/3d-model-renderer.md
- **Developed by:** [Jumble Mog](https://apify.com/jumblemog) (community)
- **Categories:** Developer tools, AI, E-commerce
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 3D Model Renderer: STL, 3MF, OBJ, GLB & OpenSCAD to PNG

**Turn 3D models and OpenSCAD code into images, measurements and printable files, without installing anything.** Send OpenSCAD code, or STL, 3MF, OBJ, GLB/glTF, PLY and OFF files as links or uploads, and get back **PNG images from any angle**, a **four-view sheet** with the model's size, a **turntable GIF or MP4**, the model's **size, volume, surface area, weight and watertightness**, and the model as **STL, 3MF, OBJ or GLB** (SVG, DXF or PDF for 2D designs). OpenSCAD errors come back with file and line, so a person or an AI agent can fix the design. Many models per run, pay per model, and models that can't be read are free.

![OpenSCAD code for a twisted vase, the four-view sheet this Actor made from it, renders of a BOSL2 gear, a multi-colored OpenSCAD design and a textured GLB model, and the JSON results for the vase and for a design with a mistake](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/3d-model-renderer-example.png?signature=N83kzLQM4HV8mtY4Uwp8)

### What it does

- **Compiles OpenSCAD** with a current OpenSCAD build and its fast Manifold engine, with the BOSL2, MCAD, Round-Anything and threads.scad libraries ready to `include`. Set a design's variables without editing it, like OpenSCAD's Customizer, and get its `echo()` output back.
- **Reads the common 3D formats**: STL (binary and ASCII), 3MF (with colors, components and multi-file projects from Bambu Studio and PrusaSlicer), OBJ, glTF and GLB (with materials and textures), PLY (with vertex colors) and OFF. Models can also come in ZIP archives, GitHub repositories and folders, and Google Drive or Dropbox share links.
- **Draws clear images**: an iso view in perspective with a soft shadow, and front, back, left, right, top and bottom views in orthographic projection, like a technical drawing. Thin outlines on sharp edges make parts easy to read. The model's own colors and textures are kept; any background color or transparent; up to 4096 pixels.
- **Makes a four-view sheet**: iso, front, right and top in one image, with the size and volume underneath. One picture shows the whole model, for listings and catalogs, or for an AI model that has to look at a design.
- **Makes turntables**: a looping GIF and/or MP4 of the model turning once, 1 to 20 seconds long, up to 1080 pixels.
- **Measures**: size and bounding box in millimetres, volume in cm³, surface area, the weight printed solid in a chosen material, triangles, vertices, the number of separate bodies, and whether the mesh is watertight and manifold.
- **Converts**: to STL, 3MF (with colors), OBJ and GLB (Y up in metres, as glTF viewers and AR expect). 2D OpenSCAD designs become SVG, DXF (for laser cutters and CNC) and PDF.
- **Errors you can act on**: an OpenSCAD mistake comes back as `{"file", "line", "message", "source"}` with the call trace, for example `broken.scad:2: Parser error: syntax error (at: translate([5,0,0) sphere(3);)`. Warnings such as unknown modules or variables come with their line too.
- **The file straight from the API**: the first file you ask for (the PNG by default) is also the run's `OUTPUT`, so the run-sync endpoint answers with the image itself.
- **Safe with untrusted files**: OpenSCAD and the renderer run as an unprivileged user in a throwaway folder, with time and file size limits.

### Who it's for

- **AI agents and LLM apps that design objects.** Language models write OpenSCAD well but can't see what they made. This Actor shows them: the four-view sheet goes straight to a vision model, and errors with line numbers let the agent fix its own code.
- **3D printing services, marketplaces and print farms** that need thumbnails, sizes and volumes for quotes, and a watertightness check, for uploaded STL and 3MF files.
- **E-commerce and product teams** making product images and turntable videos from CAD exports and glTF models.
- **Makers and educators** sharing parametric OpenSCAD designs: render every variant of a design, with an image and an STL for each.
- **Developers and automation builders** (n8n, Make, Zapier) who need 3D rendering in an app without running OpenSCAD or a GPU themselves.

### How to use it

1. Paste OpenSCAD code into **OpenSCAD code**, add links in **Links to models**, or upload files. The example is the twisted vase in the picture above.
2. Pick what to make: PNG views, the four-view sheet, a GIF or MP4 turntable, STL, 3MF, OBJ or GLB files, or SVG, DXF and PDF for 2D designs. If you like, choose the views, image size, colors and background.
3. Click **Start**. Each model appears in the **Output** tab with its images, measurements and files, or with its errors.

You can also run it through the [Apify API](https://docs.apify.com/api/v2), on a schedule, or from Make, n8n, Zapier and other integrations.

### How-to examples

#### How to make a PNG thumbnail of an STL file

```json
{"modelUrls": ["https://example.com/parts/bracket.stl"], "outputs": ["png", "sheet"]}
```

Result: a PNG of the model from an angle in `imageUrl`, a four-view sheet with its size, and the model's `sizeMm`, `volumeCm3`, `surfaceAreaCm2`, `solidWeightGrams` and `watertight` check. STL, 3MF, OBJ, GLB/glTF, PLY and OFF files all work.

#### How to render OpenSCAD code to an image and an STL online

```json
{"openscadCode": "difference() { cylinder(h = 20, r = 15); translate([0, 0, 2]) cylinder(h = 20, r = 13); }",
 "outputs": ["png", "stl"]}
```

Result: a picture of the cup and an STL ready for a slicer, without installing OpenSCAD. For a parametric design, send `parameters` such as `{"width": 80}`, or several sizes of one design in `models`.

#### How to make a turntable GIF of a 3D model

```json
{"modelUrls": ["https://github.com/you/parts/tree/main/stl"], "outputs": ["png", "gif"], "imageSize": 512}
```

Result: a 512 px thumbnail and a spinning GIF for every model in the GitHub folder, for a shop listing, a README or a print-farm catalog. Use `mp4` for a video instead.

#### How to let an AI agent design and check 3D models

Add this Actor to the [Apify MCP server](https://mcp.apify.com) with `https://mcp.apify.com/?tools=jumblemog/3d-model-renderer`. The agent writes OpenSCAD code, looks at the image to check the shape, and reads the size and volume, so it can fix the design before the user prints it. OpenSCAD errors come back in `errors`.

### FAQ

**Can it convert between 3D formats?** Yes, to STL, 3MF (with colors), OBJ and GLB. 2D OpenSCAD designs become SVG, DXF and PDF.

**Does it tell me how much a print weighs?** It gives the weight printed solid, from the volume and `materialDensity`: 1.24 g/cm³ for PLA by default, 1.04 for ABS, 1.27 for PETG. Infill makes real prints lighter.

**Does it check that a model is printable?** It reports whether the mesh is watertight and how many separate bodies it has.

**Do I need OpenSCAD or Blender installed?** No. Everything runs in the cloud.

**Does it work with Zapier, Make or n8n?** Yes. Call the Actor with its Apify app or an HTTP request, for example to make thumbnails for every uploaded file.

### Input

| Field | What it does |
| --- | --- |
| `openscadCode` | One OpenSCAD design as text, 3D or 2D. |
| `modelUrls` | Links to `.stl`, `.3mf`, `.obj`, `.glb`, `.gltf`, `.ply`, `.off` or `.scad` files, GitHub file pages, repositories and folders, GitLab file pages, Google Drive or Dropbox share links, or ZIP archives. |
| `uploads` | Model files or ZIP archives uploaded in the input form. |
| `outputs` | Any of `png`, `sheet`, `gif`, `mp4`, `stl`, `3mf`, `obj`, `glb`, `svg`, `dxf`, `pdf` (default: a PNG, plus an STL for OpenSCAD designs). Measurements always come in the results. |
| `parameters` | Variables for an OpenSCAD design, like the Customizer: `{"width": 40, "label": "Hi", "holes": true, "size": [10, 20, 5]}`. |
| `views` | Angles for the PNG images: `iso` (default), `iso-back`, `front`, `back`, `left`, `right`, `top`, `bottom`. |
| `imageSize` | Width and height of the images and the sheet, 128 to 4096 pixels (default 1024). |
| `color` | Color for models without colors of their own, such as `#f28c28` (default `#4a90d9`). |
| `background` | Background color, or `transparent` (default white). |
| `modelColors` | Draw the colors and textures in the files (default on). |
| `edges` | Outline sharp edges (default on). |
| `shadow` | Soft shadow under iso views and turntables (default on). |
| `projection` | `auto` (default: iso views in perspective, the others orthographic), `perspective` or `orthographic`. |
| `animationSeconds` | Length of one turn of the turntable, 1 to 20 seconds (default 3). |
| `animationSize` | Width and height of the turntable, 128 to 1080 pixels (default 512). |
| `upAxis` | Which way is up in mesh files: `auto` (default), `z` or `y`. |
| `units` | Units of mesh files: `auto` (default: millimetres, and metres for glTF), `mm`, `cm`, `m` or `in`. |
| `materialDensity` | Grams per cm³ for `solidWeightGrams` (default 1.24, for PLA). |
| `inputFormat` | The format of linked files when it can't be told from the name or contents. Empty: automatic. |
| `mainFile` | The model to render inside a ZIP archive or repository, such as `box.scad`. Empty: the OpenSCAD file nearest the top, or else every model. |
| `models` | More models: OpenSCAD code strings, or objects with `openscadCode` or `url` and optional `name`, `parameters`, `inputFormat`, `mainFile`, `upAxis`, `units` and `color`. |
| `renderTimeoutSecs` | OpenSCAD time limit per model, 5 to 900 seconds (default 120). |
| `maxModels` | Stop after this many models (default 100). |

Example: one parametric design in two sizes, with an image and an STL for each:

```json
{
  "models": [
    {"url": "https://example.com/box.scad", "name": "small", "parameters": {"width": 30}},
    {"url": "https://example.com/box.scad", "name": "large", "parameters": {"width": 80}}
  ],
  "outputs": ["png", "stl"]
}
```

Example: thumbnails and turntables for every model in a GitHub folder:

```json
{
  "modelUrls": ["https://github.com/you/parts/tree/main/stl"],
  "outputs": ["png", "gif"],
  "imageSize": 512
}
```

### Output

Each model becomes one dataset item, and its files are saved in the run's key-value store. This is the vase from the picture, with two views, the sheet, a turntable and an STL:

```json
{
  "index": 1,
  "name": "design",
  "status": "ok",
  "inputFormat": "scad",
  "dimension": "3d",
  "sizeMm": {"x": 86.4, "y": 86.82, "z": 120},
  "boundsMm": {"min": [-43.567, -44.186, 0], "max": [42.833, 42.634, 120]},
  "volumeCm3": 75.4268,
  "surfaceAreaCm2": 624.5824,
  "solidWeightGrams": 93.53,
  "triangles": 15942,
  "vertices": 7949,
  "bodies": 1,
  "watertight": true,
  "manifold": false,
  "imageUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-design-iso.png?signature=...",
  "imageUrls": {
    "iso": "https://api.apify.com/v2/key-value-stores/<store>/records/001-design-iso.png?signature=...",
    "front": "https://api.apify.com/v2/key-value-stores/<store>/records/001-design-front.png?signature=..."
  },
  "sheetUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-design-views.png?signature=...",
  "gifUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-design-turntable.gif?signature=...",
  "mp4Url": "https://api.apify.com/v2/key-value-stores/<store>/records/001-design-turntable.mp4?signature=...",
  "stlUrl": "https://api.apify.com/v2/key-value-stores/<store>/records/001-design.stl?signature=...",
  "threeMfUrl": null,
  "objUrl": null,
  "glbUrl": null,
  "svgUrl": null,
  "dxfUrl": null,
  "pdfUrl": null,
  "echo": ["\"Holds about 301 ml\""],
  "error": null,
  "errors": [],
  "warnings": [],
  "parameters": null,
  "sourceUrl": null,
  "processingSeconds": 7.2
}
```

- `volumeCm3` and `solidWeightGrams` are given for watertight models only. `watertight` means the surface is closed (every edge is shared by an even number of triangles, which slicers accept). `manifold` is the stricter test: every edge joins exactly two triangles. The vase isn't manifold because its base touches the twisted wall along a few edges.
- `bodies` counts the separate pieces, so a model that should be one part but has loose pieces shows up.
- 2D designs have `"dimension": "2d"`, `sizeMm` with `x` and `y` only, a PNG preview and the SVG, DXF and PDF files.

When a design can't be compiled, the item says where and why, and isn't billed:

```json
{
  "index": 5,
  "name": "broken",
  "status": "failed",
  "inputFormat": "scad",
  "error": "broken.scad:2: Parser error: syntax error (at: translate([5,0,0) sphere(3);)",
  "errors": [{"file": "broken.scad", "line": 2, "message": "Parser error: syntax error",
              "source": "translate([5,0,0) sphere(3);"}]
}
```

Download your files within your plan's data retention period, or copy them to your own storage, because run storage expires.

### Pricing

You pay per **model rendered**, at the price shown on this page, whatever still images and files you pick. Turntables are charged **per second of animation** on top: a 3-second turn counts as 3 seconds, and a GIF and an MP4 of the same turn count once. Models that can't be read or compiled are never charged. If you set a maximum cost per run, the Actor stops before a model that wouldn't fit.

### Speed

Measured on Apify with the default 2 GB of memory. One 1024-pixel iso image of each of six OBJ and GLB models, from 1,000 to 100,000 triangles, took 0.8 to 6.8 seconds per model, and 30 seconds for the whole run. The vase above, compiled and drawn from two angles with the four-view sheet, a 3-second GIF and MP4 and an STL file, took 7.2 seconds, and 3DBenchy (225,000 triangles) with all of that took 40 seconds. Turntables take the most time: 4.4 of the 6.4 seconds of a gear with all outputs. A design with a mistake is reported in 0.05 seconds. Starting a run adds about 10 seconds, so send many models in one run when you can. Runs with more memory get more CPU, which helps with big models.

### Tips and limits

- **OpenSCAD**: `$fn` sets how smooth curves are. Designs with `minkowski()` or `hull()` of many shapes are slow, so raise `renderTimeoutSecs` for them. `include`, `use` and `import()` work with files in the same ZIP archive or GitHub folder. A design that makes only 2D shapes gives a PNG preview and SVG, DXF and PDF files; extrude it with `linear_extrude()` to get 3D outputs.
- **Units and orientation**: STL, OBJ, PLY and OFF files don't record units, so they're read as millimetres, the 3D printing convention, unless you set `units`. glTF and GLB are metres and Y up by definition and are converted. OBJ files are read as Y up; set `upAxis` to `z` for CAD exports that come out lying on their side. Images and measurements use Z up, with the model's front facing −Y, as in slicers.
- **Colors and textures**: OpenSCAD's `color()`, 3MF colors, glTF materials and textures, and PLY vertex colors are drawn. OBJ materials and textures need the `.mtl` and image files next to the OBJ, for example in a ZIP archive.
- **Weight** is for a print that is solid all the way through. Infill makes real prints lighter.
- Files can be up to 300 MB, and ZIP archives up to 5,000 files and 1 GB unpacked. For meshes over 250,000 triangles, turntables are drawn from a simplified copy, where the difference doesn't show; still images and measurements always use the full mesh.

### For AI agents and developers

This Actor works with the [Apify MCP server](https://mcp.apify.com), so AI agents can call it as a tool: pass OpenSCAD in `openscadCode` (or links in `modelUrls`), ask for `sheet` to see the model from four sides in one image, and read `sheetUrl`, `sizeMm` and `volumeCm3` from the dataset item. If `status` is `failed`, `errors` says which line to fix; `echo` returns what the design printed. For a direct API call that waits for the result:

```bash
curl -X POST "https://api.apify.com/v2/acts/jumblemog~3d-model-renderer/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"openscadCode": "difference() { cube(30, center = true); sphere(19); }", "outputs": ["sheet", "stl"]}'
```

To get the image itself as the response, call `run-sync` instead. It returns the run's `OUTPUT`, the first file you asked for (or the first model's errors as JSON):

```bash
curl -X POST "https://api.apify.com/v2/acts/jumblemog~3d-model-renderer/run-sync?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"modelUrls": ["https://example.com/part.stl"], "outputs": ["png"], "imageSize": 512}' \
  -o part.png
```

### Credits

3D designs are compiled by [OpenSCAD](https://openscad.org) (GPL-2.0) with the [Manifold](https://github.com/elalish/manifold) engine (Apache-2.0) and the [BOSL2](https://github.com/BelfrySCAD/BOSL2) (BSD-2-Clause), [MCAD](https://github.com/openscad/MCAD) (LGPL-2.1), [Round-Anything](https://github.com/Irev-Dev/Round-Anything) (MIT) and [threads.scad](https://github.com/rcolyer/threads-scad) (CC0) libraries. Models are read and converted with [trimesh](https://trimesh.org) (MIT) and [fast-simplification](https://github.com/pyvista/fast-simplification) (MIT), drawn with [VTK](https://vtk.org) (BSD-3-Clause) through [PyVista](https://pyvista.org) (MIT) on [Mesa](https://mesa3d.org) (MIT), and animated with [FFmpeg](https://ffmpeg.org) (GPL) and [librsvg](https://gitlab.gnome.org/GNOME/librsvg) (LGPL-2.1). Each runs unmodified as a separate program or library. The avocado in the picture is from the [Khronos glTF Sample Assets](https://github.com/KhronosGroup/glTF-Sample-Assets) (CC0).

# Actor input Schema

## `openscadCode` (type: `string`):

A 3D or 2D design in the OpenSCAD language. It is compiled with a current OpenSCAD (Manifold engine), with the BOSL2, MCAD, Round-Anything and threads.scad libraries available through include <...>. Errors and warnings come back with their line, and echo() output is returned too.

## `modelUrls` (type: `array`):

Links to model files: .stl, .3mf, .obj, .glb, .gltf, .ply, .off or .scad, GitHub file pages, Google Drive or Dropbox share links, or ZIP archives. An archive with an OpenSCAD file renders that design (its other files can be included); otherwise every model in it is rendered.

## `uploads` (type: `array`):

Upload model files or ZIP archives from your computer.

## `outputs` (type: `array`):

Files to make for each model. Empty: a PNG image, plus an STL file for OpenSCAD designs. Size, volume and other measurements always come in the results.

## `parameters` (type: `object`):

Set variables of an OpenSCAD design without editing it, like OpenSCAD's customizer: {"width": 40, "label": "Hi", "holes": true, "size": \[10, 20, 5]}. Values can be numbers, text, true/false or lists.

## `views` (type: `array`):

The angles to draw, one PNG image each. Iso views are perspective with a soft shadow; the others are orthographic, as in a technical drawing. Models are Z up with their front facing -Y, as in slicers.

## `imageSize` (type: `integer`):

Width and height of the square images and of the four-view sheet.

## `color` (type: `string`):

Color for models (or parts) that have no color of their own, as a hex code such as #4a90d9 or #f28c28. Also the base color written into 3MF and GLB files.

## `background` (type: `string`):

Background color as a hex code, or transparent for PNG images with a transparent background (sheets and animations then use white).

## `modelColors` (type: `boolean`):

Draw colors and textures from the file: OpenSCAD color(), 3MF colors, glTF materials and textures, OBJ materials, PLY vertex colors. Off: everything in the model color.

## `edges` (type: `boolean`):

Draw thin lines along sharp edges and open borders, which makes mechanical parts easier to read, especially in front, side and top views.

## `shadow` (type: `boolean`):

A soft contact shadow under the model in iso views and animations.

## `projection` (type: `string`):

How views are projected.

## `animationSeconds` (type: `integer`):

How long one turn of the GIF or MP4 turntable takes (24 frames per second; GIFs use every other frame). Turntables are charged per second, so 3 seconds counts as 3 turntable seconds.

## `animationSize` (type: `integer`):

Width and height of the GIF and MP4 turntables.

## `upAxis` (type: `string`):

Which axis points up in the files, so models stand upright. 3D printing formats are Z up; glTF is Y up by definition; OBJ files are usually Y up but CAD exports can be Z up.

## `units` (type: `string`):

The unit of STL, OBJ, PLY, OFF and glTF coordinates, which those files don't record. Measurements are always reported in millimetres; converted files are written in millimetres (GLB in metres).

## `materialDensity` (type: `number`):

Used for solidWeightGrams, the weight of the model printed solid: 1.24 for PLA, 1.04 for ABS, 1.27 for PETG, 1.21 for TPU, 1.1 for resin. Infill makes real prints lighter.

## `inputFormat` (type: `string`):

The format of linked or uploaded files, when it can't be told from the file name or contents. Empty: automatic.

## `mainFile` (type: `string`):

The model to render inside a ZIP archive, such as box.scad or parts/lid.stl. Empty: the OpenSCAD file nearest the top of the archive, or else every model in it.

## `models` (type: `array`):

A list of models to render in the same run. Each entry is OpenSCAD code, or an object with openscadCode or url and optional name, parameters, inputFormat, mainFile, upAxis, units and color, for example the same design with different parameters: \[{"url": "https://example.com/box.scad", "name": "small", "parameters": {"width": 30}}, {"url": "https://example.com/box.scad", "name": "large", "parameters": {"width": 80}}].

## `renderTimeoutSecs` (type: `integer`):

Stop compiling an OpenSCAD design after this many seconds. Most designs take under a second; designs with minkowski() or many hull() calls take longer.

## `maxModels` (type: `integer`):

Stop after this many models, so the cost of a run stays predictable.

## Actor input object example

```json
{
  "openscadCode": "// Twisted vase: change the numbers, or send them in \"parameters\"\nheight = 120;      // mm\nradius = 34;       // mm, at the base\nsides = 7;\ntwist = 140;       // degrees from base to rim\nflare = 1.3;       // rim size / base size\nwall = 2.4;        // mm\n\nlinear_extrude(height = height, twist = twist, slices = 140, scale = flare)\n  difference() {\n    circle(r = radius, $fn = sides);\n    circle(r = radius - wall, $fn = sides);\n  }\nlinear_extrude(height = wall) circle(r = radius, $fn = sides);\n\necho(str(\"Holds about \", round(PI * pow(radius - wall, 2) * height / 1000 * 0.8), \" ml\"));\n",
  "outputs": [
    "png",
    "sheet",
    "stl"
  ],
  "parameters": {
    "twist": 140
  },
  "views": [
    "iso"
  ],
  "imageSize": 1024,
  "color": "#4a90d9",
  "background": "#ffffff",
  "modelColors": true,
  "edges": true,
  "shadow": true,
  "projection": "auto",
  "animationSeconds": 3,
  "animationSize": 512,
  "upAxis": "auto",
  "units": "auto",
  "materialDensity": 1.24,
  "renderTimeoutSecs": 120,
  "maxModels": 100
}
```

# Actor output Schema

## `results` (type: `string`):

One item per model: size, volume, watertightness and links to the images and 3D files, or the errors.

## `files` (type: `string`):

The images, animations and model files saved in the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "openscadCode": `// Twisted vase: change the numbers, or send them in "parameters"
height = 120;      // mm
radius = 34;       // mm, at the base
sides = 7;
twist = 140;       // degrees from base to rim
flare = 1.3;       // rim size / base size
wall = 2.4;        // mm

linear_extrude(height = height, twist = twist, slices = 140, scale = flare)
  difference() {
    circle(r = radius, $fn = sides);
    circle(r = radius - wall, $fn = sides);
  }
linear_extrude(height = wall) circle(r = radius, $fn = sides);

echo(str("Holds about ", round(PI * pow(radius - wall, 2) * height / 1000 * 0.8), " ml"));`,
    "outputs": [
        "png",
        "sheet",
        "stl"
    ],
    "parameters": {
        "twist": 140
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jumblemog/3d-model-renderer").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "openscadCode": """// Twisted vase: change the numbers, or send them in \"parameters\"
height = 120;      // mm
radius = 34;       // mm, at the base
sides = 7;
twist = 140;       // degrees from base to rim
flare = 1.3;       // rim size / base size
wall = 2.4;        // mm

linear_extrude(height = height, twist = twist, slices = 140, scale = flare)
  difference() {
    circle(r = radius, $fn = sides);
    circle(r = radius - wall, $fn = sides);
  }
linear_extrude(height = wall) circle(r = radius, $fn = sides);

echo(str(\"Holds about \", round(PI * pow(radius - wall, 2) * height / 1000 * 0.8), \" ml\"));
""",
    "outputs": [
        "png",
        "sheet",
        "stl",
    ],
    "parameters": { "twist": 140 },
}

# Run the Actor and wait for it to finish
run = client.actor("jumblemog/3d-model-renderer").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "openscadCode": "// Twisted vase: change the numbers, or send them in \\"parameters\\"\\nheight = 120;      // mm\\nradius = 34;       // mm, at the base\\nsides = 7;\\ntwist = 140;       // degrees from base to rim\\nflare = 1.3;       // rim size / base size\\nwall = 2.4;        // mm\\n\\nlinear_extrude(height = height, twist = twist, slices = 140, scale = flare)\\n  difference() {\\n    circle(r = radius, $fn = sides);\\n    circle(r = radius - wall, $fn = sides);\\n  }\\nlinear_extrude(height = wall) circle(r = radius, $fn = sides);\\n\\necho(str(\\"Holds about \\", round(PI * pow(radius - wall, 2) * height / 1000 * 0.8), \\" ml\\"));\\n",
  "outputs": [
    "png",
    "sheet",
    "stl"
  ],
  "parameters": {
    "twist": 140
  }
}' |
apify call jumblemog/3d-model-renderer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jumblemog/3d-model-renderer"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/avHwj4rHrIahaKzgc/builds/FjsXHA30AFn5Xkk00/openapi.json
