JewelWeight
A Rhino 8 plugin that calculates the metal weight of jewelry models, built for my own work at a jewelry workshop and now used by my colleagues there.
- Role
- Solo. Spec, product decisions and testing by me; code written with Claude Code
- Stack
- Python 3.9, RhinoCommon, Eto.Forms, unittest
- Platform
- Rhino 8, Windows
- Status
- v1.0.0, in daily use at the workshop
- Links
- GitHub Release v1.0.0
Problem
In jewelry, weight is cost. Clients set budgets in grams, and the price of an order follows the metal.
Before JewelWeight, the weight of a model was found in one of two ways:
- run Rhino's
Volumecommand and multiply by the alloy density on a calculator, again for every alloy; - or not estimate it at all and find out after casting, when the model can no longer be changed.
Solution
One window inside Rhino: Select objects → press an alloy → weight in grams.
- 8 standard alloys (585 and 750 red / yellow / white, 999, silver 925) plus custom alloys; every density is editable.
- Validation before every calculation: open or non-manifold geometry is blocked, the broken objects are highlighted in the viewport, and the message says how to fix them.
- Exported STL meshes that are printable but technically non-manifold are cleaned in memory and still calculated; the model itself is never changed.
- Any document units are converted to mm³; weight is rounded half-up to 0.01 g.
- The selection stays valid while the model changes: deleted objects and a switched document are detected on every click.
Proof: the 9-gram pair
- estimated
- 8.99 g
- limit
- 9.00 g
- alloy
- 585 yellow
- Order: a pair of rings in 585 yellow gold, no more than 9 g for both.
- JewelWeight: 2 objects, 666.71 mm³ → 8.99 g in 585 yellow.
- After casting: the weight matched the estimate. Finishing and polishing remove a little metal, so the finished pair came in slightly lighter, safely under 9 g.
- Why per-alloy buttons matter: the same pair in 585 white is 9.17 g, over the limit. The alloy alone changes the answer by 0.18 g.


Engineering highlights
- Printable STL rejected as non-manifold. Duplicate and collapsed triangles break
IsManifoldbut add no volume. Closed meshes are re-tested on a cleaned in-memory copy (weld vertices, cull degenerate and duplicate faces); if it passes, that volume is used and a note is shown. - Correct grams in any units. The unit scale is cubed to mm³; documents without reliable units are rejected; rounding uses
Decimalhalf-up, so 4.365 always becomes 4.37. Covered by unit tests. - A selection that survives edits. Object IDs and the document serial are stored; every alloy click re-inspects the objects, drops deleted ones with a notice and highlights failing ones.
- A custom dark UI from Python inside Rhino. Eto.Forms via pythonnet: custom-drawn buttons with hover and pressed states (native WPF buttons broke the theme), deferred clicks so viewport picking works, one window per Rhino session.
- Settings that survive updates and broken files. UTF-8 JSON in
%APPDATA%with schema versions and migrations, atomic writes, and a timestamped backup of damaged files. Only user overrides are stored, so improved defaults still reach unchanged alloys.
Rhino-free logic (calculation, storage, theme) lives in pure modules tested outside Rhino.
Numbers
- lines of Python, 21 files
- 2,543
- unit tests
- 65
- built-in alloys + unlimited custom
- 8
- third-party dependencies
- 0
- first commit to release v1.0.0 in one evening
- 5 commits
How I built it with AI
I wrote the spec and the prompts and split the work into three phases: core calculation, settings and UI, installer. I made the product calls: weight only, no price, because the gold price changes daily and is quoted to the client later; Rhino 8 only; Russian UI, because the users are the workshop. I tested every phase in Rhino on real models, including the STL that failed validation, which led to the mesh-cleanup fix. Claude Code wrote the code and the unit tests from the spec.
What's next
- A
.yakpackage for food4Rhino - SubD support via conversion to Brep
- Automatic toolbar setup (
.rui)
Links
github.com/Khanapin-T/rhino-jewelweight
Learnt. Built. Shipped.