pip-hinge 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ name: Publish to PyPI
2
+
3
+ # Build on every GitHub Release, and publish to PyPI via OIDC Trusted
4
+ # Publishing (no API token stored anywhere). workflow_dispatch lets the very
5
+ # first publish run be triggered by hand once the PyPI pending publisher is set.
6
+ on:
7
+ release:
8
+ types: [published]
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ build:
13
+ name: Build sdist + wheel
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v5
18
+ - name: Build
19
+ run: uv build
20
+ - uses: actions/upload-artifact@v4
21
+ with:
22
+ name: dist
23
+ path: dist/
24
+
25
+ publish:
26
+ name: Publish to PyPI
27
+ needs: build
28
+ runs-on: ubuntu-latest
29
+ # Must match the environment name registered on the PyPI trusted publisher.
30
+ environment: pypi
31
+ permissions:
32
+ id-token: write # OIDC token for Trusted Publishing
33
+ steps:
34
+ - uses: actions/download-artifact@v4
35
+ with:
36
+ name: dist
37
+ path: dist/
38
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .python-version
5
+ *.egg-info/
6
+ uv.lock
@@ -0,0 +1,35 @@
1
+ Creative Commons Attribution 4.0 International (CC BY 4.0)
2
+
3
+ This work is a derivative of "Parametric print-in-place hinge. FreeCAD." by
4
+ r0berts, published at:
5
+
6
+ https://www.printables.com/model/1395662-parametric-print-in-place-hinge-freecad
7
+
8
+ The original is licensed under CC BY 4.0. This derivative — a build123d Python
9
+ port with full reparameterisation of the sketch geometry — is released under the
10
+ same CC BY 4.0 license.
11
+
12
+ Copyright:
13
+ Original design © r0berts (Printables: @r0berts_1183620)
14
+ build123d port and parameterisation © 2026 Paul Fremantle (pzfreo)
15
+
16
+ You are free to:
17
+ Share — copy and redistribute the material in any medium or format
18
+ Adapt — remix, transform, and build upon the material for any purpose,
19
+ even commercially
20
+
21
+ Under the following terms:
22
+ Attribution — You must give appropriate credit, provide a link to the
23
+ license, and indicate if changes were made. You may do so in any
24
+ reasonable manner, but not in any way that suggests the licensor
25
+ endorses you or your use.
26
+
27
+ No additional restrictions — You may not apply legal terms or
28
+ technological measures that legally restrict others from doing anything
29
+ the license permits.
30
+
31
+ Full legal text:
32
+ https://creativecommons.org/licenses/by/4.0/legalcode
33
+
34
+ Summary:
35
+ https://creativecommons.org/licenses/by/4.0/
@@ -0,0 +1,224 @@
1
+ Metadata-Version: 2.4
2
+ Name: pip-hinge
3
+ Version: 0.1.0
4
+ Summary: Parametric print-in-place piano hinge for clamshell cases, in build123d
5
+ Project-URL: Homepage, https://github.com/pzfreo/pip-hinge
6
+ Project-URL: Issues, https://github.com/pzfreo/pip-hinge/issues
7
+ Author-email: Paul Fremantle <pzfreo@gmail.com>
8
+ License: Creative Commons Attribution 4.0 International (CC BY 4.0)
9
+
10
+ This work is a derivative of "Parametric print-in-place hinge. FreeCAD." by
11
+ r0berts, published at:
12
+
13
+ https://www.printables.com/model/1395662-parametric-print-in-place-hinge-freecad
14
+
15
+ The original is licensed under CC BY 4.0. This derivative — a build123d Python
16
+ port with full reparameterisation of the sketch geometry — is released under the
17
+ same CC BY 4.0 license.
18
+
19
+ Copyright:
20
+ Original design © r0berts (Printables: @r0berts_1183620)
21
+ build123d port and parameterisation © 2026 Paul Fremantle (pzfreo)
22
+
23
+ You are free to:
24
+ Share — copy and redistribute the material in any medium or format
25
+ Adapt — remix, transform, and build upon the material for any purpose,
26
+ even commercially
27
+
28
+ Under the following terms:
29
+ Attribution — You must give appropriate credit, provide a link to the
30
+ license, and indicate if changes were made. You may do so in any
31
+ reasonable manner, but not in any way that suggests the licensor
32
+ endorses you or your use.
33
+
34
+ No additional restrictions — You may not apply legal terms or
35
+ technological measures that legally restrict others from doing anything
36
+ the license permits.
37
+
38
+ Full legal text:
39
+ https://creativecommons.org/licenses/by/4.0/legalcode
40
+
41
+ Summary:
42
+ https://creativecommons.org/licenses/by/4.0/
43
+ License-File: LICENSE
44
+ Requires-Python: <3.14,>=3.10
45
+ Requires-Dist: build123d>=0.6
46
+ Provides-Extra: test
47
+ Requires-Dist: pytest>=7; extra == 'test'
48
+ Description-Content-Type: text/markdown
49
+
50
+ # pip-hinge
51
+
52
+ A parametric print-in-place piano hinge in [build123d](https://github.com/gumyr/build123d),
53
+ designed for clamshell cases.
54
+
55
+ Four inputs:
56
+
57
+ ```python
58
+ from pip_hinge import HingeParams, Knuckle, make_hinge
59
+
60
+ hinge = make_hinge(HingeParams(
61
+ case_h = 10, # case wall height (mm)
62
+ hinge_length = 60, # total hinge length along the axis (mm)
63
+ stations = 6, # alternating cs/ps tab count (even, ≥ 2)
64
+ knuckle = Knuckle.FULL, # FULL = "bump on top", no ramp needed
65
+ ))
66
+ ```
67
+
68
+ `make_hinge()` returns a 2-body `Compound`: the cylinder-side leaf (with
69
+ bored knuckle tabs) and the pin-side leaf (with the integral pin).
70
+
71
+ ## In context: a flat-open clamshell with HALF knuckle
72
+
73
+ ![clamshell with HALF knuckle and corner magnet pockets, flat-open print orientation](docs/diagrams/clamshell_half_preview.png)
74
+
75
+ Built by [`examples/clamshell.py`](examples/clamshell.py) — case_h = 10mm,
76
+ 80 × 50 mm footprint, 60 mm hinge with `Knuckle.HALF`, plus four 6 × 3 mm
77
+ corner magnet pockets to latch the case shut. Both halves print as one
78
+ piece in the orientation shown. The example also emits a bare HALF/FULL
79
+ variant (no magnets) for reference.
80
+
81
+ ## Parameter reference
82
+
83
+ ![parameters guide](docs/diagrams/parameters_guide.png)
84
+
85
+ Cross-section (Panel A) shows the spatial parameters: `case_h` (wall
86
+ height), `PIVOT_Z_OFFSET` (extra lift), `mounting_flat` (flat past the
87
+ disc edge), plus the derived `Po`/`Ro`/`T`/`W` and the pin/bore inset.
88
+ Top view (Panel B) shows `hinge_length`, `stations`, derived
89
+ `clasp_width`, and `clasp_clearance` between meshing tabs.
90
+
91
+ ## The two knuckle options
92
+
93
+ ![knuckle options](docs/diagrams/knuckle_options.png)
94
+
95
+ | `knuckle` | knuckle diameter | ramp | gap between case walls (flat-open) |
96
+ | -------------- | --------------------------- | --------------------- | ---------------------------------- |
97
+ | `Knuckle.FULL` | `2 × case_h` | none — rests on bed | `2 × (case_h + mounting_flat)` |
98
+ | `Knuckle.HALF` | `case_h` | 45° self-supporting teardrop | `case_h + 2 × mounting_flat` |
99
+ | `Knuckle.SMALL`| `max(case_h / 2, 5 mm)` | ~25° from vertical (smaller knuckle → naturally steeper) | `max(case_h, 10mm) + 2 × mounting_flat` |
100
+
101
+ See [docs/clamshell-integration.md](docs/clamshell-integration.md) for
102
+ mounting, orientation, multi-hinge layouts, and the closed-vs-open view.
103
+
104
+ ## Provenance
105
+
106
+ This is a port of **["Parametric print-in-place hinge. FreeCAD."](https://www.printables.com/model/1395662-parametric-print-in-place-hinge-freecad)**
107
+ by **[r0berts](https://www.printables.com/@r0berts_1183620)** on Printables,
108
+ licensed [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
109
+
110
+ The original is a spreadsheet-driven FreeCAD model. This repository:
111
+
112
+ 1. Translates the FreeCAD geometry into build123d Python via
113
+ [fcd2b123d](https://github.com/pzfreo/fcd2b123d).
114
+ 2. Reparameterises around four case-designer-facing inputs (`case_h`,
115
+ `hinge_length`, `stations`, `knuckle`) with the original dimensional
116
+ relationships derived under the hood.
117
+ 3. Generalises the comb pattern (hardcoded 6 stations in the original) to
118
+ any even number of stations ≥ 2, and adds an optional
119
+ `Knuckle.HALF` mode with a self-supporting teardrop knuckle for cases
120
+ where a smaller knuckle is wanted.
121
+
122
+ Per the CC BY 4.0 terms: design and dimensional relationships are
123
+ r0berts'; modifications are the build123d port, the four-input API, and
124
+ the configurable station count and ramp.
125
+
126
+ ## Quick start
127
+
128
+ Install from this repo into your own project (until it's on PyPI):
129
+
130
+ ```bash
131
+ uv pip install git+https://github.com/pzfreo/pip-hinge.git
132
+ ```
133
+
134
+ Then in your build123d code:
135
+
136
+ ```python
137
+ from pip_hinge import HingeParams, Knuckle, make_hinge
138
+
139
+ hinge = make_hinge(HingeParams(
140
+ case_h=10, hinge_length=60, knuckle=Knuckle.FULL,
141
+ ))
142
+ cylinder_side, pin_side = hinge.solids() # or use _split_hinge_by_side helper
143
+ ```
144
+
145
+ Or to play with it locally:
146
+
147
+ ```bash
148
+ git clone https://github.com/pzfreo/pip-hinge.git && cd pip-hinge
149
+ uv pip install -e . # editable install
150
+ python examples/clamshell.py # writes clamshell_{full,half,small,magnets}.{step,stl}
151
+ python examples/hinge_only.py # writes the bare hinge_{full,half}.{step,stl}
152
+ ```
153
+
154
+ ## Parameters
155
+
156
+ The four primary inputs:
157
+
158
+ | Parameter | Default | Meaning |
159
+ | -------------- | -------------- | -------------------------------------------------------- |
160
+ | `case_h` | (required) | Case wall height; the hinge's "scale" reference |
161
+ | `hinge_length` | (required) | Total hinge length along the axis (Y) |
162
+ | `stations` | 6 | Number of alternating cs/ps tabs (even, ≥ 2) |
163
+ | `knuckle` | `Knuckle.FULL` | `FULL`, `HALF`, or `SMALL` — see the option table below |
164
+
165
+ Three small tuneables:
166
+
167
+ | Parameter | Default | Meaning |
168
+ | ----------------- | ------- | -------------------------------------------------- |
169
+ | `mounting_flat` | 0.5 | Flat width past the disc edge for case-wall fusion. Below `pivot_clearance` (= 0.6 mm) the bare hinge fragments into multiple solids — fine when fused into a case, see docs |
170
+ | `pivot_clearance` | 0.6 | Radial pin/bore gap (FDM tolerance) |
171
+ | `clasp_clearance` | `None` | Axial gap between cs and ps tabs. `None` auto-scales with knuckle diameter `Po`: 0.2 mm at Po ≤ 5 mm (matches r0berts' original), linear up to 0.4 mm at Po ≥ 10 mm. Pass an explicit value to override |
172
+
173
+ Plus three pin-engagement constants from the original FreeCAD source
174
+ (`pin_cyl_extra`, `pin_end_offset`, `pin_short_cyl_factor`) — leave at
175
+ defaults unless deliberately tuning the pin/bore feel.
176
+
177
+ ## Validation
178
+
179
+ `make_hinge()` raises `ValueError` for hard geometric problems:
180
+ - non-positive `case_h`, `hinge_length`, or `mounting_flat`
181
+ - `stations < 2` or odd
182
+ - bore Ø ≤ `pivot_clearance` (knuckle too small for the pivot clearance)
183
+
184
+ And warns (`warnings.warn`) when:
185
+ - `clasp_width = hinge_length / stations` drops below ~3 mm (too thin for FDM)
186
+
187
+ ## Printing
188
+
189
+ Lay flat on the bed with the hinge axis along Y (parallel to bed).
190
+ 0.2 mm layers, fan on, brim recommended. After printing, gently flex the
191
+ leaves to break the clearance gaps free.
192
+
193
+ - **FULL** prints without any supports at any knuckle size — the knuckle
194
+ rests on the bed.
195
+ - **HALF** prints without supports at any `case_h`: the meshing-side underside
196
+ meets the knuckle tangentially at 45° and runs to the bed as a self-supporting
197
+ teardrop, so the disc's downward arc is never left hanging.
198
+
199
+ ## How this was built
200
+
201
+ The build123d code, API design discussions, station-count generalisation,
202
+ self-supporting ramp, clamshell example, and documentation in this
203
+ repository were produced through a paired design session with
204
+ [Claude Code](https://claude.com/claude-code) (Anthropic's Claude Opus 4.7).
205
+ I drove the design decisions — what the API should look like, which
206
+ knuckle geometries to support, what trade-offs to accept — and Claude wrote
207
+ the code, generated the diagrams, ran the verifications, and opened the
208
+ PRs. The conversation is the source of truth for *why* the code looks the
209
+ way it does; the commit history reflects the steps.
210
+
211
+ The original FreeCAD geometry from r0berts is unchanged in its dimensional
212
+ relationships — it was reparameterised, not redesigned. The Claude
213
+ collaboration is on the build123d port and the case-designer-facing API
214
+ built on top of it.
215
+
216
+ ## License
217
+
218
+ This work is licensed under [Creative Commons Attribution 4.0 International (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/),
219
+ matching the upstream Printables source. See [LICENSE](LICENSE).
220
+
221
+ When using or redistributing, please credit:
222
+
223
+ - **r0berts** — original FreeCAD design ([Printables](https://www.printables.com/model/1395662-parametric-print-in-place-hinge-freecad))
224
+ - **Paul Fremantle** (pzfreo) — build123d port, four-input parameterisation, station generalisation, and ramp option
@@ -0,0 +1,175 @@
1
+ # pip-hinge
2
+
3
+ A parametric print-in-place piano hinge in [build123d](https://github.com/gumyr/build123d),
4
+ designed for clamshell cases.
5
+
6
+ Four inputs:
7
+
8
+ ```python
9
+ from pip_hinge import HingeParams, Knuckle, make_hinge
10
+
11
+ hinge = make_hinge(HingeParams(
12
+ case_h = 10, # case wall height (mm)
13
+ hinge_length = 60, # total hinge length along the axis (mm)
14
+ stations = 6, # alternating cs/ps tab count (even, ≥ 2)
15
+ knuckle = Knuckle.FULL, # FULL = "bump on top", no ramp needed
16
+ ))
17
+ ```
18
+
19
+ `make_hinge()` returns a 2-body `Compound`: the cylinder-side leaf (with
20
+ bored knuckle tabs) and the pin-side leaf (with the integral pin).
21
+
22
+ ## In context: a flat-open clamshell with HALF knuckle
23
+
24
+ ![clamshell with HALF knuckle and corner magnet pockets, flat-open print orientation](docs/diagrams/clamshell_half_preview.png)
25
+
26
+ Built by [`examples/clamshell.py`](examples/clamshell.py) — case_h = 10mm,
27
+ 80 × 50 mm footprint, 60 mm hinge with `Knuckle.HALF`, plus four 6 × 3 mm
28
+ corner magnet pockets to latch the case shut. Both halves print as one
29
+ piece in the orientation shown. The example also emits a bare HALF/FULL
30
+ variant (no magnets) for reference.
31
+
32
+ ## Parameter reference
33
+
34
+ ![parameters guide](docs/diagrams/parameters_guide.png)
35
+
36
+ Cross-section (Panel A) shows the spatial parameters: `case_h` (wall
37
+ height), `PIVOT_Z_OFFSET` (extra lift), `mounting_flat` (flat past the
38
+ disc edge), plus the derived `Po`/`Ro`/`T`/`W` and the pin/bore inset.
39
+ Top view (Panel B) shows `hinge_length`, `stations`, derived
40
+ `clasp_width`, and `clasp_clearance` between meshing tabs.
41
+
42
+ ## The two knuckle options
43
+
44
+ ![knuckle options](docs/diagrams/knuckle_options.png)
45
+
46
+ | `knuckle` | knuckle diameter | ramp | gap between case walls (flat-open) |
47
+ | -------------- | --------------------------- | --------------------- | ---------------------------------- |
48
+ | `Knuckle.FULL` | `2 × case_h` | none — rests on bed | `2 × (case_h + mounting_flat)` |
49
+ | `Knuckle.HALF` | `case_h` | 45° self-supporting teardrop | `case_h + 2 × mounting_flat` |
50
+ | `Knuckle.SMALL`| `max(case_h / 2, 5 mm)` | ~25° from vertical (smaller knuckle → naturally steeper) | `max(case_h, 10mm) + 2 × mounting_flat` |
51
+
52
+ See [docs/clamshell-integration.md](docs/clamshell-integration.md) for
53
+ mounting, orientation, multi-hinge layouts, and the closed-vs-open view.
54
+
55
+ ## Provenance
56
+
57
+ This is a port of **["Parametric print-in-place hinge. FreeCAD."](https://www.printables.com/model/1395662-parametric-print-in-place-hinge-freecad)**
58
+ by **[r0berts](https://www.printables.com/@r0berts_1183620)** on Printables,
59
+ licensed [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
60
+
61
+ The original is a spreadsheet-driven FreeCAD model. This repository:
62
+
63
+ 1. Translates the FreeCAD geometry into build123d Python via
64
+ [fcd2b123d](https://github.com/pzfreo/fcd2b123d).
65
+ 2. Reparameterises around four case-designer-facing inputs (`case_h`,
66
+ `hinge_length`, `stations`, `knuckle`) with the original dimensional
67
+ relationships derived under the hood.
68
+ 3. Generalises the comb pattern (hardcoded 6 stations in the original) to
69
+ any even number of stations ≥ 2, and adds an optional
70
+ `Knuckle.HALF` mode with a self-supporting teardrop knuckle for cases
71
+ where a smaller knuckle is wanted.
72
+
73
+ Per the CC BY 4.0 terms: design and dimensional relationships are
74
+ r0berts'; modifications are the build123d port, the four-input API, and
75
+ the configurable station count and ramp.
76
+
77
+ ## Quick start
78
+
79
+ Install from this repo into your own project (until it's on PyPI):
80
+
81
+ ```bash
82
+ uv pip install git+https://github.com/pzfreo/pip-hinge.git
83
+ ```
84
+
85
+ Then in your build123d code:
86
+
87
+ ```python
88
+ from pip_hinge import HingeParams, Knuckle, make_hinge
89
+
90
+ hinge = make_hinge(HingeParams(
91
+ case_h=10, hinge_length=60, knuckle=Knuckle.FULL,
92
+ ))
93
+ cylinder_side, pin_side = hinge.solids() # or use _split_hinge_by_side helper
94
+ ```
95
+
96
+ Or to play with it locally:
97
+
98
+ ```bash
99
+ git clone https://github.com/pzfreo/pip-hinge.git && cd pip-hinge
100
+ uv pip install -e . # editable install
101
+ python examples/clamshell.py # writes clamshell_{full,half,small,magnets}.{step,stl}
102
+ python examples/hinge_only.py # writes the bare hinge_{full,half}.{step,stl}
103
+ ```
104
+
105
+ ## Parameters
106
+
107
+ The four primary inputs:
108
+
109
+ | Parameter | Default | Meaning |
110
+ | -------------- | -------------- | -------------------------------------------------------- |
111
+ | `case_h` | (required) | Case wall height; the hinge's "scale" reference |
112
+ | `hinge_length` | (required) | Total hinge length along the axis (Y) |
113
+ | `stations` | 6 | Number of alternating cs/ps tabs (even, ≥ 2) |
114
+ | `knuckle` | `Knuckle.FULL` | `FULL`, `HALF`, or `SMALL` — see the option table below |
115
+
116
+ Three small tuneables:
117
+
118
+ | Parameter | Default | Meaning |
119
+ | ----------------- | ------- | -------------------------------------------------- |
120
+ | `mounting_flat` | 0.5 | Flat width past the disc edge for case-wall fusion. Below `pivot_clearance` (= 0.6 mm) the bare hinge fragments into multiple solids — fine when fused into a case, see docs |
121
+ | `pivot_clearance` | 0.6 | Radial pin/bore gap (FDM tolerance) |
122
+ | `clasp_clearance` | `None` | Axial gap between cs and ps tabs. `None` auto-scales with knuckle diameter `Po`: 0.2 mm at Po ≤ 5 mm (matches r0berts' original), linear up to 0.4 mm at Po ≥ 10 mm. Pass an explicit value to override |
123
+
124
+ Plus three pin-engagement constants from the original FreeCAD source
125
+ (`pin_cyl_extra`, `pin_end_offset`, `pin_short_cyl_factor`) — leave at
126
+ defaults unless deliberately tuning the pin/bore feel.
127
+
128
+ ## Validation
129
+
130
+ `make_hinge()` raises `ValueError` for hard geometric problems:
131
+ - non-positive `case_h`, `hinge_length`, or `mounting_flat`
132
+ - `stations < 2` or odd
133
+ - bore Ø ≤ `pivot_clearance` (knuckle too small for the pivot clearance)
134
+
135
+ And warns (`warnings.warn`) when:
136
+ - `clasp_width = hinge_length / stations` drops below ~3 mm (too thin for FDM)
137
+
138
+ ## Printing
139
+
140
+ Lay flat on the bed with the hinge axis along Y (parallel to bed).
141
+ 0.2 mm layers, fan on, brim recommended. After printing, gently flex the
142
+ leaves to break the clearance gaps free.
143
+
144
+ - **FULL** prints without any supports at any knuckle size — the knuckle
145
+ rests on the bed.
146
+ - **HALF** prints without supports at any `case_h`: the meshing-side underside
147
+ meets the knuckle tangentially at 45° and runs to the bed as a self-supporting
148
+ teardrop, so the disc's downward arc is never left hanging.
149
+
150
+ ## How this was built
151
+
152
+ The build123d code, API design discussions, station-count generalisation,
153
+ self-supporting ramp, clamshell example, and documentation in this
154
+ repository were produced through a paired design session with
155
+ [Claude Code](https://claude.com/claude-code) (Anthropic's Claude Opus 4.7).
156
+ I drove the design decisions — what the API should look like, which
157
+ knuckle geometries to support, what trade-offs to accept — and Claude wrote
158
+ the code, generated the diagrams, ran the verifications, and opened the
159
+ PRs. The conversation is the source of truth for *why* the code looks the
160
+ way it does; the commit history reflects the steps.
161
+
162
+ The original FreeCAD geometry from r0berts is unchanged in its dimensional
163
+ relationships — it was reparameterised, not redesigned. The Claude
164
+ collaboration is on the build123d port and the case-designer-facing API
165
+ built on top of it.
166
+
167
+ ## License
168
+
169
+ This work is licensed under [Creative Commons Attribution 4.0 International (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/),
170
+ matching the upstream Printables source. See [LICENSE](LICENSE).
171
+
172
+ When using or redistributing, please credit:
173
+
174
+ - **r0berts** — original FreeCAD design ([Printables](https://www.printables.com/model/1395662-parametric-print-in-place-hinge-freecad))
175
+ - **Paul Fremantle** (pzfreo) — build123d port, four-input parameterisation, station generalisation, and ramp option