One evening. 4 parametric systems. One button that writes real BIM elements back into the file. And 4 bugs that lie to you politely.
The gap I wanted to close is small and very annoying.
You have a facade screen in the model. You want to study 20 versions of it. So you either rebuild the curtain wall by hand 20 times, or you take it out to Rhino, get clever, and then face the part nobody enjoys, which is getting it back into the model that actually issues the drawings.
I have written about that round trip before. This time I wanted to skip it entirely. Not export. Not import. Just have the design tool and the BIM model open at the same time, talking.
That is what this is. And the honest version of how it went is more useful than the demo, so the bugs are in here at full length.
ArchiCAD has run a JSON API on localhost for years. Most architects have never touched it, because on its own it is a fairly bare set of commands. The Tapir add-on is what makes it usable: it adds a few hundred well-shaped commands on top, and it is free.
Once that is installed, Claude Code can talk to your open model over plain HTTP. Not to a file. To the running application, while you are in it.
The first thing I ran was the equivalent of "who is there".
Port 19724 · AC29_Villa-Patio_GRAPHISOFT-Sample.pla · ArchiCAD 29 · Tapir 1.5.8
Then I selected a curtain wall in ArchiCAD and asked what was selected. It came back as facade 1, a curtain wall on Level 1, 4.55m tall, made of 383 frames and 126 panels. I had not typed a single coordinate.
That is the whole trick. Everything after this is just deciding what to do with a live connection.
The design decision that mattered most had nothing to do with geometry.
I did not want a tool that could touch anything. I wanted the entire building present, visible, and completely inert, with exactly one element live. You should not be able to nudge a slab while you are studying a facade.
So the whole project goes out as IFC, gets converted into a light 3D model the browser can hold, and every mesh in it has its raycasting switched off. It is scenery. It cannot be clicked, hovered or moved.
One element stays editable: the screen.
Here is a thing I think matters, and it is the step most demos skip.
I did not guess what the existing facade was. I read it off the live model through the API, frame by frame:
The tool then opens on those exact numbers. Which means every change you make is a deliberate departure from what is actually built, not a fresh invention that happens to look similar.
There is a test hiding in that. If the tool cannot reproduce what already exists, it has no business proposing what does not. So I rebuilt the existing facade through the tool and compared every batten against the real one.
0.0002mm. Which is to say, floating point noise.
That check took 10 minutes and bought me the confidence to trust everything after it.
The first version only did vertical battens with a rotation angle. That is a fine afternoon, and it is also boring. Real facade studies are about comparing genuinely different systems, not sliding one number.
So it became 4, all built on the same grid engine:
What makes them one engine rather than 4 tools is the idea of a field. A field is just a function over the face of the facade that returns a number between minus 1 and 1. Sweep across. Wave up. Diagonal. Ripple from the centre. Bulge. Alternate. Seeded noise.
Each system feeds 2 of those fields into different properties. In the batten system, one drives rotation and one drives depth. In the relief system, both drive depth and get blended. In the tile system, they drive the pivot angle.
Adding a 5th system is now about 150 lines: define the cell size, define what the 2 fields control, done.
The first working version had a warning that said "this now runs 40mm past the opening". Which is useless, because I ignored it.
So containment became a constraint the solver physically cannot break, rather than a message.
The interesting part is that it is not as simple as it sounds. A batten rotated 60 degrees presents a much wider face than a batten sitting square, so the run gets wider as you rotate it. The solver has to allow for the rotated footprint of the end elements before it decides how many fit.
How it resolves
Then there is depth, which turned out to be the more architectural problem.
My first relief version was flush at the outer face and grew inward, which meant a 620mm deep block was reaching into the slab behind. Wrong direction. A relief screen should stand proud, not eat the building.
So the blocks now share a common back plane and protrude outward by different amounts, and there is a set out from plane control that pushes the whole assembly further out. The readout tells you how far the design stands out and how far it cuts in, and the second number goes red if it would reach the slab.
The number I use most is clear gap: the smallest distance between neighbouring elements. It goes negative when they physically collide, which a rotation study will absolutely do to you if nothing is checking. One of my own presets was quietly overlapping by 7mm until the readout said so.
This is the part that makes it worth doing at all.
One button. The design lands in ArchiCAD as columns and beams, with a building material, grouped into a single group, on their own layer. Not a mesh. Not an imported block. Schedulable elements you can tag, count and cost.
A 680 tile screen with its steel lattice comes in as 737 elements in about 5 seconds.
The safety model is deliberately boring, because the whole thing is pointed at somebody's real project file:
This is the section I would actually read if somebody else wrote this. Every one of these looked like success at the time.
The interior views were all a flat white wall. I assumed there was a wall behind the screen. There was not.
ArchiCAD library objects export to IFC as proxies with an empty name field. The thing that actually says "Houseplant Model" lives on the IFC type the object points at, through a separate relationship. My furniture filter was reading the name, found nothing, and kept everything.
So 188 potted plants were sitting in a row directly behind the facade, blocking every view from inside. They were also, it turned out, 70% of the model's geometry. Resolving type names and re-filtering took the context file from 10 MB and 596,000 triangles down to 0.9 MB and 65,000.
I had excluded the curtain wall from the frozen context by following its IFC decomposition tree, which gave me 125 children. Job done, apparently.
Except the curtain wall's rails, panels and end posts are not aggregated under that container. They come out as loose proxies. So 8% of the context was the old facade, sitting exactly where the new one gets built, in a file whose entire premise is that the old one is not there.
Nothing errored. It just looked slightly wrong in a way I could not name for a while.
This is the worst one, and it is not my bug.
ArchiCAD refuses to modify or delete an element that sits on a hidden layer, and the delete command returns success anyway. No error. No warning. It reports that it deleted 737 elements, and deletes none of them.
The consequence is nasty in a specific way: the next build then writes a second copy on top of the first. I found it because the element count came back as 1,440 columns when it should have been 720, exactly double.
The fix is to un-hide the working layer before every write, delete in batches, and then verify the layer is empty rather than trusting the response. Which is a good general rule: with this API, read the state back rather than believing the reply.
Halfway through, ArchiCAD went pale. All the linework faded to almost nothing and the model looked broken.
That was me. I had used the HighlightElements command to make the new elements glow, and passed a nonHighlightedColor that dims everything else to 12% opacity. It does exactly what it says. It also looks identical to a corrupted display setting.
Worse, my cleanup call to clear the highlight had been failing silently, because the schema requires the highlightedColors array even when you are clearing and passing an empty element list. So the obvious call fails validation and the model stays dimmed.
I removed the highlight entirely. A model that looks broken is not worth a green glow.
The pattern in all 4: the API told me it succeeded. Only reading the model back told me the truth.
Named plainly, because a tool post without this is marketing.
It is bound to one element in one project. The element ID and the anchor point are constants in the code. Pointing it at a different facade is real work, not a setting. Generalising it is the obvious next job and I have not done it.
The woven ribbon system is an approximation. The reference I was working from has plates that genuinely twist along their length. Mine are flat plates at alternating angles. It reads correctly at facade scale and it round-trips as ordinary schedulable elements, which the twisted version would not. It is still a compromise.
It is a geometry and quantity study, not a facade. There is no structure, no fixing, no thermal movement, no tolerance, no fire, no maintenance access. It will tell you the openness percentage and the linear metres of timber. It will not tell you whether the thing stands up.
The API is where the time goes. The parametric part was the easy afternoon. The connection, the safety model, and the 4 bugs above were the rest of it.
The facade is not the point. I picked a facade because it was in the sample file.
The point is that the shape of the work changed. I did not write this tool. I described what I wanted, it got built, I corrected it where it was wrong, and I read the model back every time to check whether the answer was true.
That last habit is the whole skill. Not prompting. Verifying.
All of this is territory that has belonged to Grasshopper for 15 years, and most architects never went there, because the entry price was learning a visual programming language well enough to think in it and then keeping that skill warm between the projects that need it.
No Grasshopper was opened. What was needed was knowing what the facade should do, and being stubborn about checking whether it had actually done it.
If your practice wants this pointed at your own models, message me on LinkedIn and tell me what you would put behind the slider.