dxf

Generate, regenerate, and validate 2D DXF drawings from Python build123d sources. Use for DXF files, `.py` drawing scripts, @dxf models, 2D profiles, outlines, templates, gaskets, panels, flat patterns, laser/plasma/waterjet cut layouts, and 2D drawing exports of CAD geometry.

By earthtojake · 6,199 installs

npx skills add earthtojake/text-to-cad --skill dxf

Source repository · Upstream listing

DXF generation and validation Provenance: maintained in [earthtojake/text to cad](https://github.com/earthtojake/text to cad). Use the installed local skill files as the runtime source of truth; the repository link is only for provenance and release review. Setup Run cadgen through the cadgen command its installation writes, so this skill's commands share one installation, and its engine server, with the CAD app's: cadgen below means cadgen +0.8.2 ( ~/.local/bin/cadgen +0.8.2 where ~/.local/bin is not on your PATH) python below means cadgen +0.8.2 run If cadgen is not on your PATH, or it says 0.8.2 is not installed, run uvx no config managed python python 3.13 from cadgen==0.8.2 cadgen doctor once, outside any sandbox or with its permission: it installs cadgen, registers it, writes the cadgen command and starts the engine. With the CAD app's server running, nothing else needs the sandbox's permission: it starts the engine and holds it. Without it, a sandboxed shell cannot start the engine; when a command says no engine is running, run cadgen server outside the sandbox once. cadgen doctor <skill dir reports the installation in use and checks that it is the one this skill pins, that the CAD kernel loads, and whether the engine every build runs in is running, starting it when none is; use it for installation or kernel load errors. Drawings are build123d geometry, so a drawing builds in the engine's warm worker like any model: the first run of a script loads the CAD kernel (a few seconds), and later runs reuse it. Purpose Create or modify 2D DXF drawings from natural language requirements or from CAD geometry, export validated DXF files, and return checked outputs. A drawing's source of truth is a Python file named <name .py defining a parameterless @model function that returns planar geometry. A drawing is a model. It builds as any $cad model does: python <name .py rebuilds it in the engine, prints its document's id: and page, and writes nothing. The DXF is exported from that document, by build123d's own exporter, once the drawing checks pass: cadgen export <id drawing.dxf . A drawing that calls a part model ( bracket() in its body) builds that part in the same run. The CAD Viewer and cadgen snapshot read the .dxf itself, so the file you hand a cutting service, the file the viewer draws and the file a snapshot renders are one and the same. The contract A drawing is a @model function that takes no parameters and returns build123d 2D geometry on z=0: a sketch, a face, wires or edges. cadgen export writes the DXF. You never construct a document, name an entity, or write a file from the model. One shape is one layer, CUT . That is the whole contract for most drawings. A layer per part when the drawing genuinely has more than one CAM operation: return a Compound of labelled children, each label its layer ( profile.label, marks.label = "CUT", "ENGRAVE" ). Children sharing a label share a layer, and several shapes make one part of a layer as bd.Compound([a, b], label="ENGRAVE") . A layer name may not be empty or hold any of < /\":;? = and a backtick. Planar means 2D, on z=0. The export refuses a document holding a solid ( bracket is 3D: a DXF is drawn from 2D geometry a model returns ) and an edge with any point more than 1e 6 mm off z=0, by its element name. A face taken from a solid sits at that solid's height; relocate it ( flatten.flatten face(face) , or bd.Location((0, 0, z)) face ). No parameters. Dimensions are module constants ( HOLE D = 4.5 ) or constants imported from the part the drawing derives from; a different drawing is a different @model function. Text is bd.Text(...) engraved OUTLINES on a marking layer, never a DXF TEXT entity: cut and marking toolchains consume geometry, and font rendering inside CAM is unreliable. Output bytes are a function of the geometry. Layers are written in name order and entities in an order of their content, so an unchanged drawing exports an identical file, on any machine, and the file is replaced only when its bytes change. Drawings delivered after every change go in an exports.py beside them that imports each drawing and calls export(drawing, path) (the model function itself, or the handle its call returns): The three DXF workflows Copy the full template for the applicable workflow from references/generator templates.md when creating a new drawing. 1. Drafted from scratch (gaskets, panels, templates, cut layouts with no 3D model behind them): a <name .py that builds sketches and returns them. 2. Flat pattern of a part this project models : a drawing script beside the model it derives from, with its OWN stem ( bracket drawing.py beside bracket.py ). Import the model and call it, exactly as an assembly composes a child: importing never builds, and inside the drawing's run the call builds the part in the same run and returns its geometry. An edit to the part re runs the drawing's body on its next run; an edit the part's body does not reach (a comment, another model) re runs nothing. 3. Flat pattern of an imported STEP (a .step / .stp with no Python source): read it with read step , or convert it once ( cadgen export vendor panel.step vendor panel.xbf ) and read the xbf with read xbf , which is faster. Like every file a run reads, it is an input: replacing the vendor file re runs the drawing. Never read a file this project exports. Keep source STEPs in a vendor/ directory beside the drawing, committed like any other input. For a part this project models, use workflow 2: import the model and call it. One model per file is the recommendation, and a drawing gets its own script. A file MAY declare several models (two drawings, or a drawing beside a part's @model ): python <file .py builds every one its main block calls, each with its own id. A drawing composes models, never the reverse. Use this skill when Use this skill when the user asks for DXF files, 2D drawings, profiles, outlines, templates, gaskets, panels, flat patterns, or cut layouts for laser, plasma, waterjet, or CNC routing. Use $cad for the 3D part or assembly a DXF derives from. Use $sendcutsend for SendCutSend specific upload preflight. Defaults Use these defaults unless the user specifies otherwise: Units: millimeters. The engine sets them; a drawing never declares units. Geometry lives at 1:1 scale in the XY plane. Cut profiles close. Open contours belong on bend/engrave/reference layers: the drawing checks enforce this (see Validation). For CAD backed parts, derive contours from the real topology with cadgen.flatten rather than redrawing them: planar faces selects, flatten face lays a face into XY exactly, union faces fuses, and flat pattern does all of it in one call. Hand drawn parametric outlines only when there is no reliable 3D topology. Kerf / tool radius compensation is flatten.offset profile(shape, amount) or flat pattern(..., kerf=...) ; never hand offset coordinates. Curves stay curves. The union and the offset are exact OCC operations, and each edge is written as one entity, so a filleted corner exports as an ARC and a hole as a CIRCLE , kerf included. A profile that comes out as hundreds of short LINE s means something fell back to the sampled path: investigate rather than accept it. Layers carry intent: keep cut geometry and bend/fold lines on separate layers, and name bend layers with bend or fold so downstream tools classify them as bends rather than cuts. DXF layers are drawing structure, not STEP part/assembly structure. Tool Running the script is the only way to build a drawing, and exporting it the only way to write its DXF. python <drawing .py takes no options and writes nothing; it prints each model's report ( built src/gasket.py::gasket cold in 2.29s: ... ), its id: and its page, and exits 1 when a body raises. cadgen export exits 2 when the export refuses the drawing (3D, off the plane, a failed drawing check), naming which. An imported .dxf needs nothing at all: hand it straight to a snapshot or the viewer. Paths on the command line, and those export takes from Python, resolve from the working directory; anchor them on file in an exports.py . Keep a drawing script in the same directory as the geometry it derives from, named <name .py . cadgen snapshot draws a drawing the way the CAD Viewer's drawing pane does: whole, from above, fitted with a margin, in the pens the file declares (an entity with no pen of its own takes the paper's ink), on light paper or, with display '{"appearance": "dark"}' , dark. size profile , width and height size it; camera takes a plan view (below), annotation ink on the sheet and measurements dimensions; every other flag is refused by name, and what it does not draw (points, hatch patterns, images) is named in a warning. OUT is written exactly as given and must be a .png ; check the exit status before reading it, since a refused or failed snapshot writes nothing. A Quick Edit prompt from a drawing carries a packet (inline JSON or a .snapshot.json path; save inline JSON to a file first) whose views are plan view camera windows ( {"position": [x, y, d], "target": [x, y, 0], "up": [0, 1, 0], "orthographicHalfHeight": h} , looking straight down) and whose annotation marks are in drawing coordinates, on the sheet. Draw what the person saw, each window with their ink and dimensions on it, before editing: No CLI inspects an existing .dxf . For entity/layer checks read it with ezdxf directly (it arrives with build123d), and validate dxf file for the drawing checks; review geometry visually (see [Show the model]( show the model)). Workflow 1. Convert the request into a short brief: outline dimensions, holes and slots, layers, units, output path, and validation targets. 2. Pick the workflow: drafted from scratch, flat pattern of a modelled part (create and validate the 3D geometry with $cad first), or flat pattern of an imported STEP. 3. Write or edit the <name .py source with meaningful dimensions as named constants, reusing the model's geometry helpers instead of duplicating formulas. 4. Run each drawing script directly ( python <drawing .py ); do not sweep directories. Then export each drawing to its DXF: 5. Validate the exported DXF deterministically, then hand off and report. Show the model Show the user each model you create or change, and any model or file they ask to see. A file you export is a download: give its path, do not open it. Snapshots and validation don't replace this. Never screenshot the viewer to confirm your own work; review with cadgen snapshot . If your tools include cad show (your host may prefix it), call it with the model's id or the file's absolute path, and follow its description for when to call it again. The other tools depend on the host. A host that draws CAD cards or tabs (Claude Desktop, the Codex app) also has cad view , which reads what the user selected, and cad screenshot , which shows you what they see, both of a card or tab that is open, for when they ask about it. A text host (Claude Code in a terminal, codex exec ) draws nothing: its cad show opens the model's page in the user's browser and answers with the URL to give them, and it has no view to read. cad inspect , cad snapshot and cad export are on every host. Call only the tools you have, and never say a card shows a model when your host drew none. Otherwise give the user the page's link once: a model's page is the view: line its run prints. For a file, run the CAD Viewer, from any folder: The command ensures this installation's engine, registers each file and prints its page, /<id , then