{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-11-02-antimony-cad-software-evolved-from-lisp-machines-and-not/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "## about\n\nAntimony is a computer-aided design (CAD) tool from a parallel universe in which CAD software evolved from Lisp machines rather than drafting tables.\n\n## demo\n\n[player.vimeo.com](https://player.vimeo.com/video/125111378)\n\n## foundations\n\nAntimony is built on three mostly-orthogonal axes:\n\n- A framework for tracking information flow through directed acyclic graphs\n- A geometry engine for doing [CSG](http://en.wikipedia.org/wiki/Constructive_solid_geometry)\n- A standard library of shapes and transforms\n\n### Graph engine\n\nSolid modeling in Antimony is done by connecting nodes in a graph:\\\n ![Graph example](https://www.mattkeeter.com/projects/antimony/3/images/graph.png)\n\nEach node is defined by a customizable script. Antimony uses Python 3.x plus a few extra magic keywords.\n\nHere's what the circle node above looks like:\n\n```python\nimport fab.shapes\n\n# Define a set of input ports\n# (and inject variables into the local namespace)\ninput('x', float)\ninput('y', float)\ninput('r', float)\n\n# Call the 'circle' function in the standard shapes library\n# using the variables that came in from the input ports\nc = fab.shapes.circle(x, y, r)\n\n# Create an output port that produces the circle shape\noutput('shape', c)\n```\n\nNodes usually represent a primitive shape or transform. Links are tracked and changes are automatically propagated downstream.\n\n![Change propagation](https://www.mattkeeter.com/projects/antimony/3/images/tracking.gif)\n\nThe graph engine scales up to complex multi-part assembles.\n\n![Kelvin](https://www.mattkeeter.com/projects/antimony/3/images/big.png)\n\n![Kelvin](https://www.mattkeeter.com/projects/antimony/3/images/bigger.png)\n\n### Geometry engine\n\nAntimony's geometry engine uses [functional representations](http://en.wikipedia.org/wiki/Function_representation) for solid modeling. This representation is particularly suitable for modeling with boolean operations (union / intersection / difference).\n\n![Boolean example](https://www.mattkeeter.com/projects/antimony/3/images/csg.png)\n\nIn the application, the geometry engine renders shapes as shaded bitmaps. They're then blitted to a 3D viewport.\n\n![Application screenshot](https://www.mattkeeter.com/projects/antimony/3/images/app.png)\n\nAntimony can export heightmaps for 2.5D processes and `.stl` files for 3D manufacturing. The `.stl` export includes feature detection to keep corners and edges sharp.\n\n![Mesh](https://www.mattkeeter.com/projects/antimony/3/images/export.png)\n\n### Standard library\n\nAntimony's standard library defines many [shapes and transforms](https://github.com/mkeeter/antimony/blob/develop/py/fab/shapes.py), from basic (rotate, scale, boolean operations) to unusual (attract, repel, bend).\n\nThese shapes are used in node definitions, which typically add input and output ports and can optionally define UI features.\n\nHere's an example of a node that defines UI features:\n\n```python\nimport fab\n\ntitle('Rectangle')\n\ninput('xmin', float)\ninput('ymin', float)\ninput('xmax', float, 1)\ninput('ymax', float, 1)\n\noutput('shape', fab.shapes.rectangle(xmin, xmax, ymin, ymax))\n\n# UI\nsb.ui.wireframe([(xmin, ymin, 0), (xmax, ymin, 0),\n                 (xmax, ymax, 0), (xmin, ymax, 0)], close=True)\nsb.ui.point(xmin, ymin, 0)\nsb.ui.point(xmax, ymax, 0)\n```\n\nIn the 3D viewport, the UI features defined at the bottom of the script are drawn over the rendering of the rectangle.\n\nThese UI features are hooked back into the graph: dragging the points at the rectangle's corners pushes changes to the graph node.\n\n![UI dragging](https://www.mattkeeter.com/projects/antimony/3/images/dragging.gif)\n\n**As an aside**: most users will be satisfied with the built-in shapes, but it's also possible to define custom shapes.\n\nShapes are represented with a prefix string syntax that's easy to parse but a bit cryptic to decipher. Here's the definition for the circle shape used above:\n\n```python\ndef circle(x0, y0, r):\n    return Shape(\n            '-r+q-Xf%gq-Yf%gf%g' % (x0, y0, r), # math string\n            x0 - r, y0 - r, x0 + r, y0 + r)     # bounds\n```\n\nUnpacking and hierarchically indenting the prefix string gives\n\n```python\n-\n  r\n    +\n      q\n        -\n          X\n          f%g\n      q\n        -\n          Y\n          f%g\n  f%g\n% (x, y, r)\n```\n\nThis encodes a distance field representation of a 2D circle:\n\n```python\nf(x,y) = sqrt(pow(x - x0, 2) + pow(y - y0, 2)) - r\n```\n\nwhere `x0`, `y0`, and `r` are the circle's center and radius (specified when `circle` is called).\n\nThe exact mapping from prefix strings to infix functions is left as an exercise for the reader (or can be looked up in Appendix A of [my thesis](https://www.mattkeeter.com/research/thesis.pdf)).\n\n## download\n\nA prebuilt Mac application can be downloaded [from the Github releases page](https://github.com/mkeeter/antimony/releases).\n\nAntimony's source is [available on Github](https://github.com/mkeeter/antimony), along with instructions for [building it](https://github.com/mkeeter/antimony/blob/master/BUILDING.md) on Mac and Linux.\n\n## development\n\nAntimony is a long-running project under [active development](https://github.com/mkeeter/antimony/graphs/contributors).\n\n![Development](https://www.mattkeeter.com/projects/antimony/3/images/development.png)\n\nIt's at a beta level of stability: solid, but not recommended for mission-critical use.\n\nIf you're interested in contributing, there's a pretty low bar for entry. Given basic Python knowledge, you can get started making custom nodes (like this [HSB color node](https://github.com/mkeeter/antimony/blob/develop/py/nodes/Color/set_color_hsb.node) contributed by [RobotGrrl](https://twitter.com/RobotGrrl) or the [plethora of nodes](https://github.com/mkeeter/antimony/commits?author=neilger) contributed by [Neil](http://ng.cba.mit.edu/)).\n\nFor more ambitious folks with C++ experience, there are a whole host of improvements that could be made, from speeding up rendering to cleaning up the UI and optimizing graph evaluation. Send me a note if this piques your interest.\n\n## history\n\nAntimony grew out of my work on powerful personal-scale CAD/CAM workflows at the [MIT Center for Bits and Atoms](http://cba.mit.edu).\n\nIt's the latest tool in a line of software that included [cad\\_ui](https://www.mattkeeter.com/projects/solver) and [kokopelli](https://www.mattkeeter.com/projects/kokopelli), and draws inspiration from [fabserver](http://kokompe.cba.mit.edu).\n\nFor a historical perspective, there are a set of earlier Antimony writeups:\n\n- [Early 2014](https://www.mattkeeter.com/projects/antimony/1) (developed as a demo for the World Economic Forum)\n- [Fall 2014](https://www.mattkeeter.com/projects/antimony/2) (updated for use in How to Make Almost Anything)\n\nThis update coincides with the 2015 edition of [Fab Academy](http://fabacademy.org/); use [this search query](https://www.google.com/search?q=site%3Ahttp%3A%2F%2Ffabacademy.org%2Farchives%2F2015%2F%20antimony&rct=j) to see how people are using it.\n\n## press & discussion\n\n- [Hackaday write-up](http://hackaday.com/2015/05/29/otherworldy-cad-software-hails-from-a-parallel-universe/)\n- [Interview with Libre Graphics World](https://librearts.org/2015/05/introducing-antimony-node-based-cad-application/)\n- [Hacker News discussion](https://news.ycombinator.com/item?id=9623609)\n",
  "authors": [
    "pmkary"
  ],
  "captured_at": "2026-11-04T00:52:13.198927099+00:00",
  "category": "news",
  "content_html": "<h2>about</h2>\n<p>Antimony is a computer-aided design (CAD) tool from a parallel universe in which CAD software evolved from Lisp machines rather than drafting tables.</p>\n<h2>demo</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://player.vimeo.com/video/125111378\">player.vimeo.com</a></p>\n<h2>foundations</h2>\n<p>Antimony is built on three mostly-orthogonal axes:</p>\n<ul>\n<li>A framework for tracking information flow through directed acyclic graphs</li>\n<li>A geometry engine for doing <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"http://en.wikipedia.org/wiki/Constructive_solid_geometry\">CSG</a></li>\n<li>A standard library of shapes and transforms</li>\n</ul>\n<h3>Graph engine</h3>\n<p>Solid modeling in Antimony is done by connecting nodes in a graph:<br />\n<picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/graph.png\" alt=\"Graph example\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Each node is defined by a customizable script. Antimony uses Python 3.x plus a few extra magic keywords.</p>\n<p>Here's what the circle node above looks like:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">fab</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">shapes</span></span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Define a set of input ports\n</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> (and inject variables into the local namespace)\n</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">input</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">x<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">float</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">input</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">y<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">float</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">input</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">r<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">float</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Call the &#39;circle&#39; function in the standard shapes library\n</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> using the variables that came in from the input ports\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">c</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">fab</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">shapes</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">circle</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> Create an output port that produces the circle shape\n</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">output</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">shape<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">c</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>Nodes usually represent a primitive shape or transform. Links are tracked and changes are automatically propagated downstream.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/tracking.gif\" alt=\"Change propagation\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>The graph engine scales up to complex multi-part assembles.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/big.png\" alt=\"Kelvin\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/bigger.png\" alt=\"Kelvin\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h3>Geometry engine</h3>\n<p>Antimony's geometry engine uses <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"http://en.wikipedia.org/wiki/Function_representation\">functional representations</a> for solid modeling. This representation is particularly suitable for modeling with boolean operations (union / intersection / difference).</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/csg.png\" alt=\"Boolean example\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>In the application, the geometry engine renders shapes as shaded bitmaps. They're then blitted to a 3D viewport.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/app.png\" alt=\"Application screenshot\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Antimony can export heightmaps for 2.5D processes and <code>.stl</code> files for 3D manufacturing. The <code>.stl</code> export includes feature detection to keep corners and edges sharp.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/export.png\" alt=\"Mesh\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<h3>Standard library</h3>\n<p>Antimony's standard library defines many <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mkeeter/antimony/blob/develop/py/fab/shapes.py\">shapes and transforms</a>, from basic (rotate, scale, boolean operations) to unusual (attract, repel, bend).</p>\n<p>These shapes are used in node definitions, which typically add input and output ports and can optionally define UI features.</p>\n<p>Here's an example of a node that defines UI features:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">fab</span></span></span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">title</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">Rectangle<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">input</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">xmin<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">float</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">input</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">ymin<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">float</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">input</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">xmax<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">float</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">input</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">ymax<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-type syntax-python\">float</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">output</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">shape<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">fab</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">shapes</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">rectangle</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmin</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmax</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymin</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymax</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> UI\n</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">sb</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">ui</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">wireframe</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmin</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymin</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmax</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymin</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span>\n                 <span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmax</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymax</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-list syntax-python\">,</span> <span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmin</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymax</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">close</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">True</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">sb</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">ui</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">point</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmin</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymin</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">sb</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">ui</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">point</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">xmax</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ymax</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>In the 3D viewport, the UI features defined at the bottom of the script are drawn over the rendering of the rectangle.</p>\n<p>These UI features are hooked back into the graph: dragging the points at the rectangle's corners pushes changes to the graph node.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/dragging.gif\" alt=\"UI dragging\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p><strong>As an aside</strong>: most users will be satisfied with the built-in shapes, but it's also possible to define custom shapes.</p>\n<p>Shapes are represented with a prefix string syntax that's easy to parse but a bit cryptic to decipher. Here's the definition for the circle shape used above:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-storage syntax-type syntax-function syntax-python\">def</span> <span class=\"syntax-entity syntax-name syntax-function syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">circle</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-python\">(</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">x0</span><span class=\"syntax-punctuation syntax-separator syntax-parameters syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">y0</span><span class=\"syntax-punctuation syntax-separator syntax-parameters syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">r</span><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-function syntax-begin syntax-python\">:</span></span>\n    <span class=\"syntax-keyword syntax-control syntax-flow syntax-return syntax-python\">return</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Shape</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n            <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">-r+q-Xf<span class=\"syntax-constant syntax-other syntax-placeholder syntax-python\">%g</span>q-Yf<span class=\"syntax-constant syntax-other syntax-placeholder syntax-python\">%g</span>f<span class=\"syntax-constant syntax-other syntax-placeholder syntax-python\">%g</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">%</span> <span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x0</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y0</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> math string\n</span>            <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x0</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y0</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x0</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">+</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y0</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">+</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>     <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> bounds\n</span></span></span></code></pre>\n<p>Unpacking and hierarchically indenting the prefix string gives</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span>\n  <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span>\n    <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">+</span>\n      <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">q</span></span>\n        <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span>\n          <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">X</span></span>\n          <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">f</span></span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">%</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">g</span></span>\n      <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">q</span></span>\n        <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span>\n          <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">Y</span></span>\n          <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">f</span></span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">%</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">g</span></span>\n  <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">f</span></span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">%</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">g</span></span>\n<span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">%</span> <span class=\"syntax-meta syntax-group syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y</span></span><span class=\"syntax-punctuation syntax-separator syntax-tuple syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>This encodes a distance field representation of a 2D circle:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">f</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">sqrt</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">pow</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">x0</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">2</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">+</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">pow</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">y0</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">2</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">r</span></span>\n</span></span></code></pre>\n<p>where <code>x0</code>, <code>y0</code>, and <code>r</code> are the circle's center and radius (specified when <code>circle</code> is called).</p>\n<p>The exact mapping from prefix strings to infix functions is left as an exercise for the reader (or can be looked up in Appendix A of <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.mattkeeter.com/research/thesis.pdf\">my thesis</a>).</p>\n<h2>download</h2>\n<p>A prebuilt Mac application can be downloaded <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mkeeter/antimony/releases\">from the Github releases page</a>.</p>\n<p>Antimony's source is <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mkeeter/antimony\">available on Github</a>, along with instructions for <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mkeeter/antimony/blob/master/BUILDING.md\">building it</a> on Mac and Linux.</p>\n<h2>development</h2>\n<p>Antimony is a long-running project under <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mkeeter/antimony/graphs/contributors\">active development</a>.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://www.mattkeeter.com/projects/antimony/3/images/development.png\" alt=\"Development\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>It's at a beta level of stability: solid, but not recommended for mission-critical use.</p>\n<p>If you're interested in contributing, there's a pretty low bar for entry. Given basic Python knowledge, you can get started making custom nodes (like this <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mkeeter/antimony/blob/develop/py/nodes/Color/set_color_hsb.node\">HSB color node</a> contributed by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://twitter.com/RobotGrrl\">RobotGrrl</a> or the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/mkeeter/antimony/commits?author=neilger\">plethora of nodes</a> contributed by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"http://ng.cba.mit.edu/\">Neil</a>).</p>\n<p>For more ambitious folks with C++ experience, there are a whole host of improvements that could be made, from speeding up rendering to cleaning up the UI and optimizing graph evaluation. Send me a note if this piques your interest.</p>\n<h2>history</h2>\n<p>Antimony grew out of my work on powerful personal-scale CAD/CAM workflows at the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"http://cba.mit.edu\">MIT Center for Bits and Atoms</a>.</p>\n<p>It's the latest tool in a line of software that included <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.mattkeeter.com/projects/solver\">cad_ui</a> and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.mattkeeter.com/projects/kokopelli\">kokopelli</a>, and draws inspiration from <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"http://kokompe.cba.mit.edu\">fabserver</a>.</p>\n<p>For a historical perspective, there are a set of earlier Antimony writeups:</p>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.mattkeeter.com/projects/antimony/1\">Early 2014</a> (developed as a demo for the World Economic Forum)</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.mattkeeter.com/projects/antimony/2\">Fall 2014</a> (updated for use in How to Make Almost Anything)</li>\n</ul>\n<p>This update coincides with the 2015 edition of <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"http://fabacademy.org/\">Fab Academy</a>; use <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.google.com/search?q=site%3Ahttp%3A%2F%2Ffabacademy.org%2Farchives%2F2015%2F%20antimony&amp;rct=j\">this search query</a> to see how people are using it.</p>\n<h2>press &amp; discussion</h2>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"http://hackaday.com/2015/05/29/otherworldy-cad-software-hails-from-a-parallel-universe/\">Hackaday write-up</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://librearts.org/2015/05/introducing-antimony-node-based-cad-application/\">Interview with Libre Graphics World</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://news.ycombinator.com/item?id=9623609\">Hacker News discussion</a></li>\n</ul>\n",
  "content_markdown": "## about\n\nAntimony is a computer-aided design (CAD) tool from a parallel universe in which CAD software evolved from Lisp machines rather than drafting tables.\n\n## demo\n\n[player.vimeo.com](https://player.vimeo.com/video/125111378)\n\n## foundations\n\nAntimony is built on three mostly-orthogonal axes:\n\n- A framework for tracking information flow through directed acyclic graphs\n- A geometry engine for doing [CSG](http://en.wikipedia.org/wiki/Constructive_solid_geometry)\n- A standard library of shapes and transforms\n\n### Graph engine\n\nSolid modeling in Antimony is done by connecting nodes in a graph:\\\n ![Graph example](https://www.mattkeeter.com/projects/antimony/3/images/graph.png)\n\nEach node is defined by a customizable script. Antimony uses Python 3.x plus a few extra magic keywords.\n\nHere's what the circle node above looks like:\n\n```python\nimport fab.shapes\n\n# Define a set of input ports\n# (and inject variables into the local namespace)\ninput('x', float)\ninput('y', float)\ninput('r', float)\n\n# Call the 'circle' function in the standard shapes library\n# using the variables that came in from the input ports\nc = fab.shapes.circle(x, y, r)\n\n# Create an output port that produces the circle shape\noutput('shape', c)\n```\n\nNodes usually represent a primitive shape or transform. Links are tracked and changes are automatically propagated downstream.\n\n![Change propagation](https://www.mattkeeter.com/projects/antimony/3/images/tracking.gif)\n\nThe graph engine scales up to complex multi-part assembles.\n\n![Kelvin](https://www.mattkeeter.com/projects/antimony/3/images/big.png)\n\n![Kelvin](https://www.mattkeeter.com/projects/antimony/3/images/bigger.png)\n\n### Geometry engine\n\nAntimony's geometry engine uses [functional representations](http://en.wikipedia.org/wiki/Function_representation) for solid modeling. This representation is particularly suitable for modeling with boolean operations (union / intersection / difference).\n\n![Boolean example](https://www.mattkeeter.com/projects/antimony/3/images/csg.png)\n\nIn the application, the geometry engine renders shapes as shaded bitmaps. They're then blitted to a 3D viewport.\n\n![Application screenshot](https://www.mattkeeter.com/projects/antimony/3/images/app.png)\n\nAntimony can export heightmaps for 2.5D processes and `.stl` files for 3D manufacturing. The `.stl` export includes feature detection to keep corners and edges sharp.\n\n![Mesh](https://www.mattkeeter.com/projects/antimony/3/images/export.png)\n\n### Standard library\n\nAntimony's standard library defines many [shapes and transforms](https://github.com/mkeeter/antimony/blob/develop/py/fab/shapes.py), from basic (rotate, scale, boolean operations) to unusual (attract, repel, bend).\n\nThese shapes are used in node definitions, which typically add input and output ports and can optionally define UI features.\n\nHere's an example of a node that defines UI features:\n\n```python\nimport fab\n\ntitle('Rectangle')\n\ninput('xmin', float)\ninput('ymin', float)\ninput('xmax', float, 1)\ninput('ymax', float, 1)\n\noutput('shape', fab.shapes.rectangle(xmin, xmax, ymin, ymax))\n\n# UI\nsb.ui.wireframe([(xmin, ymin, 0), (xmax, ymin, 0),\n                 (xmax, ymax, 0), (xmin, ymax, 0)], close=True)\nsb.ui.point(xmin, ymin, 0)\nsb.ui.point(xmax, ymax, 0)\n```\n\nIn the 3D viewport, the UI features defined at the bottom of the script are drawn over the rendering of the rectangle.\n\nThese UI features are hooked back into the graph: dragging the points at the rectangle's corners pushes changes to the graph node.\n\n![UI dragging](https://www.mattkeeter.com/projects/antimony/3/images/dragging.gif)\n\n**As an aside**: most users will be satisfied with the built-in shapes, but it's also possible to define custom shapes.\n\nShapes are represented with a prefix string syntax that's easy to parse but a bit cryptic to decipher. Here's the definition for the circle shape used above:\n\n```python\ndef circle(x0, y0, r):\n    return Shape(\n            '-r+q-Xf%gq-Yf%gf%g' % (x0, y0, r), # math string\n            x0 - r, y0 - r, x0 + r, y0 + r)     # bounds\n```\n\nUnpacking and hierarchically indenting the prefix string gives\n\n```python\n-\n  r\n    +\n      q\n        -\n          X\n          f%g\n      q\n        -\n          Y\n          f%g\n  f%g\n% (x, y, r)\n```\n\nThis encodes a distance field representation of a 2D circle:\n\n```python\nf(x,y) = sqrt(pow(x - x0, 2) + pow(y - y0, 2)) - r\n```\n\nwhere `x0`, `y0`, and `r` are the circle's center and radius (specified when `circle` is called).\n\nThe exact mapping from prefix strings to infix functions is left as an exercise for the reader (or can be looked up in Appendix A of [my thesis](https://www.mattkeeter.com/research/thesis.pdf)).\n\n## download\n\nA prebuilt Mac application can be downloaded [from the Github releases page](https://github.com/mkeeter/antimony/releases).\n\nAntimony's source is [available on Github](https://github.com/mkeeter/antimony), along with instructions for [building it](https://github.com/mkeeter/antimony/blob/master/BUILDING.md) on Mac and Linux.\n\n## development\n\nAntimony is a long-running project under [active development](https://github.com/mkeeter/antimony/graphs/contributors).\n\n![Development](https://www.mattkeeter.com/projects/antimony/3/images/development.png)\n\nIt's at a beta level of stability: solid, but not recommended for mission-critical use.\n\nIf you're interested in contributing, there's a pretty low bar for entry. Given basic Python knowledge, you can get started making custom nodes (like this [HSB color node](https://github.com/mkeeter/antimony/blob/develop/py/nodes/Color/set_color_hsb.node) contributed by [RobotGrrl](https://twitter.com/RobotGrrl) or the [plethora of nodes](https://github.com/mkeeter/antimony/commits?author=neilger) contributed by [Neil](http://ng.cba.mit.edu/)).\n\nFor more ambitious folks with C++ experience, there are a whole host of improvements that could be made, from speeding up rendering to cleaning up the UI and optimizing graph evaluation. Send me a note if this piques your interest.\n\n## history\n\nAntimony grew out of my work on powerful personal-scale CAD/CAM workflows at the [MIT Center for Bits and Atoms](http://cba.mit.edu).\n\nIt's the latest tool in a line of software that included [cad\\_ui](https://www.mattkeeter.com/projects/solver) and [kokopelli](https://www.mattkeeter.com/projects/kokopelli), and draws inspiration from [fabserver](http://kokompe.cba.mit.edu).\n\nFor a historical perspective, there are a set of earlier Antimony writeups:\n\n- [Early 2014](https://www.mattkeeter.com/projects/antimony/1) (developed as a demo for the World Economic Forum)\n- [Fall 2014](https://www.mattkeeter.com/projects/antimony/2) (updated for use in How to Make Almost Anything)\n\nThis update coincides with the 2015 edition of [Fab Academy](http://fabacademy.org/); use [this search query](https://www.google.com/search?q=site%3Ahttp%3A%2F%2Ffabacademy.org%2Farchives%2F2015%2F%20antimony&rct=j) to see how people are using it.\n\n## press & discussion\n\n- [Hackaday write-up](http://hackaday.com/2015/05/29/otherworldy-cad-software-hails-from-a-parallel-universe/)\n- [Interview with Libre Graphics World](https://librearts.org/2015/05/introducing-antimony-node-based-cad-application/)\n- [Hacker News discussion](https://news.ycombinator.com/item?id=9623609)\n",
  "dateCreated": "2026-11-04T00:52:13.198927099+00:00",
  "date_created": "2026-11-02T08:29:40+00:00",
  "date_modified": "2026-11-02T08:29:40+00:00",
  "date_published": "2026-11-02T08:29:40+00:00",
  "description": "about Antimony is a computer-aided design (CAD) tool from a parallel universe in which CAD software evolved from Lisp machines rather than drafting tables. demo player.vimeo.com foundations Antimony is built on three mostly-orthogonal…",
  "external_url": "https://www.mattkeeter.com/projects/antimony/3/",
  "git": {
    "commit": "20068632b65d2830a2d54f25ca1d90d697bea2c0",
    "path": "items/hnrss-org/2026/11/2026-11-02-antimony-cad-software-evolved-from-lisp-machines-and-not.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/20068632b65d2830a2d54f25ca1d90d697bea2c0/items/hnrss-org/2026/11/2026-11-02-antimony-cad-software-evolved-from-lisp-machines-and-not.md"
  },
  "id": "urn:aggr:item:c3e40d391ecbcfd2f6f70087755a3d390cd17a62",
  "isBasedOn": {
    "@id": "https://www.mattkeeter.com/projects/antimony/3/"
  },
  "mainEntity": {
    "@id": "https://www.mattkeeter.com/projects/antimony/3/",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-11-02-antimony-cad-software-evolved-from-lisp-machines-and-not/#webpage"
    },
    "author": [
      {
        "@type": "Person",
        "name": "pmkary"
      }
    ],
    "dateModified": "2026-11-02T08:29:40+00:00",
    "datePublished": "2026-11-02T08:29:40+00:00",
    "headline": "Antimony: CAD Software Evolved from Lisp Machines and Not Drafting Tables (2015)",
    "image": {
      "@type": "ImageObject",
      "caption": "Graph example",
      "height": 90,
      "url": "https://www.mattkeeter.com/projects/antimony/3/images/graph.png",
      "width": 160
    },
    "timeRequired": "PT4M",
    "url": "https://www.mattkeeter.com/projects/antimony/3/",
    "wordCount": 805
  },
  "name": "Archived snapshot: Antimony: CAD Software Evolved from Lisp Machines and Not Drafting Tables (2015)",
  "preview": {
    "alt": "Graph example",
    "color": null,
    "height": 90,
    "placeholder": {
      "data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
      "hash": ""
    },
    "url": "https://www.mattkeeter.com/projects/antimony/3/images/graph.png",
    "width": 160
  },
  "reading_minutes": 4,
  "replicated_at": null,
  "source": "hnrss-org",
  "source_name": "Hacker News: Front Page",
  "summary": null,
  "tags": [],
  "temporalCoverage": "2026-11-04T00:52:13.198927099+00:00",
  "title": "Antimony: CAD Software Evolved from Lisp Machines and Not Drafting Tables (2015)",
  "url": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-11-02-antimony-cad-software-evolved-from-lisp-machines-and-not/",
  "word_count": 805
}