A lens cap is a standard part, so I built a generator for it
11 October 2026
Lost lens caps are a running joke on r/functionalprint. Four threads there about printed replacement caps had 2248, 1635, 894 and 359 upvotes. That surprised me, because a lens cap is about as standard as a part gets: one number on the lens sizes it. The Lens Cap Generator is the result: you type one number and get a cap.
The number on the lens
Look at the front of a lens and you will find something like ⌀52. That is the filter thread, an M52 internal thread, and its pitch follows filter practice: 0.5 mm up to 30.5 mm, 1 mm from 86 mm, and 0.75 mm for everything in between, which covers most lenses people own. So the 52 really means M52 × 0.75, and the same number is printed inside the old cap and on every filter that fits.
From there it is ISO arithmetic. The crests of an internal thread sit at D1 = D − 1.0825 × P, so a 52 mm lens has its crests at 51.19 mm. The push-in cap has a short skirt that sits 0.15 mm inside those crests, and a 45° ridge around it that reaches 0.3 mm past them. Pushed in, the ridge snaps over the first crest and the cap holds.
The ridge must stop before it hits the bottom of the thread groove. With a 0.75 mm pitch the groove is 0.41 mm deep, so the generator caps the grip at 0.39 mm. Ask for 0.6 and it says exactly that, with the number, instead of handing you a cap that will not go in.
Three ways to hold
Push-in is the default and the one I trust most. It grips the thread, so it also works on top of a screwed-in filter, which has the same thread on its front.
Slip-over is for lenses without a filter thread, or for capping a hood. You measure the barrel with a caliper and the cap becomes a cup with small ribs inside.
Screw-in cuts a real M × P thread into the skirt. I labelled it experimental on the page and I mean it. A 0.75 mm pitch is close to what a 0.4 mm nozzle can draw, so it wants 0.12 mm layers and a clean first layer.
Around the cap there are a few extras: up to 24 characters of text or an SVG logo inlaid flush in a second color, a leash eyelet, a strap holder that parks up to three caps, and a fit-test ring. The ring is the skirt and a thin band of front plate. It prints in minutes and tells you whether to move the grip up or down by 0.1 mm before you spend filament on a whole cap.
What went wrong on the way
The slip-over cup looked fine in every check I had. Then the repo's fuzz test loaded the exported STL back, the way a slicer does, and the mesh fell apart. I had cut the grip ribs as small circles out of the big cavity circle, and some of the intersection points landed a fraction of a micron from the circle's own vertices. Manifold kept them apart. An STL loader merged them, and the cup tore. Now the cavity is one outline with the ribs as bumps on it, all on the same angular stations, and every test checks the mesh after a round trip through STL, not just as built.
The strap holder had its own problem. Each request left the server process bigger than before: 257, then 353, then 439 MB. The bolt generator was killed for exactly this in September, so I knew the cause. Glibc raises its mmap threshold after big blocks are freed, the next build's arrays land on the heap, and freed heap pages stay mapped. A fixed 1 MB threshold and a trim after each build keep it flat now.
The screw-in holder was simply too dense. Three threaded sockets came to 300,000 triangles and the container sat at 430 of its 500 MB. Half-millimetre chords and six rings per pitch still draw a thread finer than the nozzle can print, at a fraction of that.
I have not printed every size. The fit-test ring is there because printers differ by a tenth or two, and if your 0.3 mm grip turns out loose or tight on a lens you own, the report button on the page sends me the exact settings.