gridfinity-rebase 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.
Files changed (75) hide show
  1. gridfinity_rebase-0.1.0/LICENSE +23 -0
  2. gridfinity_rebase-0.1.0/PKG-INFO +172 -0
  3. gridfinity_rebase-0.1.0/README.md +161 -0
  4. gridfinity_rebase-0.1.0/docs/benchmark.json +186 -0
  5. gridfinity_rebase-0.1.0/docs/images/README.md +47 -0
  6. gridfinity_rebase-0.1.0/docs/images/base-magnet-holes-2x3.png +0 -0
  7. gridfinity_rebase-0.1.0/docs/images/base-plain-2x3.png +0 -0
  8. gridfinity_rebase-0.1.0/docs/images/base-press-fit-2x3.png +0 -0
  9. gridfinity_rebase-0.1.0/docs/images/base-press-fit-screws-2x3.png +0 -0
  10. gridfinity_rebase-0.1.0/docs/images/base-rebuilt-2x3.png +0 -0
  11. gridfinity_rebase-0.1.0/docs/images/base-rebuilt-only-corners-2x3.png +0 -0
  12. gridfinity_rebase-0.1.0/docs/images/base-rebuilt-screws-2x3.png +0 -0
  13. gridfinity_rebase-0.1.0/docs/images/base-rebuilt-screws-thumbscrew-2x3.png +0 -0
  14. gridfinity_rebase-0.1.0/docs/images/base-rebuilt-screws-thumbscrew-only-corners-2x3.png +0 -0
  15. gridfinity_rebase-0.1.0/docs/images/base-rebuilt-thumbscrew-2x3.png +0 -0
  16. gridfinity_rebase-0.1.0/docs/images/base-screws-2x3.png +0 -0
  17. gridfinity_rebase-0.1.0/docs/images/detail-crush-ribs.png +0 -0
  18. gridfinity_rebase-0.1.0/docs/images/detail-magnet-holes.png +0 -0
  19. gridfinity_rebase-0.1.0/docs/images/detail-segments-256.png +0 -0
  20. gridfinity_rebase-0.1.0/docs/images/detail-segments-32.png +0 -0
  21. gridfinity_rebase-0.1.0/docs/images/detail-segments-64.png +0 -0
  22. gridfinity_rebase-0.1.0/docs/images/detail-side-loading.png +0 -0
  23. gridfinity_rebase-0.1.0/docs/images/detail-thumbscrew.png +0 -0
  24. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-magnet-holes-2x3.png +0 -0
  25. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-plain-2x3.png +0 -0
  26. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-press-fit-2x3.png +0 -0
  27. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-press-fit-screws-2x3.png +0 -0
  28. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-2x3.png +0 -0
  29. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-only-corners-2x3.png +0 -0
  30. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-screws-2x3.png +0 -0
  31. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-screws-thumbscrew-2x3.png +0 -0
  32. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-screws-thumbscrew-only-corners-2x3.png +0 -0
  33. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-rebuilt-thumbscrew-2x3.png +0 -0
  34. gridfinity_rebase-0.1.0/docs/images/thumbnails/base-screws-2x3.png +0 -0
  35. gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-crush-ribs.png +0 -0
  36. gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-magnet-holes.png +0 -0
  37. gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-segments-256.png +0 -0
  38. gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-segments-32.png +0 -0
  39. gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-segments-64.png +0 -0
  40. gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-side-loading.png +0 -0
  41. gridfinity_rebase-0.1.0/docs/images/thumbnails/detail-thumbscrew.png +0 -0
  42. gridfinity_rebase-0.1.0/docs/performance.md +94 -0
  43. gridfinity_rebase-0.1.0/docs/presets.md +163 -0
  44. gridfinity_rebase-0.1.0/docs/segments.md +46 -0
  45. gridfinity_rebase-0.1.0/pyproject.toml +39 -0
  46. gridfinity_rebase-0.1.0/pyproject.toml.orig +31 -0
  47. gridfinity_rebase-0.1.0/scripts/benchmark.py +174 -0
  48. gridfinity_rebase-0.1.0/scripts/render_readme.py +259 -0
  49. gridfinity_rebase-0.1.0/scripts/setup-dev.sh +6 -0
  50. gridfinity_rebase-0.1.0/src/gridfinity_rebase/__init__.py +78 -0
  51. gridfinity_rebase-0.1.0/src/gridfinity_rebase/__main__.py +5 -0
  52. gridfinity_rebase-0.1.0/src/gridfinity_rebase/api.py +363 -0
  53. gridfinity_rebase-0.1.0/src/gridfinity_rebase/catalog.py +86 -0
  54. gridfinity_rebase-0.1.0/src/gridfinity_rebase/cli.py +377 -0
  55. gridfinity_rebase-0.1.0/src/gridfinity_rebase/errors.py +19 -0
  56. gridfinity_rebase-0.1.0/src/gridfinity_rebase/geometry.py +328 -0
  57. gridfinity_rebase-0.1.0/src/gridfinity_rebase/options.py +97 -0
  58. gridfinity_rebase-0.1.0/src/gridfinity_rebase/presets.py +253 -0
  59. gridfinity_rebase-0.1.0/src/gridfinity_rebase/py.typed +0 -0
  60. gridfinity_rebase-0.1.0/src/gridfinity_rebase/stl.py +127 -0
  61. gridfinity_rebase-0.1.0/tests/fixtures/README.md +21 -0
  62. gridfinity_rebase-0.1.0/tests/fixtures/gf_bin_1x1_h6_bin_v01.stl +0 -0
  63. gridfinity_rebase-0.1.0/tests/fixtures/test-rebased.stl +0 -0
  64. gridfinity_rebase-0.1.0/tests/fixtures/test.stl +0 -0
  65. gridfinity_rebase-0.1.0/tests/test_api.py +330 -0
  66. gridfinity_rebase-0.1.0/tests/test_cli.py +84 -0
  67. gridfinity_rebase-0.1.0/tests/test_core.py +96 -0
  68. gridfinity_rebase-0.1.0/tests/test_only_corners.py +161 -0
  69. gridfinity_rebase-0.1.0/tests/test_options.py +232 -0
  70. gridfinity_rebase-0.1.0/tests/test_presets.py +263 -0
  71. gridfinity_rebase-0.1.0/tests/test_side_pocket_height.py +132 -0
  72. gridfinity_rebase-0.1.0/tests/test_standard_bins.py +166 -0
  73. gridfinity_rebase-0.1.0/tests/test_thumbscrew.py +137 -0
  74. gridfinity_rebase-0.1.0/tests/test_validation.py +111 -0
  75. gridfinity_rebase-0.1.0/uv.lock +774 -0
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Szymon Krajewski
4
+ Copyright (c) 2023 Kenneth Hodson
5
+ Copyright (c) 2023 Zachary Freedman and Voidstar Lab LLC
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: gridfinity-rebase
3
+ Version: 0.1.0
4
+ Summary: Fast, validated Gridfinity STL foot replacement
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Dist: numpy>=2.0,<3
8
+ Requires-Dist: manifold3d>=3.5,<4
9
+ Requires-Python: >=3.10
10
+ Description-Content-Type: text/markdown
11
+
12
+ # Gridfinity Rebase
13
+
14
+ CLI for replacing Gridfinity bin bases with configurable presets or a base copied from another STL.
15
+
16
+ [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-FFDD00?style=for-the-badge&logo=buymeacoffee&logoColor=000)](https://buymeacoffee.com/skrajewski)
17
+
18
+ ## Install
19
+
20
+ Install Python 3.10+ and [uv](https://docs.astral.sh/uv/), then run this command from the repository:
21
+
22
+ ```sh
23
+ uv tool install .
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ Pass an STL file to replace its base. You can also use the explicit
29
+ `gridfinity-rebase rebase` subcommand. Run `gridfinity-rebase` without arguments
30
+ to display help.
31
+
32
+ ```sh
33
+ # Create smooth bottom-loading magnet pockets in bin-rebased-magnet-holes.stl.
34
+ gridfinity-rebase bin.stl --preset magnet-holes
35
+
36
+ # Create side-loading magnet pockets in bin-rebased-rebuilt.stl.
37
+ gridfinity-rebase bin.stl --preset rebuilt
38
+
39
+ # Create screw holes without magnet pockets in bin-rebased-screws.stl.
40
+ gridfinity-rebase bin.stl --screws
41
+
42
+ # Add screw holes to bottom-loading press-fit pockets
43
+ gridfinity-rebase bin.stl --preset press-fit --screws
44
+
45
+ # Place magnet pockets and screw holes only at the four outer corners of the bin.
46
+ gridfinity-rebase bin.stl --preset rebuilt --screws --only-corners
47
+
48
+ # Add side-loading magnet pockets and an M15x1.5 thumbscrew hole.
49
+ # The output is bin-rebased-rebuilt-thumbscrew.stl.
50
+ gridfinity-rebase bin.stl --preset rebuilt --thumbscrew
51
+
52
+ # Copy a base from another bin
53
+ gridfinity-rebase bin.stl --base donor.stl -o result.stl
54
+
55
+ # Inspect a model or list presets
56
+ gridfinity-rebase inspect bin.stl
57
+ gridfinity-rebase presets
58
+ ```
59
+
60
+ ## Presets
61
+
62
+ Available presets: `plain`, `magnet-holes`, `rebuilt` and `press-fit`.
63
+ `refined` is an alias for `rebuilt`.
64
+
65
+ `magnet-holes` creates smooth bottom-loading Ø6.5 × 2.4 mm pockets without ribs.
66
+ `press-fit` adds eight crush ribs to each pocket. You can also get this geometry
67
+ with `--preset magnet-holes --crush-ribs`.
68
+
69
+ The previews show the same 2×3 example bin from underneath. Click a preview for the full-size image.
70
+ Append the options in each row to `gridfinity-rebase bin.stl`.
71
+
72
+ | Preview | Preset | Options |
73
+ | --- | --- | --- |
74
+ | [![Plain 2×3 bin base](docs/images/thumbnails/base-plain-2x3.png)](docs/images/base-plain-2x3.png) | `plain` creates standard feet without magnet pockets or screw holes. | `--preset plain` |
75
+ | [![2×3 bin base with smooth bottom-loading magnet pockets](docs/images/thumbnails/base-magnet-holes-2x3.png)](docs/images/base-magnet-holes-2x3.png) | `magnet-holes` creates four Ø6.5 mm magnet pockets per foot, 2.4 mm deep, without crush ribs. | `--preset magnet-holes` |
76
+ | [![2×3 bin base with side-loading magnet pockets](docs/images/thumbnails/base-rebuilt-2x3.png)](docs/images/base-rebuilt-2x3.png) | `rebuilt` creates four pockets per foot in a fan pattern, with one opening per edge. Small underside slots let you remove magnets. | `--preset rebuilt` |
77
+ | [![2×3 bin base with ribbed bottom-loading magnet pockets](docs/images/thumbnails/base-press-fit-2x3.png)](docs/images/base-press-fit-2x3.png) | `press-fit` creates four bottom-loading pockets per foot, each with eight crush ribs. | `--preset press-fit` |
78
+
79
+ ### Geometry options
80
+
81
+ The default preset is `plain`. Select another preset or change individual settings:
82
+
83
+ - `--magnets none|side|bottom`: no magnet pockets, side-loading pockets, or bottom-loading pockets.
84
+ - `--side-pocket-height MM`: set the side-loading pocket height. The default is 2.1 mm.
85
+ - `--screws` / `--no-screws`: enable or disable 3 mm screw bores.
86
+ - `--crush-ribs` / `--no-crush-ribs`: enable or disable ribs in bottom-loading pockets.
87
+ - `--only-corners`: limit magnet pockets and 3 mm screw bores to the four outer corners of the whole bin, regardless of grid size. A 1×1 bin keeps all four holes. Central `--thumbscrew` holes still appear in every foot.
88
+ - `--thumbscrew` / `--no-thumbscrew`: enable or disable the central threaded hole.
89
+
90
+ ### Examples with geometry options
91
+
92
+ Add flags to a preset to combine magnet pockets, screws and central threads,
93
+ or to place magnet pockets and screw bores only at the outer corners.
94
+
95
+ | Preview | Description | Options |
96
+ | --- | --- | --- |
97
+ | [![2×3 bin base with side-loading magnet pockets and screw bores](docs/images/thumbnails/base-rebuilt-screws-2x3.png)](docs/images/base-rebuilt-screws-2x3.png) | Each side-loading pocket has a Ø3 mm screw bore. | `--preset rebuilt --screws` |
98
+ | [![2×3 bin base with screw bores only](docs/images/thumbnails/base-screws-2x3.png)](docs/images/base-screws-2x3.png) | Each foot has four Ø3 mm screw bores without magnet pockets. | `--screws` |
99
+ | [![2×3 bin base with press-fit magnet pockets and screw bores](docs/images/thumbnails/base-press-fit-screws-2x3.png)](docs/images/base-press-fit-screws-2x3.png) | Bottom-loading pockets have crush ribs and screw bores in their floors. | `--preset press-fit --screws` |
100
+ | [![2×3 bin base with side-loading magnet pockets and central threads](docs/images/thumbnails/base-rebuilt-thumbscrew-2x3.png)](docs/images/base-rebuilt-thumbscrew-2x3.png) | Each foot has side-loading pockets and a central M15×1.5 threaded hole. | `--preset rebuilt --thumbscrew` |
101
+ | [![2×3 bin base with magnet pockets only at the four outer corners](docs/images/thumbnails/base-rebuilt-only-corners-2x3.png)](docs/images/base-rebuilt-only-corners-2x3.png) | The whole bin has four side-loading pockets, one at each outer corner, instead of 24. | `--preset rebuilt --only-corners` |
102
+ | [![2×3 bin base with side-loading magnet pockets, screw bores and central threads](docs/images/thumbnails/base-rebuilt-screws-thumbscrew-2x3.png)](docs/images/base-rebuilt-screws-thumbscrew-2x3.png) | The bin has 24 side pockets, 24 screw bores and six central threaded holes. | `--preset rebuilt --screws --thumbscrew` |
103
+ | [![2×3 bin base with four outer-corner magnet pockets and screw bores, plus six central threads](docs/images/thumbnails/base-rebuilt-screws-thumbscrew-only-corners-2x3.png)](docs/images/base-rebuilt-screws-thumbscrew-only-corners-2x3.png) | The whole bin has four side pockets and four screw bores at its outer corners. All six feet have a central threaded hole. | `--preset rebuilt --screws --thumbscrew --only-corners` |
104
+
105
+ ### Close-ups
106
+
107
+ | Preview | Description | Options |
108
+ | --- | --- | --- |
109
+ | [![Close-up of a side-loading magnet pocket](docs/images/thumbnails/detail-side-loading.png)](docs/images/detail-side-loading.png) | The magnet slides through the opening in the edge of the foot. | `--preset rebuilt` |
110
+ | [![Close-up of a smooth bottom magnet pocket](docs/images/thumbnails/detail-magnet-holes.png)](docs/images/detail-magnet-holes.png) | Insert the magnet into the circular recess from underneath. | `--preset magnet-holes` |
111
+ | [![Close-up of the eight crush ribs in a magnet pocket](docs/images/thumbnails/detail-crush-ribs.png)](docs/images/detail-crush-ribs.png) | Eight ribs narrow the pocket for a press fit. | `--preset press-fit` |
112
+ | [![Close-up of a central M15×1.5 threaded hole](docs/images/thumbnails/detail-thumbscrew.png)](docs/images/detail-thumbscrew.png) | The M15×1.5 threaded hole is 4.75 mm deep, with a solid bridge above. | `--preset rebuilt --thumbscrew` |
113
+
114
+ The images show geometry generated by the CLI. [Regenerate the graphics](docs/images/README.md).
115
+
116
+ See [curve resolution](docs/segments.md) for `--segments` settings and visual comparisons.
117
+
118
+ ## Key details
119
+
120
+ - The CLI supports standard rectangular Gridfinity bins on a 42 mm grid. Use millimeters for STL units, with feet at the bottom and Z pointing up.
121
+ - The CLI detects the base and cut height. It preserves the bin interior and geometry above the cut, and rejects invalid meshes, incompatible bases and ambiguous models.
122
+ - A donor base can match the input grid or have its X/Y dimensions swapped. The CLI can also tile a 1×1 donor base across the input.
123
+ - Unmodified presets write to `bin-rebased-PRESET.stl`. `--thumbscrew` and `--only-corners` append their names to the filename. Modified settings use a descriptive suffix, such as `bin-rebased-magnets-bottom-crush-ribs-screws.stl`. Donor bases use `bin-rebased.stl`. Use `-o` to choose a filename and `--overwrite` to replace an existing output.
124
+ - JSON reports include the resolved `geometry` settings. `base` identifies the starting preset or donor path. The default preset is `plain`. For donor bases, `geometry` is `null`.
125
+ - `--base-height MM` overrides automatic detection for custom models and replaces everything below that height. The minimum is 4.75 mm.
126
+
127
+ Run `gridfinity-rebase --help` for all options.
128
+
129
+ ## Performance
130
+
131
+ Run the benchmark from the repository root:
132
+
133
+ ```sh
134
+ uv run --locked --python 3.11 python scripts/benchmark.py --runs 5
135
+ ```
136
+
137
+ The benchmark generates all test models locally. You do not need to download example STLs.
138
+ See [benchmark instructions, methodology and reference results](docs/performance.md)
139
+ for JSON output and environment details.
140
+
141
+ ## AI Disclosure
142
+
143
+ Szymon here. I use AI to build this tool.
144
+
145
+ I needed a way for quick replacement of base of custom Grdifnity bins downloaded from Internet, but I didn't want to spend too much of my free time on this. I collaborated with the AI, describing how it should work, how I want to use it and what's the important from the both code perspective and end-user perspective. It allowed me to iterate and create something that is exactly what I needed. Now I share it with you.
146
+
147
+ Just want you to know.
148
+
149
+ ## License
150
+
151
+ The [MIT license](LICENSE) covers this CLI and its adapted preset implementation.
152
+
153
+ Processing a model does not replace its existing license or attribution
154
+ requirements. When sharing a rebased STL, preserve applicable notices and
155
+ comply with the licenses of the input model and any donor geometry.
156
+
157
+ ## Acknowledgements
158
+
159
+ Preset geometry is adapted from the MIT-licensed [Gridfinity Rebuilt implementation](https://github.com/kennetek/gridfinity-rebuilt-openscad/tree/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd)
160
+ by Kenneth Hodson, based on Gridfinity by Zack Freedman. Rebuilt credits
161
+ [Gridfinity Refined](https://www.printables.com/model/413761-gridfinity-refined)
162
+ by grizzie17 as the source of its side-loading magnet pockets.
163
+
164
+ Rebuilt source files at revision `910e22d8607fd7f5f51ad5e5cbc5287a76810bfd`:
165
+
166
+ - [standard.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/standard.scad): mating profile, grid, radii and hole dimensions.
167
+ - [gridfinity-rebuilt-holes.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/gridfinity-rebuilt-holes.scad): side-loading magnet pockets and crush ribs.
168
+ - [base.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/base.scad): fan arrangement of the four pockets and the central threaded hole.
169
+
170
+ The native thumbscrew thread tessellation derives from `ScrewThread()` in
171
+ [threads-scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/external/threads-scad/threads.scad),
172
+ created in 2016 — 2017 by Ryan A. Colyer and released under [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/).
@@ -0,0 +1,161 @@
1
+ # Gridfinity Rebase
2
+
3
+ CLI for replacing Gridfinity bin bases with configurable presets or a base copied from another STL.
4
+
5
+ [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-FFDD00?style=for-the-badge&logo=buymeacoffee&logoColor=000)](https://buymeacoffee.com/skrajewski)
6
+
7
+ ## Install
8
+
9
+ Install Python 3.10+ and [uv](https://docs.astral.sh/uv/), then run this command from the repository:
10
+
11
+ ```sh
12
+ uv tool install .
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ Pass an STL file to replace its base. You can also use the explicit
18
+ `gridfinity-rebase rebase` subcommand. Run `gridfinity-rebase` without arguments
19
+ to display help.
20
+
21
+ ```sh
22
+ # Create smooth bottom-loading magnet pockets in bin-rebased-magnet-holes.stl.
23
+ gridfinity-rebase bin.stl --preset magnet-holes
24
+
25
+ # Create side-loading magnet pockets in bin-rebased-rebuilt.stl.
26
+ gridfinity-rebase bin.stl --preset rebuilt
27
+
28
+ # Create screw holes without magnet pockets in bin-rebased-screws.stl.
29
+ gridfinity-rebase bin.stl --screws
30
+
31
+ # Add screw holes to bottom-loading press-fit pockets
32
+ gridfinity-rebase bin.stl --preset press-fit --screws
33
+
34
+ # Place magnet pockets and screw holes only at the four outer corners of the bin.
35
+ gridfinity-rebase bin.stl --preset rebuilt --screws --only-corners
36
+
37
+ # Add side-loading magnet pockets and an M15x1.5 thumbscrew hole.
38
+ # The output is bin-rebased-rebuilt-thumbscrew.stl.
39
+ gridfinity-rebase bin.stl --preset rebuilt --thumbscrew
40
+
41
+ # Copy a base from another bin
42
+ gridfinity-rebase bin.stl --base donor.stl -o result.stl
43
+
44
+ # Inspect a model or list presets
45
+ gridfinity-rebase inspect bin.stl
46
+ gridfinity-rebase presets
47
+ ```
48
+
49
+ ## Presets
50
+
51
+ Available presets: `plain`, `magnet-holes`, `rebuilt` and `press-fit`.
52
+ `refined` is an alias for `rebuilt`.
53
+
54
+ `magnet-holes` creates smooth bottom-loading Ø6.5 × 2.4 mm pockets without ribs.
55
+ `press-fit` adds eight crush ribs to each pocket. You can also get this geometry
56
+ with `--preset magnet-holes --crush-ribs`.
57
+
58
+ The previews show the same 2×3 example bin from underneath. Click a preview for the full-size image.
59
+ Append the options in each row to `gridfinity-rebase bin.stl`.
60
+
61
+ | Preview | Preset | Options |
62
+ | --- | --- | --- |
63
+ | [![Plain 2×3 bin base](docs/images/thumbnails/base-plain-2x3.png)](docs/images/base-plain-2x3.png) | `plain` creates standard feet without magnet pockets or screw holes. | `--preset plain` |
64
+ | [![2×3 bin base with smooth bottom-loading magnet pockets](docs/images/thumbnails/base-magnet-holes-2x3.png)](docs/images/base-magnet-holes-2x3.png) | `magnet-holes` creates four Ø6.5 mm magnet pockets per foot, 2.4 mm deep, without crush ribs. | `--preset magnet-holes` |
65
+ | [![2×3 bin base with side-loading magnet pockets](docs/images/thumbnails/base-rebuilt-2x3.png)](docs/images/base-rebuilt-2x3.png) | `rebuilt` creates four pockets per foot in a fan pattern, with one opening per edge. Small underside slots let you remove magnets. | `--preset rebuilt` |
66
+ | [![2×3 bin base with ribbed bottom-loading magnet pockets](docs/images/thumbnails/base-press-fit-2x3.png)](docs/images/base-press-fit-2x3.png) | `press-fit` creates four bottom-loading pockets per foot, each with eight crush ribs. | `--preset press-fit` |
67
+
68
+ ### Geometry options
69
+
70
+ The default preset is `plain`. Select another preset or change individual settings:
71
+
72
+ - `--magnets none|side|bottom`: no magnet pockets, side-loading pockets, or bottom-loading pockets.
73
+ - `--side-pocket-height MM`: set the side-loading pocket height. The default is 2.1 mm.
74
+ - `--screws` / `--no-screws`: enable or disable 3 mm screw bores.
75
+ - `--crush-ribs` / `--no-crush-ribs`: enable or disable ribs in bottom-loading pockets.
76
+ - `--only-corners`: limit magnet pockets and 3 mm screw bores to the four outer corners of the whole bin, regardless of grid size. A 1×1 bin keeps all four holes. Central `--thumbscrew` holes still appear in every foot.
77
+ - `--thumbscrew` / `--no-thumbscrew`: enable or disable the central threaded hole.
78
+
79
+ ### Examples with geometry options
80
+
81
+ Add flags to a preset to combine magnet pockets, screws and central threads,
82
+ or to place magnet pockets and screw bores only at the outer corners.
83
+
84
+ | Preview | Description | Options |
85
+ | --- | --- | --- |
86
+ | [![2×3 bin base with side-loading magnet pockets and screw bores](docs/images/thumbnails/base-rebuilt-screws-2x3.png)](docs/images/base-rebuilt-screws-2x3.png) | Each side-loading pocket has a Ø3 mm screw bore. | `--preset rebuilt --screws` |
87
+ | [![2×3 bin base with screw bores only](docs/images/thumbnails/base-screws-2x3.png)](docs/images/base-screws-2x3.png) | Each foot has four Ø3 mm screw bores without magnet pockets. | `--screws` |
88
+ | [![2×3 bin base with press-fit magnet pockets and screw bores](docs/images/thumbnails/base-press-fit-screws-2x3.png)](docs/images/base-press-fit-screws-2x3.png) | Bottom-loading pockets have crush ribs and screw bores in their floors. | `--preset press-fit --screws` |
89
+ | [![2×3 bin base with side-loading magnet pockets and central threads](docs/images/thumbnails/base-rebuilt-thumbscrew-2x3.png)](docs/images/base-rebuilt-thumbscrew-2x3.png) | Each foot has side-loading pockets and a central M15×1.5 threaded hole. | `--preset rebuilt --thumbscrew` |
90
+ | [![2×3 bin base with magnet pockets only at the four outer corners](docs/images/thumbnails/base-rebuilt-only-corners-2x3.png)](docs/images/base-rebuilt-only-corners-2x3.png) | The whole bin has four side-loading pockets, one at each outer corner, instead of 24. | `--preset rebuilt --only-corners` |
91
+ | [![2×3 bin base with side-loading magnet pockets, screw bores and central threads](docs/images/thumbnails/base-rebuilt-screws-thumbscrew-2x3.png)](docs/images/base-rebuilt-screws-thumbscrew-2x3.png) | The bin has 24 side pockets, 24 screw bores and six central threaded holes. | `--preset rebuilt --screws --thumbscrew` |
92
+ | [![2×3 bin base with four outer-corner magnet pockets and screw bores, plus six central threads](docs/images/thumbnails/base-rebuilt-screws-thumbscrew-only-corners-2x3.png)](docs/images/base-rebuilt-screws-thumbscrew-only-corners-2x3.png) | The whole bin has four side pockets and four screw bores at its outer corners. All six feet have a central threaded hole. | `--preset rebuilt --screws --thumbscrew --only-corners` |
93
+
94
+ ### Close-ups
95
+
96
+ | Preview | Description | Options |
97
+ | --- | --- | --- |
98
+ | [![Close-up of a side-loading magnet pocket](docs/images/thumbnails/detail-side-loading.png)](docs/images/detail-side-loading.png) | The magnet slides through the opening in the edge of the foot. | `--preset rebuilt` |
99
+ | [![Close-up of a smooth bottom magnet pocket](docs/images/thumbnails/detail-magnet-holes.png)](docs/images/detail-magnet-holes.png) | Insert the magnet into the circular recess from underneath. | `--preset magnet-holes` |
100
+ | [![Close-up of the eight crush ribs in a magnet pocket](docs/images/thumbnails/detail-crush-ribs.png)](docs/images/detail-crush-ribs.png) | Eight ribs narrow the pocket for a press fit. | `--preset press-fit` |
101
+ | [![Close-up of a central M15×1.5 threaded hole](docs/images/thumbnails/detail-thumbscrew.png)](docs/images/detail-thumbscrew.png) | The M15×1.5 threaded hole is 4.75 mm deep, with a solid bridge above. | `--preset rebuilt --thumbscrew` |
102
+
103
+ The images show geometry generated by the CLI. [Regenerate the graphics](docs/images/README.md).
104
+
105
+ See [curve resolution](docs/segments.md) for `--segments` settings and visual comparisons.
106
+
107
+ ## Key details
108
+
109
+ - The CLI supports standard rectangular Gridfinity bins on a 42 mm grid. Use millimeters for STL units, with feet at the bottom and Z pointing up.
110
+ - The CLI detects the base and cut height. It preserves the bin interior and geometry above the cut, and rejects invalid meshes, incompatible bases and ambiguous models.
111
+ - A donor base can match the input grid or have its X/Y dimensions swapped. The CLI can also tile a 1×1 donor base across the input.
112
+ - Unmodified presets write to `bin-rebased-PRESET.stl`. `--thumbscrew` and `--only-corners` append their names to the filename. Modified settings use a descriptive suffix, such as `bin-rebased-magnets-bottom-crush-ribs-screws.stl`. Donor bases use `bin-rebased.stl`. Use `-o` to choose a filename and `--overwrite` to replace an existing output.
113
+ - JSON reports include the resolved `geometry` settings. `base` identifies the starting preset or donor path. The default preset is `plain`. For donor bases, `geometry` is `null`.
114
+ - `--base-height MM` overrides automatic detection for custom models and replaces everything below that height. The minimum is 4.75 mm.
115
+
116
+ Run `gridfinity-rebase --help` for all options.
117
+
118
+ ## Performance
119
+
120
+ Run the benchmark from the repository root:
121
+
122
+ ```sh
123
+ uv run --locked --python 3.11 python scripts/benchmark.py --runs 5
124
+ ```
125
+
126
+ The benchmark generates all test models locally. You do not need to download example STLs.
127
+ See [benchmark instructions, methodology and reference results](docs/performance.md)
128
+ for JSON output and environment details.
129
+
130
+ ## AI Disclosure
131
+
132
+ Szymon here. I use AI to build this tool.
133
+
134
+ I needed a way for quick replacement of base of custom Grdifnity bins downloaded from Internet, but I didn't want to spend too much of my free time on this. I collaborated with the AI, describing how it should work, how I want to use it and what's the important from the both code perspective and end-user perspective. It allowed me to iterate and create something that is exactly what I needed. Now I share it with you.
135
+
136
+ Just want you to know.
137
+
138
+ ## License
139
+
140
+ The [MIT license](LICENSE) covers this CLI and its adapted preset implementation.
141
+
142
+ Processing a model does not replace its existing license or attribution
143
+ requirements. When sharing a rebased STL, preserve applicable notices and
144
+ comply with the licenses of the input model and any donor geometry.
145
+
146
+ ## Acknowledgements
147
+
148
+ Preset geometry is adapted from the MIT-licensed [Gridfinity Rebuilt implementation](https://github.com/kennetek/gridfinity-rebuilt-openscad/tree/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd)
149
+ by Kenneth Hodson, based on Gridfinity by Zack Freedman. Rebuilt credits
150
+ [Gridfinity Refined](https://www.printables.com/model/413761-gridfinity-refined)
151
+ by grizzie17 as the source of its side-loading magnet pockets.
152
+
153
+ Rebuilt source files at revision `910e22d8607fd7f5f51ad5e5cbc5287a76810bfd`:
154
+
155
+ - [standard.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/standard.scad): mating profile, grid, radii and hole dimensions.
156
+ - [gridfinity-rebuilt-holes.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/gridfinity-rebuilt-holes.scad): side-loading magnet pockets and crush ribs.
157
+ - [base.scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/core/base.scad): fan arrangement of the four pockets and the central threaded hole.
158
+
159
+ The native thumbscrew thread tessellation derives from `ScrewThread()` in
160
+ [threads-scad](https://github.com/kennetek/gridfinity-rebuilt-openscad/blob/910e22d8607fd7f5f51ad5e5cbc5287a76810bfd/src/external/threads-scad/threads.scad),
161
+ created in 2016 — 2017 by Ryan A. Colyer and released under [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/).
@@ -0,0 +1,186 @@
1
+ {
2
+ "measured_at_utc": "2026-10-13T21:57:46.970337+00:00",
3
+ "platform": "macOS-26.2-arm64-arm-64bit",
4
+ "machine": "arm64",
5
+ "processor": "arm",
6
+ "logical_cpus": 12,
7
+ "python": "3.11.14",
8
+ "dependencies": {
9
+ "gridfinity-rebase": "0.2.1",
10
+ "manifold3d": "3.5.4",
11
+ "numpy": "2.4.6"
12
+ },
13
+ "runs": 5,
14
+ "warmups_per_scenario": 1,
15
+ "segments": 64,
16
+ "inputs": {
17
+ "1x1": {
18
+ "sha256": "b3b6c2ad78f0e541e5e90331b669c8eaff3a692773903fc71c41b03e225bf184",
19
+ "triangles": 1894
20
+ },
21
+ "donor": {
22
+ "sha256": "b3b6c2ad78f0e541e5e90331b669c8eaff3a692773903fc71c41b03e225bf184",
23
+ "triangles": 1894
24
+ },
25
+ "6x6": {
26
+ "sha256": "c65ebe2a72559086b1a7fa85df1fdde08dccaef808ebc5581f53459b682f24d9",
27
+ "triangles": 58246
28
+ }
29
+ },
30
+ "results": [
31
+ {
32
+ "scenario": "1x1/plain",
33
+ "input_triangles": 1894,
34
+ "process_median_ms": 94.51,
35
+ "process_min_ms": 89.43,
36
+ "process_max_ms": 95.4,
37
+ "warm_engine_median_ms": 12.46,
38
+ "process_samples_ms": [
39
+ 94.5103750564158,
40
+ 89.4317920319736,
41
+ 89.57604202441871,
42
+ 95.39591695647687,
43
+ 94.918749993667
44
+ ],
45
+ "warm_engine_samples_ms": [
46
+ 12.875832966528833,
47
+ 12.11520901415497,
48
+ 12.394832912832499,
49
+ 12.613541912287474,
50
+ 12.457333039492369
51
+ ]
52
+ },
53
+ {
54
+ "scenario": "1x1/rebuilt",
55
+ "input_triangles": 1894,
56
+ "process_median_ms": 94.41,
57
+ "process_min_ms": 93.3,
58
+ "process_max_ms": 97.89,
59
+ "warm_engine_median_ms": 14.64,
60
+ "process_samples_ms": [
61
+ 94.40787509083748,
62
+ 97.88887505419552,
63
+ 93.29600003547966,
64
+ 94.29145907051861,
65
+ 97.07208396866918
66
+ ],
67
+ "warm_engine_samples_ms": [
68
+ 15.291957999579608,
69
+ 14.654417056590319,
70
+ 14.159000013023615,
71
+ 14.640958048403263,
72
+ 14.112790930084884
73
+ ]
74
+ },
75
+ {
76
+ "scenario": "1x1/rebuilt-screws",
77
+ "input_triangles": 1894,
78
+ "process_median_ms": 112.18,
79
+ "process_min_ms": 110.47,
80
+ "process_max_ms": 115.48,
81
+ "warm_engine_median_ms": 28.16,
82
+ "process_samples_ms": [
83
+ 115.48470810521394,
84
+ 111.7373340530321,
85
+ 112.17912496067584,
86
+ 110.46716605778784,
87
+ 115.03658397123218
88
+ ],
89
+ "warm_engine_samples_ms": [
90
+ 27.97850000206381,
91
+ 28.1615830026567,
92
+ 27.632666984573007,
93
+ 28.340917080640793,
94
+ 28.18029106128961
95
+ ]
96
+ },
97
+ {
98
+ "scenario": "1x1/refined",
99
+ "input_triangles": 1894,
100
+ "process_median_ms": 87.83,
101
+ "process_min_ms": 87.02,
102
+ "process_max_ms": 89.51,
103
+ "warm_engine_median_ms": 14.14,
104
+ "process_samples_ms": [
105
+ 87.8272500121966,
106
+ 87.02079206705093,
107
+ 89.35604197904468,
108
+ 87.70487492438406,
109
+ 89.51008401345462
110
+ ],
111
+ "warm_engine_samples_ms": [
112
+ 14.215333969332278,
113
+ 13.873500050976872,
114
+ 14.188083005137742,
115
+ 13.950416934676468,
116
+ 14.141583000309765
117
+ ]
118
+ },
119
+ {
120
+ "scenario": "1x1/press-fit",
121
+ "input_triangles": 1894,
122
+ "process_median_ms": 87.83,
123
+ "process_min_ms": 86.86,
124
+ "process_max_ms": 90.24,
125
+ "warm_engine_median_ms": 13.72,
126
+ "process_samples_ms": [
127
+ 87.73008291609585,
128
+ 88.37041701190174,
129
+ 90.24062496609986,
130
+ 86.86333289369941,
131
+ 87.8282500198111
132
+ ],
133
+ "warm_engine_samples_ms": [
134
+ 13.611625065095723,
135
+ 13.737166998907924,
136
+ 13.724167016334832,
137
+ 13.462667004205287,
138
+ 14.19558294583112
139
+ ]
140
+ },
141
+ {
142
+ "scenario": "1x1/donor",
143
+ "input_triangles": 1894,
144
+ "process_median_ms": 89.76,
145
+ "process_min_ms": 89.11,
146
+ "process_max_ms": 91.82,
147
+ "warm_engine_median_ms": 18.54,
148
+ "process_samples_ms": [
149
+ 90.0000830879435,
150
+ 89.24408291932195,
151
+ 89.1148749506101,
152
+ 89.76320794317871,
153
+ 91.8165419716388
154
+ ],
155
+ "warm_engine_samples_ms": [
156
+ 18.746749963611364,
157
+ 18.00991699565202,
158
+ 18.890125094912946,
159
+ 18.205416039563715,
160
+ 18.536541028879583
161
+ ]
162
+ },
163
+ {
164
+ "scenario": "6x6/refined",
165
+ "input_triangles": 58246,
166
+ "process_median_ms": 260.88,
167
+ "process_min_ms": 257.67,
168
+ "process_max_ms": 270.68,
169
+ "warm_engine_median_ms": 178.35,
170
+ "process_samples_ms": [
171
+ 264.94266698136926,
172
+ 260.8814589912072,
173
+ 257.6676660683006,
174
+ 260.19500009715557,
175
+ 270.68120893090963
176
+ ],
177
+ "warm_engine_samples_ms": [
178
+ 179.92949998006225,
179
+ 178.08800004422665,
180
+ 178.34912496618927,
181
+ 178.3229160355404,
182
+ 179.09554205834866
183
+ ]
184
+ }
185
+ ]
186
+ }
@@ -0,0 +1,47 @@
1
+ # README graphics
2
+
3
+ Each PNG contains one model or one close-up, without embedded text. The main
4
+ README places the images in tables with descriptions and the corresponding CLI
5
+ options. Clicking a thumbnail opens the full-size image.
6
+ The `thumbnails/` directory contains 260 px previews, so the README can use
7
+ standard Markdown image links without HTML sizing attributes.
8
+
9
+ The `base-*-2x3.png` images show the underside of the same synthetic 2×3 example
10
+ bin, using `generate_base()` and the CLI's resolved geometry options. They use
11
+ the same body, camera, orthographic scale and lighting. The `detail-*.png` images
12
+ show crops of those same models. Magnification varies between details.
13
+
14
+ The four preset images are `base-plain-2x3.png`,
15
+ `base-magnet-holes-2x3.png`, `base-rebuilt-2x3.png` and
16
+ `base-press-fit-2x3.png`. `refined` shares the `rebuilt` image because it is
17
+ an alias. Other base images illustrate combinations of geometry flags,
18
+ such as `rebuilt` with `--screws`.
19
+ The `detail-magnet-holes.png` and `detail-crush-ribs.png` close-ups show
20
+ the difference between smooth magnet pockets and `press-fit`.
21
+
22
+ The `detail-segments-{32,64,256}.png` images compare a central threaded
23
+ hole in a generated 1×1 base at three curve resolutions. All three use the same
24
+ camera, scale and lighting. Only the base's segment count changes.
25
+
26
+ Regenerate from the repository root:
27
+
28
+ ```sh
29
+ uv run --with pillow python scripts/render_readme.py
30
+ ```
31
+
32
+ Regenerate only the three resolution comparisons and their thumbnails:
33
+
34
+ ```sh
35
+ uv run --with pillow python scripts/render_readme.py --segments-only
36
+ ```
37
+
38
+ The renderer uses NumPy and Pillow with a triangle depth buffer. It needs no
39
+ display, GPU or external CAD renderer. The command installs Pillow as a temporary
40
+ dependency. Preset and geometry option illustrations use 256 segments by default
41
+ for close-ups, independently of the CLI's default of 64. The resolution
42
+ comparisons always use 32, 64 and 256, regardless of the renderer's `--segments`
43
+ argument. Edit descriptions and options in the README.
44
+
45
+ The shared example body is 21 mm high, with a cavity starting at 8 mm. Its base
46
+ extends to 7 mm. The body has no stacking lip because these illustrations
47
+ focus on the feet and mounting options.