# How to Create Snapshots for CAD Review and Validation in Text-to-CAD

> Learn how to create snapshots for CAD review and validation in Text-to-CAD using Playwright. Automate design review and validation pipelines with rendered image outputs.

- Repository: [earthtojake/text-to-cad](https://github.com/earthtojake/text-to-cad)
- Tags: how-to-guide
- Published: 2026-07-29

---

**The snapshot skill in `earthtojake/text-to-cad` converts STEP models into rendered images (PNG, GLB, 3MF) using a headless Chromium browser via Playwright, enabling automated design review and validation pipelines.**

The `text-to-cad` repository provides a powerful snapshot skill that transforms STEP files into visual assets for documentation and quality assurance. Learning how to create snapshots for CAD review and validation allows you to automate design checks and generate consistent documentation across your engineering workflow. This guide covers the command-line interface and programmatic APIs based on the actual implementation in [`skills/cad/scripts/snapshot/__main__.py`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad/scripts/snapshot/__main__.py).

## Understanding the Snapshot Architecture

The snapshot system consists of three tightly-coupled components defined in the source code.

### CLI Parser and Options Builder

The **`parse_snapshot_args`** function in [`skills/cad/scripts/snapshot/__main__.py`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad/scripts/snapshot/__main__.py) builds a **`SnapshotOptions`** object from command-line flags, validating inputs and merging per-job selection options. This component handles path resolution for STEP files and enforces mutually exclusive constraints, such as preventing simultaneous use of **`--focus`** and **`--hide`** selectors.

### Headless Browser Renderer

The **`BatchSnapshotRenderer`** class launches a headless Chromium instance via Playwright and orchestrates the rendering pipeline. It manages viewport sizing through **`max_output_size`**, which inspects output dimensions in batch jobs and defaults to constants like **`SIMPLE_RENDER_WIDTH = 1200`** defined at the module level. The renderer wraps each operation with **`with_snapshot_timeout`**, enforcing **`DEFAULT_TIMEOUT_SECONDS`** (300 seconds) before raising a `SnapshotError`.

### Runtime JavaScript Assets

The browser loads [`skills/cad/scripts/snapshot/runtime/snapshot-render.js`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad/scripts/snapshot/runtime/snapshot-render.js), which exposes **`window.__snapshotRender`**. This function loads the STEP model via the **cadpy** library, applies appearance and display settings, and captures the canvas as a data-URL or generates GLB/3MF payloads. The CLI then decodes this payload through **`write_output_payload`** and writes the final file.

## Preparing a Render Job

A **render job** is a JSON object describing the input model, output format, view configuration, and optional selectors for focus or hiding parts.

### Single Job Structure

Minimal jobs require an `input` path and `output` destination:

```json
{
  "input": "models/gear.step",
  "output": "snapshots/gear.png",
  "mode": "rendered",
  "appearance": "workbench",
  "display": {
    "projection": "orthographic",
    "exploded": { "enabled": true, "axis": "z", "spacing": 1.5 }
  },
  "camera": "iso",
  "size_profile": "simple"
}

```

### Batch Configuration

For multiple snapshots, wrap jobs in a `jobs` array or set `"single": false`. The CLI automatically detects single-job payloads when using top-level keys versus batch arrays.

## Running the Snapshot CLI

The entry point is the Python script at [`skills/cad/scripts/snapshot/__main__.py`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad/scripts/snapshot/__main__.py), invoked as a module. It accepts either direct flags or a JSON job file.

### Command-Line Execution

Generate a single PNG from a STEP file using appearance and display settings:

```bash
python skills/cad/scripts/snapshot \
  --input models/robot_arm.step \
  --output snapshots/robot_arm.png \
  --appearance workbench \
  --display rendered \
  --camera iso \
  --size-profile diagnostic

```

### Essential CLI Flags

- **`--input`**: Path to `.step` or `.stp` file (required unless using `--job`)
- **`--output`**: Destination path (supports PNG, GLB, 3MF extensions)
- **`--appearance`**: Theme name, JSON object, or path to JSON appearance file
- **`--display`**: Display mode (`solid`, `rendered`, `transparent`) or JSON descriptor
- **`--camera`**: Preset (`iso`, `top`, `front`) or JSON camera definition
- **`--focus` / `--hide`**: Selector refs like `#o1.2` to isolate or hide parts (mutually exclusive)
- **`--size-profile`**: Predefined dimensions (`simple`, `diagnostic`, `assembly`, `presentation`, `orbit`, `contact-sheet`)
- **`--view-labels`**: Burn camera labels into the output image

### Batch Rendering

Process multiple jobs using a JSON file:

```bash
python skills/cad/scripts/snapshot --job batch.json

```

Example batch configuration:

```json
{
  "jobs": [
    {
      "input": "models/gear.step",
      "output": "snapshots/gear.png",
      "mode": "rendered",
      "appearance": "workbench",
      "display": "rendered"
    },
    {
      "input": "models/gear.step",
      "output": "snapshots/gear.glb",
      "mode": "view",
      "appearance": "workbench",
      "display": { "mode": "wireframe" }
    }
  ]
}

```

## Programmatic Rendering

Import the renderer directly for integration into Python applications without invoking the CLI:

```python
import asyncio
import json
from skills.cad.scripts.snapshot.__main__ import (
    BatchSnapshotRenderer, 
    normalize_snapshot_job_packet,
    render_resolved_job_packet
)

async def programmatic_render():
    raw = '{"input":"models/part.step","output":"snapshots/part.png"}'
    single, jobs = normalize_snapshot_job_packet(json.loads(raw))
    packet = {"single": single, "jobs": jobs}
    result = await render_resolved_job_packet(packet)
    print(result)

asyncio.run(programmatic_render())

```

This approach uses **`render_resolved_job_packet`** to handle packet processing and **`print_render_result`** for status output, mirroring the CLI's internal workflow.

## Configuring Advanced Visual Settings

### Appearance and Display Modes

The **`appearance`** parameter controls materials and lighting themes, while **`display`** manages geometry representation (solid, wireframe, transparent). These settings map directly to the runtime JavaScript that configures the WebGL rendering context in [`snapshot-render.js`](https://github.com/earthtojake/text-to-cad/blob/main/snapshot-render.js).

### Size Profiles and Viewport Control

Size profiles define canvas dimensions for different use cases:

- **`simple`**: Standard documentation size (1200px width default)
- **`diagnostic`**: Detail-oriented inspection views
- **`assembly`**: Larger canvas for complex multi-part models
- **`presentation`**: Publication-quality high resolution
- **`orbit`** and **`contact-sheet`**: Specialized layouts for specific review workflows

The renderer automatically selects the largest required dimensions when processing batches via **`max_output_size`**.

## Summary

- The snapshot skill converts **STEP models** to **PNG, GLB, or 3MF** formats using a **headless Chromium** renderer via Playwright, as implemented in [`skills/cad/scripts/snapshot/__main__.py`](https://github.com/earthtojake/text-to-cad/blob/main/skills/cad/scripts/snapshot/__main__.py).
- Configuration happens through **`SnapshotOptions`** parsed by **`parse_snapshot_args`** and executed by **`BatchSnapshotRenderer`**.
- Jobs support both **single-file** and **batch** modes via JSON configuration, with automatic viewport sizing and 300-second timeout protection via `DEFAULT_TIMEOUT_SECONDS`.
- **Runtime assets** in [`snapshot-render.js`](https://github.com/earthtojake/text-to-cad/blob/main/snapshot-render.js) handle the actual WebGL rendering through **`window.__snapshotRender`**, utilizing the **cadpy** library for model conversion and `write_output_payload` for file serialization.

## Frequently Asked Questions

### What output formats does the snapshot tool support?

The snapshot tool generates **PNG** images for documentation, **GLB** files for web-based 3D viewing, and **3MF** files for manufacturing workflows. The format is determined by the file extension specified in the `--output` flag or JSON job configuration. The runtime JavaScript in [`snapshot-render.js`](https://github.com/earthtojake/text-to-cad/blob/main/snapshot-render.js) handles format-specific encoding before returning data to the CLI for writing.

### Can I render multiple CAD models in a single command?

Yes. Create a JSON file with a `jobs` array containing multiple render configurations, then invoke `python skills/cad/scripts/snapshot --job batch.json`. The **`BatchSnapshotRenderer`** reuses the same Chromium instance across jobs, significantly improving performance when generating multiple views of the same assembly or processing multiple parts sequentially.

### How do I troubleshoot timeout errors during rendering?

The default **`DEFAULT_TIMEOUT_SECONDS`** is set to 300 seconds (5 minutes) in [`__main__.py`](https://github.com/earthtojake/text-to-cad/blob/main/__main__.py). If complex assemblies exceed this limit, the renderer raises a `SnapshotError`. Ensure Playwright is properly installed with `python -m playwright install chromium`, and consider simplifying display modes or reducing model complexity. For batch operations, verify that `max_output_size` calculations do not request excessively large viewports that slow down the browser renderer.

### What is the difference between `--focus` and `--hide` selectors?

Both options use selector references like `#o1.2` to manipulate visibility, but they are **mutually exclusive**. **`--focus`** isolates specific parts while hiding all others, while **`--hide`** removes specific parts from view while keeping the rest visible. The CLI parser in `parse_snapshot_args` aborts with a `SnapshotError` if you attempt to use both flags simultaneously, enforcing a single visibility strategy per job.