woodwright 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.
- woodwright-0.1.0/.gitignore +75 -0
- woodwright-0.1.0/LICENSE +21 -0
- woodwright-0.1.0/PKG-INFO +121 -0
- woodwright-0.1.0/README.md +96 -0
- woodwright-0.1.0/docs/initial_vision.md +19 -0
- woodwright-0.1.0/docs/plan.md +577 -0
- woodwright-0.1.0/docs/validation.md +145 -0
- woodwright-0.1.0/docs/vision.md +358 -0
- woodwright-0.1.0/pyproject.toml +65 -0
- woodwright-0.1.0/src/woodwright/__init__.py +124 -0
- woodwright-0.1.0/src/woodwright/assembly.py +173 -0
- woodwright-0.1.0/src/woodwright/cuts.py +791 -0
- woodwright-0.1.0/src/woodwright/examples/__init__.py +93 -0
- woodwright-0.1.0/src/woodwright/examples/__main__.py +42 -0
- woodwright-0.1.0/src/woodwright/examples/_common.py +17 -0
- woodwright-0.1.0/src/woodwright/examples/cuts.py +145 -0
- woodwright-0.1.0/src/woodwright/examples/frames.py +133 -0
- woodwright-0.1.0/src/woodwright/examples/joints.py +454 -0
- woodwright-0.1.0/src/woodwright/examples/projects.py +457 -0
- woodwright-0.1.0/src/woodwright/export.py +68 -0
- woodwright-0.1.0/src/woodwright/joints.py +915 -0
- woodwright-0.1.0/src/woodwright/part.py +230 -0
- woodwright-0.1.0/src/woodwright/placement.py +177 -0
- woodwright-0.1.0/src/woodwright/py.typed +0 -0
- woodwright-0.1.0/src/woodwright/rules.py +49 -0
- woodwright-0.1.0/src/woodwright/stock.py +15 -0
- woodwright-0.1.0/tests/test_assembly.py +133 -0
- woodwright-0.1.0/tests/test_cuts.py +325 -0
- woodwright-0.1.0/tests/test_examples.py +125 -0
- woodwright-0.1.0/tests/test_joints.py +488 -0
- woodwright-0.1.0/tests/test_part.py +138 -0
- woodwright-0.1.0/tests/test_placement.py +133 -0
- woodwright-0.1.0/tests/test_rules.py +19 -0
- woodwright-0.1.0/tests/test_smoke.py +5 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
### macOS
|
|
2
|
+
# Finder metadata
|
|
3
|
+
.DS_Store
|
|
4
|
+
|
|
5
|
+
# Thumbnails
|
|
6
|
+
._*
|
|
7
|
+
|
|
8
|
+
# Custom folder icons
|
|
9
|
+
Icon
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Volume root files
|
|
13
|
+
.DocumentRevisions-V100
|
|
14
|
+
.fseventsd
|
|
15
|
+
.Spotlight-V100
|
|
16
|
+
.TemporaryItems
|
|
17
|
+
.Trashes
|
|
18
|
+
.VolumeIcon.icns
|
|
19
|
+
.com.apple.timemachine.donotpresent
|
|
20
|
+
|
|
21
|
+
### JetBrains
|
|
22
|
+
# JetBrains IDE directory
|
|
23
|
+
.idea/
|
|
24
|
+
|
|
25
|
+
# CMake build directories
|
|
26
|
+
cmake-build-*/
|
|
27
|
+
|
|
28
|
+
# File-based project format
|
|
29
|
+
*.iws
|
|
30
|
+
*.iml
|
|
31
|
+
|
|
32
|
+
# IntelliJ build output
|
|
33
|
+
out/
|
|
34
|
+
|
|
35
|
+
### Python
|
|
36
|
+
# Byte-compiled files
|
|
37
|
+
__pycache__/
|
|
38
|
+
*.py[cod]
|
|
39
|
+
*$py.class
|
|
40
|
+
|
|
41
|
+
# C extensions
|
|
42
|
+
*.so
|
|
43
|
+
|
|
44
|
+
# Distribution / packaging
|
|
45
|
+
build/
|
|
46
|
+
dist/
|
|
47
|
+
*.egg-info/
|
|
48
|
+
*.egg
|
|
49
|
+
|
|
50
|
+
# dotenv environment variable files
|
|
51
|
+
.env
|
|
52
|
+
|
|
53
|
+
# Virtual environments
|
|
54
|
+
.venv
|
|
55
|
+
env/
|
|
56
|
+
venv/
|
|
57
|
+
|
|
58
|
+
# Unit test / coverage reports
|
|
59
|
+
htmlcov/
|
|
60
|
+
.tox/
|
|
61
|
+
.nox/
|
|
62
|
+
.coverage
|
|
63
|
+
.coverage.*
|
|
64
|
+
.pytest_cache/
|
|
65
|
+
|
|
66
|
+
# Type checkers
|
|
67
|
+
.mypy_cache/
|
|
68
|
+
|
|
69
|
+
# Jupyter Notebook
|
|
70
|
+
.ipynb_checkpoints
|
|
71
|
+
|
|
72
|
+
# pyenv
|
|
73
|
+
# .python-version
|
|
74
|
+
|
|
75
|
+
output/
|
woodwright-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bohumír Zámečník
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: woodwright
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A semantic CAD library for woodworking.
|
|
5
|
+
Project-URL: Homepage, https://github.com/bzamecnik/woodwright
|
|
6
|
+
Project-URL: Source, https://github.com/bzamecnik/woodwright
|
|
7
|
+
Project-URL: Issues, https://github.com/bzamecnik/woodwright/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/bzamecnik/woodwright/tree/HEAD/docs
|
|
9
|
+
Author-email: Bohumir Zamecnik <bohumir.zamecnik@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: build123d,cad,cut list,furniture,joinery,woodworking
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Manufacturing
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.14
|
|
23
|
+
Requires-Dist: build123d>=0.13.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# woodwright
|
|
27
|
+
|
|
28
|
+
A semantic CAD library for woodworking. You describe furniture the way a
|
|
29
|
+
woodworker thinks about it: boards with named sides, and the joints between
|
|
30
|
+
them. woodwright works out the joinery, the cut sizes and where every part
|
|
31
|
+
goes, and produces 3D models (STEP, STL), drawings (SVG) and cut lists.
|
|
32
|
+
|
|
33
|
+
It is built on [build123d](https://github.com/gumyr/build123d). This is an
|
|
34
|
+
early alpha: the API will still change.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```shell
|
|
39
|
+
pip install woodwright # or: uv add woodwright
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Requires Python 3.14. Source: <https://github.com/bzamecnik/woodwright>
|
|
43
|
+
|
|
44
|
+
## Quickstart
|
|
45
|
+
|
|
46
|
+
A rail tenoned into a stile. You give the design dimensions and the joint;
|
|
47
|
+
the tenon, the mortise, the rail's cut length and its placement are derived.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from pathlib import Path
|
|
51
|
+
|
|
52
|
+
import woodwright as ww
|
|
53
|
+
from woodwright.export import export_model
|
|
54
|
+
|
|
55
|
+
oak = ww.Stock.board(thickness=20, species="oak")
|
|
56
|
+
|
|
57
|
+
frame = ww.Assembly("corner", root_location=ww.orient(right_end=ww.UP, back_edge=ww.RIGHT))
|
|
58
|
+
stile = frame.add(ww.Board("stile", oak, length=600, width=60))
|
|
59
|
+
rail = frame.add(ww.Board("rail", oak, length=300, width=60)) # shoulder to shoulder
|
|
60
|
+
frame.join(ww.MortiseTenon(tenon=rail.left_end, mortise=stile.back_edge))
|
|
61
|
+
|
|
62
|
+
model = frame.resolve()
|
|
63
|
+
print(model.cut_list())
|
|
64
|
+
export_model(model, Path("output/corner")) # STEP, STL, SVG views, cut list
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
stile 600 x 60 x 20 mm oak
|
|
69
|
+
- mortise 50 x 8 mm, 42 deep, in stile.back_edge
|
|
70
|
+
rail 340 x 60 x 20 mm oak
|
|
71
|
+
- tenon 50 x 8 mm, 40 long, on rail.left_end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Cuts and joints so far: grooves, dados, rabbets, mortises, tenons (haunched,
|
|
75
|
+
mitred), chamfers, mitres, tapers; butt, dado, rabbet, groove, tongue and
|
|
76
|
+
groove, mortise and tenon, bridle, half lap, cross lap, mitre corners and
|
|
77
|
+
splices, sliding, through and half-blind dovetails, and table-top buttons.
|
|
78
|
+
|
|
79
|
+
## Example library
|
|
80
|
+
|
|
81
|
+
`woodwright.examples` holds over fifty examples, from single cuts through
|
|
82
|
+
joints to projects: a try square, a mallet, a bookshelf, a dovetailed drawer
|
|
83
|
+
with a bottom, a dining table.
|
|
84
|
+
|
|
85
|
+
```shell
|
|
86
|
+
python -m woodwright.examples list
|
|
87
|
+
python -m woodwright.examples export projects.table --out output
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The design ideas are in [docs/vision.md](https://github.com/bzamecnik/woodwright/blob/HEAD/docs/vision.md)
|
|
91
|
+
and [docs/plan.md](https://github.com/bzamecnik/woodwright/blob/HEAD/docs/plan.md).
|
|
92
|
+
|
|
93
|
+
## Development
|
|
94
|
+
|
|
95
|
+
Install the environment and dependencies:
|
|
96
|
+
```shell
|
|
97
|
+
uv sync
|
|
98
|
+
pre-commit install # ruff lint + format on commit
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Optionally, for notebooks with an interactive 3D viewer:
|
|
102
|
+
```shell
|
|
103
|
+
uv sync --group notebook
|
|
104
|
+
uv run jupyter lab
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Run the tests and the linters:
|
|
108
|
+
```shell
|
|
109
|
+
uv run pytest
|
|
110
|
+
uv run ruff format
|
|
111
|
+
uv run ruff check --fix
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
[MIT License](./LICENSE).
|
|
117
|
+
|
|
118
|
+
### Credits
|
|
119
|
+
|
|
120
|
+
- Ideas and guidance: Bohumír Zámečník
|
|
121
|
+
- Most of the implementation: Claude Code (Opus 5.5)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# woodwright
|
|
2
|
+
|
|
3
|
+
A semantic CAD library for woodworking. You describe furniture the way a
|
|
4
|
+
woodworker thinks about it: boards with named sides, and the joints between
|
|
5
|
+
them. woodwright works out the joinery, the cut sizes and where every part
|
|
6
|
+
goes, and produces 3D models (STEP, STL), drawings (SVG) and cut lists.
|
|
7
|
+
|
|
8
|
+
It is built on [build123d](https://github.com/gumyr/build123d). This is an
|
|
9
|
+
early alpha: the API will still change.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```shell
|
|
14
|
+
pip install woodwright # or: uv add woodwright
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Python 3.14. Source: <https://github.com/bzamecnik/woodwright>
|
|
18
|
+
|
|
19
|
+
## Quickstart
|
|
20
|
+
|
|
21
|
+
A rail tenoned into a stile. You give the design dimensions and the joint;
|
|
22
|
+
the tenon, the mortise, the rail's cut length and its placement are derived.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
import woodwright as ww
|
|
28
|
+
from woodwright.export import export_model
|
|
29
|
+
|
|
30
|
+
oak = ww.Stock.board(thickness=20, species="oak")
|
|
31
|
+
|
|
32
|
+
frame = ww.Assembly("corner", root_location=ww.orient(right_end=ww.UP, back_edge=ww.RIGHT))
|
|
33
|
+
stile = frame.add(ww.Board("stile", oak, length=600, width=60))
|
|
34
|
+
rail = frame.add(ww.Board("rail", oak, length=300, width=60)) # shoulder to shoulder
|
|
35
|
+
frame.join(ww.MortiseTenon(tenon=rail.left_end, mortise=stile.back_edge))
|
|
36
|
+
|
|
37
|
+
model = frame.resolve()
|
|
38
|
+
print(model.cut_list())
|
|
39
|
+
export_model(model, Path("output/corner")) # STEP, STL, SVG views, cut list
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
stile 600 x 60 x 20 mm oak
|
|
44
|
+
- mortise 50 x 8 mm, 42 deep, in stile.back_edge
|
|
45
|
+
rail 340 x 60 x 20 mm oak
|
|
46
|
+
- tenon 50 x 8 mm, 40 long, on rail.left_end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Cuts and joints so far: grooves, dados, rabbets, mortises, tenons (haunched,
|
|
50
|
+
mitred), chamfers, mitres, tapers; butt, dado, rabbet, groove, tongue and
|
|
51
|
+
groove, mortise and tenon, bridle, half lap, cross lap, mitre corners and
|
|
52
|
+
splices, sliding, through and half-blind dovetails, and table-top buttons.
|
|
53
|
+
|
|
54
|
+
## Example library
|
|
55
|
+
|
|
56
|
+
`woodwright.examples` holds over fifty examples, from single cuts through
|
|
57
|
+
joints to projects: a try square, a mallet, a bookshelf, a dovetailed drawer
|
|
58
|
+
with a bottom, a dining table.
|
|
59
|
+
|
|
60
|
+
```shell
|
|
61
|
+
python -m woodwright.examples list
|
|
62
|
+
python -m woodwright.examples export projects.table --out output
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The design ideas are in [docs/vision.md](https://github.com/bzamecnik/woodwright/blob/HEAD/docs/vision.md)
|
|
66
|
+
and [docs/plan.md](https://github.com/bzamecnik/woodwright/blob/HEAD/docs/plan.md).
|
|
67
|
+
|
|
68
|
+
## Development
|
|
69
|
+
|
|
70
|
+
Install the environment and dependencies:
|
|
71
|
+
```shell
|
|
72
|
+
uv sync
|
|
73
|
+
pre-commit install # ruff lint + format on commit
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Optionally, for notebooks with an interactive 3D viewer:
|
|
77
|
+
```shell
|
|
78
|
+
uv sync --group notebook
|
|
79
|
+
uv run jupyter lab
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Run the tests and the linters:
|
|
83
|
+
```shell
|
|
84
|
+
uv run pytest
|
|
85
|
+
uv run ruff format
|
|
86
|
+
uv run ruff check --fix
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
[MIT License](./LICENSE).
|
|
92
|
+
|
|
93
|
+
### Credits
|
|
94
|
+
|
|
95
|
+
- Ideas and guidance: Bohumír Zámečník
|
|
96
|
+
- Most of the implementation: Claude Code (Opus 5.5)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Initial vision
|
|
2
|
+
|
|
3
|
+
Let's design a textual markup language to describe furniture design and construction. For a programmer and hobby woodworker it feels limiting that description of furniture to be designed or documented is purely visual - 2D sketches on paper or possibly 3D CAD models which take a lot work to make in specialized software. It makes it unsuitable to discuss with LLMs, to parametrize, easily work with programmatically, construct, modify or convert into other representations (2D plans, 3D models, images).
|
|
4
|
+
|
|
5
|
+
Furniture is typically composed of pieces which are first shaped from rough lumber to given size and shape, including joints, and then assembled together and surface-finished. Thus, it could be represented as a graph where the pieces are vertices and their joints are edges. Also the shaping process can be expressed this way: individual stages can be vertices, while the shaping operations (cutting, drilling, etc.) can be expressed as edges or a different kind of vertices connected by edges. Similarly for gluing, fastening with screws, nails, finishing, etc. The various vertices or edges can have properties, such as a kind of material, sizes, etc.
|
|
6
|
+
|
|
7
|
+
A crucial aspect is representing shapes. One possible paradigm could be constructive solid geometry (CSG), nicely represented e.g. by OpenSCAD, where shapes can be constructed using text-based representation language. Maybe that is too general for furniture. I guess there can be some standard library where common shapes (in a parametric form) can be represented and then applied in a composable way. For example, there can be a primitive "board" as a cuboid with 3 dimensions (length, width, thickness). It may be possible to apply operations, such as cutting through or partially in some way. Those could be combined to make a shape of a mortice or tenon. Those can be then applied on a board to make e.g. an apron for a table or with different parameter a stretcher. Typically multiple copies of the same shape (maybe with different parameters) may be needed. Then they can be assembled by orienting the pieces and connecting their joints.
|
|
8
|
+
|
|
9
|
+
A construction and assembly process could then be expressed by a graph of shaping and joining those primitive objects.
|
|
10
|
+
|
|
11
|
+
3D modeling software often allows using geometric constraints so that some properties of the shapes can be enforced and some dimensions can be calculated automatically, while others are fixed.
|
|
12
|
+
|
|
13
|
+
The language could be an application of an existing markup language, so that any infrastructure for it can be reused. It should be nicely readable and writable by human. YAML or something similar might be a nice basis.
|
|
14
|
+
|
|
15
|
+
One of the open questions is a coordinate system. Either we can rely one some local cartesian coordinates or try a coordinate-free approach with Geometric Algebra but still keep it approachable for casual users.
|
|
16
|
+
|
|
17
|
+
This opens up door for more advances possibilities, such as static load analysis for safety and material optimization.
|
|
18
|
+
|
|
19
|
+
The original idea comes from 2025-12-11.
|