dkdc-draw 0.1.1__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.
- dkdc_draw-0.1.1/Cargo.toml +20 -0
- dkdc_draw-0.1.1/LICENSE +21 -0
- dkdc_draw-0.1.1/PKG-INFO +134 -0
- dkdc_draw-0.1.1/README.md +111 -0
- dkdc_draw-0.1.1/crates/draw-cli/Cargo.toml +31 -0
- dkdc_draw-0.1.1/crates/draw-cli/README.md +111 -0
- dkdc_draw-0.1.1/crates/draw-cli/src/cli.rs +147 -0
- dkdc_draw-0.1.1/crates/draw-cli/src/lib.rs +16 -0
- dkdc_draw-0.1.1/crates/draw-cli/src/main.rs +3 -0
- dkdc_draw-0.1.1/crates/draw-core/Cargo.toml +25 -0
- dkdc_draw-0.1.1/crates/draw-core/src/document.rs +165 -0
- dkdc_draw-0.1.1/crates/draw-core/src/element.rs +350 -0
- dkdc_draw-0.1.1/crates/draw-core/src/export_png.rs +83 -0
- dkdc_draw-0.1.1/crates/draw-core/src/export_svg.rs +747 -0
- dkdc_draw-0.1.1/crates/draw-core/src/history.rs +166 -0
- dkdc_draw-0.1.1/crates/draw-core/src/lib.rs +21 -0
- dkdc_draw-0.1.1/crates/draw-core/src/point.rs +140 -0
- dkdc_draw-0.1.1/crates/draw-core/src/render.rs +1659 -0
- dkdc_draw-0.1.1/crates/draw-core/src/storage.rs +112 -0
- dkdc_draw-0.1.1/crates/draw-core/src/style.rs +108 -0
- dkdc_draw-0.1.1/crates/draw-py/Cargo.lock +1388 -0
- dkdc_draw-0.1.1/crates/draw-py/Cargo.toml +22 -0
- dkdc_draw-0.1.1/crates/draw-py/src/lib.rs +65 -0
- dkdc_draw-0.1.1/py/dkdc_draw/__init__.py +38 -0
- dkdc_draw-0.1.1/py/dkdc_draw/core.pyi +79 -0
- dkdc_draw-0.1.1/py/dkdc_draw/py.typed +0 -0
- dkdc_draw-0.1.1/pyproject.toml +52 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[workspace]
|
|
2
|
+
resolver = "2"
|
|
3
|
+
members = [
|
|
4
|
+
"crates/draw-core",
|
|
5
|
+
"crates/draw-app",
|
|
6
|
+
"crates/draw-webapp",
|
|
7
|
+
"crates/draw-cli",
|
|
8
|
+
"crates/draw-wasm",
|
|
9
|
+
]
|
|
10
|
+
default-members = [
|
|
11
|
+
"crates/draw-core",
|
|
12
|
+
"crates/draw-cli",
|
|
13
|
+
"crates/draw-wasm",
|
|
14
|
+
]
|
|
15
|
+
exclude = ["crates/draw-py"]
|
|
16
|
+
|
|
17
|
+
[profile.release]
|
|
18
|
+
lto = true
|
|
19
|
+
strip = true
|
|
20
|
+
codegen-units = 1
|
dkdc_draw-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dkdc.io
|
|
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.
|
dkdc_draw-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dkdc-draw
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Rust
|
|
11
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Summary: Local-first drawing tool
|
|
14
|
+
Keywords: graphics,drawing,canvas,sketch
|
|
15
|
+
Home-Page: https://github.com/dkdc-io/draw
|
|
16
|
+
Author-email: Cody <cody@dkdc.io>
|
|
17
|
+
License-Expression: MIT
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
20
|
+
Project-URL: Homepage, https://github.com/dkdc-io/draw
|
|
21
|
+
Project-URL: Repository, https://github.com/dkdc-io/draw
|
|
22
|
+
|
|
23
|
+
# draw
|
|
24
|
+
|
|
25
|
+
Local-first, sketch-style drawing tool. Excalidraw-inspired, built on Rust with a vanilla JS frontend.
|
|
26
|
+
|
|
27
|
+
Single binary. No cloud. Your drawings live in `~/.config/draw/drawings/`.
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- **9 tools**: Select, Rectangle, Ellipse, Diamond, Line, Arrow, Pen (freedraw), Text, Eraser
|
|
32
|
+
- **Sketch-style fills**: hachure (diagonal lines), cross-hatch, solid, none
|
|
33
|
+
- **Full interactions**: drag, resize, multi-select, rubber band, pan (scroll/space+drag), zoom (ctrl+scroll)
|
|
34
|
+
- **Undo/redo**: all operations, including batched multi-element changes
|
|
35
|
+
- **Copy/paste/duplicate** with proper ID remapping
|
|
36
|
+
- **Z-ordering**: bring to front/back/forward/backward
|
|
37
|
+
- **Styles**: stroke color/width/dash, fill color/pattern/density, opacity, font
|
|
38
|
+
- **Export**: SVG and PNG
|
|
39
|
+
- **Document management**: auto-save, dirty indicator, rename, list
|
|
40
|
+
- **Desktop app**: native window via webview (same UI, no browser needed)
|
|
41
|
+
- **Python bindings**: `import dkdc_draw`
|
|
42
|
+
- **Keyboard-driven**: full shortcut set, `?` for help overlay
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
### From source (Rust)
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
cargo install dkdc-draw --features webapp
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### From source (Python)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
uv tool install dkdc-draw
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Development
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
bin/setup # install dependencies
|
|
62
|
+
bin/install # build and install CLI
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
draw --webapp # launch web UI
|
|
69
|
+
draw --app # launch desktop app
|
|
70
|
+
draw new [name] # create new drawing
|
|
71
|
+
draw open <file> # open .draw.json file
|
|
72
|
+
draw list # list saved drawings
|
|
73
|
+
draw export-svg <file> [-o output.svg]
|
|
74
|
+
draw export-png <file> [-o output.png] [--scale 2.0]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Python
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import dkdc_draw
|
|
81
|
+
|
|
82
|
+
doc = dkdc_draw.new_document("sketch")
|
|
83
|
+
dkdc_draw.save_document(doc, "sketch.draw.json")
|
|
84
|
+
svg = dkdc_draw.export_svg(doc)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Keyboard shortcuts
|
|
88
|
+
|
|
89
|
+
| Key | Action |
|
|
90
|
+
|-----|--------|
|
|
91
|
+
| V | Select |
|
|
92
|
+
| R | Rectangle |
|
|
93
|
+
| O | Ellipse |
|
|
94
|
+
| D | Diamond |
|
|
95
|
+
| L | Line |
|
|
96
|
+
| A | Arrow |
|
|
97
|
+
| P | Pen (freedraw) |
|
|
98
|
+
| T | Text |
|
|
99
|
+
| E | Eraser |
|
|
100
|
+
| G | Toggle grid snap |
|
|
101
|
+
| ? | Help overlay |
|
|
102
|
+
| Ctrl+Z | Undo |
|
|
103
|
+
| Ctrl+Shift+Z | Redo |
|
|
104
|
+
| Ctrl+S | Save |
|
|
105
|
+
| Ctrl+A | Select all |
|
|
106
|
+
| Ctrl+D | Duplicate |
|
|
107
|
+
| Delete | Delete selected |
|
|
108
|
+
| ] / [ | Bring to front / Send to back |
|
|
109
|
+
|
|
110
|
+
## Architecture
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
crates/
|
|
114
|
+
draw-core/ Document model, serialization, SVG/PNG export, tiny-skia renderer
|
|
115
|
+
draw-cli/ CLI binary (clap)
|
|
116
|
+
draw-webapp/ Axum web server (port 1213) + embedded vanilla JS frontend
|
|
117
|
+
draw-app/ Desktop app (wry webview)
|
|
118
|
+
draw-wasm/ WASM bindings for the renderer
|
|
119
|
+
draw-py/ PyO3 Python bindings
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Development
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bin/build # build all (Rust + Python)
|
|
126
|
+
bin/check # run all checks (format, lint, test)
|
|
127
|
+
bin/format # format all code
|
|
128
|
+
bin/test # run all tests
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
|
134
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# draw
|
|
2
|
+
|
|
3
|
+
Local-first, sketch-style drawing tool. Excalidraw-inspired, built on Rust with a vanilla JS frontend.
|
|
4
|
+
|
|
5
|
+
Single binary. No cloud. Your drawings live in `~/.config/draw/drawings/`.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **9 tools**: Select, Rectangle, Ellipse, Diamond, Line, Arrow, Pen (freedraw), Text, Eraser
|
|
10
|
+
- **Sketch-style fills**: hachure (diagonal lines), cross-hatch, solid, none
|
|
11
|
+
- **Full interactions**: drag, resize, multi-select, rubber band, pan (scroll/space+drag), zoom (ctrl+scroll)
|
|
12
|
+
- **Undo/redo**: all operations, including batched multi-element changes
|
|
13
|
+
- **Copy/paste/duplicate** with proper ID remapping
|
|
14
|
+
- **Z-ordering**: bring to front/back/forward/backward
|
|
15
|
+
- **Styles**: stroke color/width/dash, fill color/pattern/density, opacity, font
|
|
16
|
+
- **Export**: SVG and PNG
|
|
17
|
+
- **Document management**: auto-save, dirty indicator, rename, list
|
|
18
|
+
- **Desktop app**: native window via webview (same UI, no browser needed)
|
|
19
|
+
- **Python bindings**: `import dkdc_draw`
|
|
20
|
+
- **Keyboard-driven**: full shortcut set, `?` for help overlay
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
### From source (Rust)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cargo install dkdc-draw --features webapp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### From source (Python)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv tool install dkdc-draw
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Development
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bin/setup # install dependencies
|
|
40
|
+
bin/install # build and install CLI
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
draw --webapp # launch web UI
|
|
47
|
+
draw --app # launch desktop app
|
|
48
|
+
draw new [name] # create new drawing
|
|
49
|
+
draw open <file> # open .draw.json file
|
|
50
|
+
draw list # list saved drawings
|
|
51
|
+
draw export-svg <file> [-o output.svg]
|
|
52
|
+
draw export-png <file> [-o output.png] [--scale 2.0]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Python
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import dkdc_draw
|
|
59
|
+
|
|
60
|
+
doc = dkdc_draw.new_document("sketch")
|
|
61
|
+
dkdc_draw.save_document(doc, "sketch.draw.json")
|
|
62
|
+
svg = dkdc_draw.export_svg(doc)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Keyboard shortcuts
|
|
66
|
+
|
|
67
|
+
| Key | Action |
|
|
68
|
+
|-----|--------|
|
|
69
|
+
| V | Select |
|
|
70
|
+
| R | Rectangle |
|
|
71
|
+
| O | Ellipse |
|
|
72
|
+
| D | Diamond |
|
|
73
|
+
| L | Line |
|
|
74
|
+
| A | Arrow |
|
|
75
|
+
| P | Pen (freedraw) |
|
|
76
|
+
| T | Text |
|
|
77
|
+
| E | Eraser |
|
|
78
|
+
| G | Toggle grid snap |
|
|
79
|
+
| ? | Help overlay |
|
|
80
|
+
| Ctrl+Z | Undo |
|
|
81
|
+
| Ctrl+Shift+Z | Redo |
|
|
82
|
+
| Ctrl+S | Save |
|
|
83
|
+
| Ctrl+A | Select all |
|
|
84
|
+
| Ctrl+D | Duplicate |
|
|
85
|
+
| Delete | Delete selected |
|
|
86
|
+
| ] / [ | Bring to front / Send to back |
|
|
87
|
+
|
|
88
|
+
## Architecture
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
crates/
|
|
92
|
+
draw-core/ Document model, serialization, SVG/PNG export, tiny-skia renderer
|
|
93
|
+
draw-cli/ CLI binary (clap)
|
|
94
|
+
draw-webapp/ Axum web server (port 1213) + embedded vanilla JS frontend
|
|
95
|
+
draw-app/ Desktop app (wry webview)
|
|
96
|
+
draw-wasm/ WASM bindings for the renderer
|
|
97
|
+
draw-py/ PyO3 Python bindings
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
bin/build # build all (Rust + Python)
|
|
104
|
+
bin/check # run all checks (format, lint, test)
|
|
105
|
+
bin/format # format all code
|
|
106
|
+
bin/test # run all tests
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "dkdc-draw"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
authors = ["Cody <cody@dkdc.io>"]
|
|
6
|
+
description = "Local-first drawing tool"
|
|
7
|
+
repository = "https://github.com/dkdc-io/draw"
|
|
8
|
+
homepage = "https://github.com/dkdc-io/draw"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
keywords = ["graphics", "drawing", "cli", "sketch"]
|
|
12
|
+
categories = ["graphics", "command-line-utilities"]
|
|
13
|
+
|
|
14
|
+
[lib]
|
|
15
|
+
name = "draw"
|
|
16
|
+
path = "src/lib.rs"
|
|
17
|
+
|
|
18
|
+
[[bin]]
|
|
19
|
+
name = "draw"
|
|
20
|
+
path = "src/main.rs"
|
|
21
|
+
|
|
22
|
+
[features]
|
|
23
|
+
app = ["dep:dkdc-draw-app"]
|
|
24
|
+
webapp = ["dep:dkdc-draw-webapp"]
|
|
25
|
+
|
|
26
|
+
[dependencies]
|
|
27
|
+
anyhow = "1"
|
|
28
|
+
dkdc-draw-core = { version = "0.1.1", path = "../draw-core" }
|
|
29
|
+
dkdc-draw-app = { version = "0.1.1", path = "../draw-app", optional = true }
|
|
30
|
+
dkdc-draw-webapp = { version = "0.1.1", path = "../draw-webapp", optional = true }
|
|
31
|
+
clap = { version = "4.5", features = ["derive"] }
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# draw
|
|
2
|
+
|
|
3
|
+
Local-first, sketch-style drawing tool. Excalidraw-inspired, built on Rust with a vanilla JS frontend.
|
|
4
|
+
|
|
5
|
+
Single binary. No cloud. Your drawings live in `~/.config/draw/drawings/`.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **9 tools**: Select, Rectangle, Ellipse, Diamond, Line, Arrow, Pen (freedraw), Text, Eraser
|
|
10
|
+
- **Sketch-style fills**: hachure (diagonal lines), cross-hatch, solid, none
|
|
11
|
+
- **Full interactions**: drag, resize, multi-select, rubber band, pan (scroll/space+drag), zoom (ctrl+scroll)
|
|
12
|
+
- **Undo/redo**: all operations, including batched multi-element changes
|
|
13
|
+
- **Copy/paste/duplicate** with proper ID remapping
|
|
14
|
+
- **Z-ordering**: bring to front/back/forward/backward
|
|
15
|
+
- **Styles**: stroke color/width/dash, fill color/pattern/density, opacity, font
|
|
16
|
+
- **Export**: SVG and PNG
|
|
17
|
+
- **Document management**: auto-save, dirty indicator, rename, list
|
|
18
|
+
- **Desktop app**: native window via webview (same UI, no browser needed)
|
|
19
|
+
- **Python bindings**: `import dkdc_draw`
|
|
20
|
+
- **Keyboard-driven**: full shortcut set, `?` for help overlay
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
### From source (Rust)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cargo install dkdc-draw --features webapp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### From source (Python)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
uv tool install dkdc-draw
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Development
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bin/setup # install dependencies
|
|
40
|
+
bin/install # build and install CLI
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
draw --webapp # launch web UI
|
|
47
|
+
draw --app # launch desktop app
|
|
48
|
+
draw new [name] # create new drawing
|
|
49
|
+
draw open <file> # open .draw.json file
|
|
50
|
+
draw list # list saved drawings
|
|
51
|
+
draw export-svg <file> [-o output.svg]
|
|
52
|
+
draw export-png <file> [-o output.png] [--scale 2.0]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Python
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import dkdc_draw
|
|
59
|
+
|
|
60
|
+
doc = dkdc_draw.new_document("sketch")
|
|
61
|
+
dkdc_draw.save_document(doc, "sketch.draw.json")
|
|
62
|
+
svg = dkdc_draw.export_svg(doc)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Keyboard shortcuts
|
|
66
|
+
|
|
67
|
+
| Key | Action |
|
|
68
|
+
|-----|--------|
|
|
69
|
+
| V | Select |
|
|
70
|
+
| R | Rectangle |
|
|
71
|
+
| O | Ellipse |
|
|
72
|
+
| D | Diamond |
|
|
73
|
+
| L | Line |
|
|
74
|
+
| A | Arrow |
|
|
75
|
+
| P | Pen (freedraw) |
|
|
76
|
+
| T | Text |
|
|
77
|
+
| E | Eraser |
|
|
78
|
+
| G | Toggle grid snap |
|
|
79
|
+
| ? | Help overlay |
|
|
80
|
+
| Ctrl+Z | Undo |
|
|
81
|
+
| Ctrl+Shift+Z | Redo |
|
|
82
|
+
| Ctrl+S | Save |
|
|
83
|
+
| Ctrl+A | Select all |
|
|
84
|
+
| Ctrl+D | Duplicate |
|
|
85
|
+
| Delete | Delete selected |
|
|
86
|
+
| ] / [ | Bring to front / Send to back |
|
|
87
|
+
|
|
88
|
+
## Architecture
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
crates/
|
|
92
|
+
draw-core/ Document model, serialization, SVG/PNG export, tiny-skia renderer
|
|
93
|
+
draw-cli/ CLI binary (clap)
|
|
94
|
+
draw-webapp/ Axum web server (port 1213) + embedded vanilla JS frontend
|
|
95
|
+
draw-app/ Desktop app (wry webview)
|
|
96
|
+
draw-wasm/ WASM bindings for the renderer
|
|
97
|
+
draw-py/ PyO3 Python bindings
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
bin/build # build all (Rust + Python)
|
|
104
|
+
bin/check # run all checks (format, lint, test)
|
|
105
|
+
bin/format # format all code
|
|
106
|
+
bin/test # run all tests
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
use anyhow::Result;
|
|
2
|
+
use clap::Parser;
|
|
3
|
+
use std::path::PathBuf;
|
|
4
|
+
|
|
5
|
+
use draw_core::document::Document;
|
|
6
|
+
|
|
7
|
+
#[derive(Parser, Debug)]
|
|
8
|
+
#[command(name = "draw")]
|
|
9
|
+
#[command(about = "Local-first drawing tool")]
|
|
10
|
+
#[command(version)]
|
|
11
|
+
pub struct Args {
|
|
12
|
+
/// Open the desktop app
|
|
13
|
+
#[cfg(feature = "app")]
|
|
14
|
+
#[arg(short = 'a', long)]
|
|
15
|
+
pub app: bool,
|
|
16
|
+
|
|
17
|
+
/// Open the webapp
|
|
18
|
+
#[cfg(feature = "webapp")]
|
|
19
|
+
#[arg(short = 'w', long)]
|
|
20
|
+
pub webapp: bool,
|
|
21
|
+
|
|
22
|
+
#[command(subcommand)]
|
|
23
|
+
pub command: Option<Command>,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#[derive(clap::Subcommand, Debug)]
|
|
27
|
+
pub enum Command {
|
|
28
|
+
/// Create a new drawing
|
|
29
|
+
New {
|
|
30
|
+
/// Drawing name
|
|
31
|
+
#[arg(default_value = "untitled")]
|
|
32
|
+
name: String,
|
|
33
|
+
},
|
|
34
|
+
/// Open an existing drawing
|
|
35
|
+
Open {
|
|
36
|
+
/// Path to .draw.json file
|
|
37
|
+
file: PathBuf,
|
|
38
|
+
},
|
|
39
|
+
/// List saved drawings
|
|
40
|
+
List,
|
|
41
|
+
/// Export drawing to SVG
|
|
42
|
+
ExportSvg {
|
|
43
|
+
/// Path to .draw.json file
|
|
44
|
+
file: PathBuf,
|
|
45
|
+
/// Output SVG path (defaults to same name with .svg extension)
|
|
46
|
+
#[arg(short, long)]
|
|
47
|
+
output: Option<PathBuf>,
|
|
48
|
+
},
|
|
49
|
+
/// Export drawing to PNG
|
|
50
|
+
ExportPng {
|
|
51
|
+
/// Path to .draw.json file
|
|
52
|
+
file: PathBuf,
|
|
53
|
+
/// Output PNG path (defaults to same name with .png extension)
|
|
54
|
+
#[arg(short, long)]
|
|
55
|
+
output: Option<PathBuf>,
|
|
56
|
+
/// Scale factor (default: 2x for retina)
|
|
57
|
+
#[arg(short, long, default_value_t = 2.0)]
|
|
58
|
+
scale: f32,
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn run_cli(argv: impl IntoIterator<Item = impl Into<String>>) -> Result<()> {
|
|
63
|
+
let argv: Vec<String> = argv.into_iter().map(Into::into).collect();
|
|
64
|
+
|
|
65
|
+
// No args = help
|
|
66
|
+
if argv.len() <= 1 {
|
|
67
|
+
Args::parse_from(["draw", "--help"]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let args = Args::parse_from(&argv);
|
|
71
|
+
|
|
72
|
+
#[cfg(feature = "app")]
|
|
73
|
+
if args.app {
|
|
74
|
+
return draw_app::run_app(None);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[cfg(feature = "webapp")]
|
|
78
|
+
if args.webapp {
|
|
79
|
+
return draw_webapp::run_webapp(None);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
match args.command {
|
|
83
|
+
Some(Command::New { name }) => {
|
|
84
|
+
let doc = Document::new(name);
|
|
85
|
+
let path = draw_core::storage::save_to_storage(&doc)?;
|
|
86
|
+
println!("Created: {} ({})", doc.name, path.display());
|
|
87
|
+
|
|
88
|
+
#[cfg(feature = "webapp")]
|
|
89
|
+
return draw_webapp::run_webapp(Some(doc.id));
|
|
90
|
+
|
|
91
|
+
#[cfg(not(feature = "webapp"))]
|
|
92
|
+
{
|
|
93
|
+
println!("Run with --webapp to open in browser");
|
|
94
|
+
Ok(())
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
Some(Command::Open { file }) => {
|
|
98
|
+
let doc = draw_core::storage::load(&file)?;
|
|
99
|
+
println!("Loaded: {} ({} elements)", doc.name, doc.elements.len());
|
|
100
|
+
|
|
101
|
+
#[cfg(feature = "webapp")]
|
|
102
|
+
return draw_webapp::run_webapp(Some(doc.id));
|
|
103
|
+
|
|
104
|
+
#[cfg(not(feature = "webapp"))]
|
|
105
|
+
{
|
|
106
|
+
println!("Run with --webapp to open in browser");
|
|
107
|
+
Ok(())
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
Some(Command::List) => {
|
|
111
|
+
let drawings = draw_core::storage::list_drawings()?;
|
|
112
|
+
if drawings.is_empty() {
|
|
113
|
+
println!("No saved drawings.");
|
|
114
|
+
} else {
|
|
115
|
+
for (name, path) in drawings {
|
|
116
|
+
println!(" {} ({})", name, path.display());
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
Ok(())
|
|
120
|
+
}
|
|
121
|
+
Some(Command::ExportSvg { file, output }) => {
|
|
122
|
+
let doc = draw_core::storage::load(&file)?;
|
|
123
|
+
let svg = draw_core::export_svg(&doc);
|
|
124
|
+
let out_path = output.unwrap_or_else(|| file.with_extension("svg"));
|
|
125
|
+
std::fs::write(&out_path, &svg)?;
|
|
126
|
+
println!("Exported SVG to {}", out_path.display());
|
|
127
|
+
Ok(())
|
|
128
|
+
}
|
|
129
|
+
Some(Command::ExportPng {
|
|
130
|
+
file,
|
|
131
|
+
output,
|
|
132
|
+
scale,
|
|
133
|
+
}) => {
|
|
134
|
+
let doc = draw_core::storage::load(&file)?;
|
|
135
|
+
let png = draw_core::export_png_with_scale(&doc, scale)?;
|
|
136
|
+
let out_path = output.unwrap_or_else(|| file.with_extension("png"));
|
|
137
|
+
std::fs::write(&out_path, &png)?;
|
|
138
|
+
println!("Exported PNG to {}", out_path.display());
|
|
139
|
+
Ok(())
|
|
140
|
+
}
|
|
141
|
+
None => {
|
|
142
|
+
// No subcommand but also no flags = help
|
|
143
|
+
Args::parse_from(["draw", "--help"]);
|
|
144
|
+
unreachable!()
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
pub mod cli;
|
|
2
|
+
|
|
3
|
+
pub use cli::run_cli;
|
|
4
|
+
pub use draw_core::{
|
|
5
|
+
document::Document,
|
|
6
|
+
element::{Element, FreeDrawElement, LineElement, ShapeElement, TextElement},
|
|
7
|
+
export_png, export_png_with_scale, export_svg,
|
|
8
|
+
point::{Bounds, Point, ViewState},
|
|
9
|
+
render::{HandlePosition, RenderConfig, Renderer},
|
|
10
|
+
storage,
|
|
11
|
+
style::{
|
|
12
|
+
Arrowhead, DEFAULT_FILL_COLOR, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE,
|
|
13
|
+
DEFAULT_HACHURE_ANGLE, DEFAULT_HACHURE_GAP, DEFAULT_STROKE_COLOR, DEFAULT_STROKE_WIDTH,
|
|
14
|
+
FillStyle, FillType, FontStyle, StrokeStyle, TextAlign,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "dkdc-draw-core"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
edition = "2024"
|
|
5
|
+
authors = ["Cody <cody@dkdc.io>"]
|
|
6
|
+
description = "Core library for draw"
|
|
7
|
+
repository = "https://github.com/dkdc-io/draw"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
|
|
10
|
+
[lib]
|
|
11
|
+
name = "draw_core"
|
|
12
|
+
path = "src/lib.rs"
|
|
13
|
+
|
|
14
|
+
[dependencies]
|
|
15
|
+
anyhow = "1"
|
|
16
|
+
chrono = { version = "0.4", features = ["serde"] }
|
|
17
|
+
dirs = "6"
|
|
18
|
+
resvg = "0.47"
|
|
19
|
+
serde = { version = "1", features = ["derive"] }
|
|
20
|
+
serde_json = "1"
|
|
21
|
+
tiny-skia = "0.12"
|
|
22
|
+
uuid = { version = "1", features = ["v4"] }
|
|
23
|
+
|
|
24
|
+
[dev-dependencies]
|
|
25
|
+
tempfile = "3"
|