A beginner‑friendly clone of text‑to‑cad using only Python’s standard library
Welcome to another official UVF IT guide! In this quick build you’ll create a minimal text‑to‑CAD converter that parses simple shape commands and outputs an OpenSCAD file you can view locally. It’s inspired by the real text‑to‑cad project but stripped down to the essentials so you can finish in about 45 minutes.
The stack is pure Python (no external CAD kernels) and SQLite for storing generated snippets. All tools are free‑tier and run on any modern OS.
sqlite3 module (bundled with Python).Create a clean workspace so later steps don’t interfere with other Python work. We’ll spin up a virtual environment, activate it, and add a single file called converter.py where all our logic will live. This keeps dependencies isolated and mirrors professional projects.
The scaffold is tiny: just the env and an empty source file. You’ll later add a tiny SQLite helper, but for now we only need the file to exist so the parser can be imported without errors.
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install --upgrade pip
touch converter.pyNow we give the converter its brain. The parser reads a line like cube 10 or cylinder 5 20 and turns it into an OpenSCAD snippet. We keep the logic straightforward: split the line, validate the shape, and format the appropriate OpenSCAD call.
The function returns a string so the caller can either write it to a file or store it in SQLite later. Errors raise a clear ValueError so the user knows what went wrong.
converter.py
import sqlite3
def parse_line(line: str) -> str:
"""Convert a simple shape command into an OpenSCAD string.
Supported commands:
cube <size>
cylinder <radius> <height>
"""
parts = line.strip().split()
if not parts:
raise ValueError("Empty command")
shape = parts[0].lower()
if shape == "cube" and len(parts) == 2:
size = float(parts[1])
return f"cube({size});"
if shape == "cylinder" and len(parts) == 3:
r, h = map(float, parts[1:])
return f"cylinder(r={r}, h={h});"
raise ValueError(f"Unsupported or malformed command: {line}")
# Tiny helper to persist snippets – not used yet but handy for later phases
def save_snippet(db_path: str, snippet: str) -> None:
conn = sqlite3.connect(db_path)
cur = conn.cursor()
cur.execute("CREATE TABLE IF NOT EXISTS snippets(id INTEGER PRIMARY KEY AUTOINCREMENT, code TEXT)")
cur.execute("INSERT INTO snippets(code) VALUES(?)", (snippet,))
conn.commit()
conn.close()We now give the user a tiny command‑line interface. By passing a shape description as a single argument the script parses it, writes the corresponding OpenSCAD code to output.scad, and stores the raw line in a tiny SQLite log for later inspection. This keeps the tool usable without any GUI while still persisting what was generated.
Running the script is as easy as typing python converter.py "cube 10". The quotes protect the space‑separated parameters from the shell, and the script will echo a short success message so you know the file was created.
python converter.py "cube 10"After the file is written, open it in the free OpenSCAD application to see the actual 3‑D model. OpenSCAD reads the .scad script and renders the geometry instantly, giving you visual confirmation that the parser worked correctly.
If you are on macOS, the open command will launch the default app for .scad files. On Linux you can use xdg-open, and on Windows start. Adjust the command for your platform.
# macOS
open output.scad
# Linux
# xdg-open output.scad
# Windows
# start output.scadWant to expose the converter over HTTP? A minimal Flask stub can turn the same parsing logic into a tiny web service. You can POST a shape string to /convert and receive the generated OpenSCAD code as plain text. This is a convenient way to integrate the tool into other pipelines or front‑ends without rewriting the core logic.
The Flask app re‑uses the parse_line function from converter.py, so all existing shapes continue to work. You can later add more routes, authentication, or even a tiny HTML form if you wish.
app.py
from flask import Flask, request, jsonify
import subprocess, os, sys
# Import the parsing function from our existing script
sys.path.append(os.path.dirname(__file__))
from converter import parse_line, write_scad
app = Flask(__name__)
@app.route('/convert', methods=['POST'])
def convert():
# Expect a JSON payload like {"shape": "cube 10"}
data = request.get_json(silent=True) or {}
shape_cmd = data.get('shape', '')
if not shape_cmd:
return jsonify({'error': 'No shape provided'}), 400
# Reuse the core parser
scad_line = parse_line(shape_cmd)
if not scad_line:
return jsonify({'error': 'Unsupported shape'}), 400
# Write a temporary file for visual debugging (optional)
write_scad(scad_line, filename='temp_output.scad')
return jsonify({'scad': scad_line})
if __name__ == '__main__':
app.run(debug=True)| Check | Command / Why it matters |
|---|---|
Run python converter.py "cube 10" without errors | Shows 'Wrote output.scad' and creates snippets.db |
cat output.scad displays cube(10); | Confirms correct OpenSCAD generation |
Open output.scad in OpenSCAD and see a 10×10×10 cube | Visual verification of the shape |
Your minimal text‑to‑CAD clone is now functional. Feel free to grow it by adding more geometry, a web UI, or integration with real CAD kernels like build123d. Happy coding!