MertCapkin-GraphCraft 0.1.1__tar.gz → 2.0.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.
- {mertcapkin_graphcraft-0.1.1/scripts/MertCapkin_GraphCraft.egg-info → mertcapkin_graphcraft-2.0.0}/PKG-INFO +20 -5
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/README.md +16 -3
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/pyproject.toml +3 -2
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0/scripts/MertCapkin_GraphCraft.egg-info}/PKG-INFO +20 -5
- mertcapkin_graphcraft-2.0.0/scripts/MertCapkin_GraphCraft.egg-info/SOURCES.txt +104 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/MertCapkin_GraphCraft.egg-info/requires.txt +4 -1
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/__init__.py +2 -2
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/aesthetic/__init__.py +1 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/aesthetic/cli.py +79 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/aesthetic/config_loader.py +47 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/aesthetic/contrast.py +49 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/aesthetic/evaluate.py +384 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/aesthetic/research.py +123 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/.cursor/rules/graphcraft.mdc +4 -3
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/.cursor/skills/stitch-import/STITCH_IMPORT.md +34 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/.cursor/skills/visual-review/VISUAL_REVIEW.md +47 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/.graphcraft-assets-version +1 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/design/screens/login.example.yaml +2 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/design-system/components/button.example.yaml +1 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/handoff/DESIGN_BRIEF.md +1 -1
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/orchestrator/GRAPHCRAFT.md +12 -8
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/README.md +26 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/flutter/README.md +13 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/flutter/lib/components/button_primary.dart +50 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/flutter/lib/graphcraft_ui_core.dart +5 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/flutter/lib/screens/login_screen.dart +42 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/flutter/lib/tokens.dart +19 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/flutter/pubspec.yaml +15 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/godot/README.md +15 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/godot/components/button_primary.gd +26 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/godot/plugin.cfg +7 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/godot/plugin.gd +8 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/godot/screens/login_screen.gd +31 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/godot/tokens.gd +16 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/README.md +31 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/package.json +16 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/src/components/ButtonPrimary.tsx +75 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/src/components/index.ts +2 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/src/index.ts +7 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/src/screens/LoginScreen.tsx +29 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/src/theme.ts +23 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/src/tokens.ts +35 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/rn/tsconfig.json +14 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/unity/GraphCraft.UI.asmdef +14 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/unity/README.md +15 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/unity/Runtime/Components/ButtonPrimary.cs +45 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/unity/Runtime/Screens/LoginScreen.cs +41 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packages/ui-core/unity/Runtime/Tokens/DesignTokens.cs +18 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/assets/packs/styles/warm-light/style.yaml +18 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/cli.py +20 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/constants.py +10 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/cycle/__init__.py +1 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/cycle/cli.py +205 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/design_audit.py +70 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/design_brief_utils.py +44 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/design_graph/bridge.py +278 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/design_graph/builder.py +1 -1
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/design_graph/cli.py +203 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/design_graph/query.py +283 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/design_state.py +68 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/gate_cmd.py +147 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/stitch/fetch.py +53 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/stitch/import_cmd.py +126 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/stitch/mcp.py +106 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/stitch/validate.py +99 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/ui/__init__.py +1 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/ui/cli.py +65 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/ui/tokens_emit.py +216 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/ui/validate.py +211 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/visual/__init__.py +1 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/visual/cli.py +57 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/visual/png_utils.py +79 -0
- mertcapkin_graphcraft-2.0.0/scripts/graphcraft/visual/review.py +215 -0
- mertcapkin_graphcraft-0.1.1/scripts/MertCapkin_GraphCraft.egg-info/SOURCES.txt +0 -53
- mertcapkin_graphcraft-0.1.1/scripts/graphcraft/assets/.cursor/skills/stitch-import/STITCH_IMPORT.md +0 -25
- mertcapkin_graphcraft-0.1.1/scripts/graphcraft/assets/.cursor/skills/visual-review/VISUAL_REVIEW.md +0 -20
- mertcapkin_graphcraft-0.1.1/scripts/graphcraft/assets/.graphcraft-assets-version +0 -1
- mertcapkin_graphcraft-0.1.1/scripts/graphcraft/assets/packages/ui-core/README.md +0 -23
- mertcapkin_graphcraft-0.1.1/scripts/graphcraft/design_graph/cli.py +0 -83
- mertcapkin_graphcraft-0.1.1/scripts/graphcraft/design_graph/query.py +0 -81
- mertcapkin_graphcraft-0.1.1/scripts/graphcraft/stitch/import_cmd.py +0 -68
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/LICENSE +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/MANIFEST.in +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/MertCapkin_GraphCraft.egg-info/dependency_links.txt +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/MertCapkin_GraphCraft.egg-info/entry_points.txt +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/MertCapkin_GraphCraft.egg-info/top_level.txt +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/__main__.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/.cursor/commands/graphcraft.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/.cursor/skills/design-strategist/DESIGN_STRATEGIST.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/.cursor/skills/designer/DESIGNER.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/.cursor/skills/mobile-app/MOBILE_APP.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/.cursor/skills/mobile-game/MOBILE_GAME.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/.stitch/metadata.template.json +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/design-system/tokens.base.json +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/design-system/tokens.json +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/graphcraft.config.yaml +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/handoff/AESTHETIC_BRIEF.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/packages/assets/README.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/packs/mobile-app/STACKS.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/packs/mobile-game/STACKS.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/packs/stitch/README.md +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/assets/packs/styles/minimal-dark/style.yaml +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/bootstrap.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/design_graph/__init__.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/design_graph/harmony.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/design_graph/report.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/design_graph/schema.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/design_graph/stitch_adapter.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/doctor.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/init_cmd.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/installer.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/stitch/__init__.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/scripts/graphcraft/stitch/cli.py +0 -0
- {mertcapkin_graphcraft-0.1.1 → mertcapkin_graphcraft-2.0.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MertCapkin_GraphCraft
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Mobile game/app design layer on GraphStack — design graph, style packs, aesthetic engine
|
|
5
5
|
Author: GraphCraft contributors
|
|
6
6
|
License: MIT
|
|
@@ -22,10 +22,12 @@ Provides-Extra: graphstack
|
|
|
22
22
|
Requires-Dist: MertCapkin_GraphStack[graphify]<5,>=4.7; extra == "graphstack"
|
|
23
23
|
Provides-Extra: graphify
|
|
24
24
|
Requires-Dist: graphifyy<0.9,>=0.7; extra == "graphify"
|
|
25
|
+
Provides-Extra: visual
|
|
26
|
+
Requires-Dist: pillow>=9; extra == "visual"
|
|
25
27
|
Provides-Extra: dev
|
|
26
28
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
27
29
|
Provides-Extra: full
|
|
28
|
-
Requires-Dist: MertCapkin_GraphCraft[dev,graphify,graphstack]; extra == "full"
|
|
30
|
+
Requires-Dist: MertCapkin_GraphCraft[dev,graphify,graphstack,visual]; extra == "full"
|
|
29
31
|
Dynamic: license-file
|
|
30
32
|
|
|
31
33
|
<div align="center">
|
|
@@ -56,16 +58,22 @@ GraphCraft → design layer (graphcraft-out/, design-system/)
|
|
|
56
58
|
|
|
57
59
|
**Requirements:** Python 3.8+, Git, [Cursor](https://cursor.sh)
|
|
58
60
|
|
|
59
|
-
### Install (PyPI
|
|
61
|
+
### Install (PyPI)
|
|
60
62
|
|
|
61
63
|
```powershell
|
|
62
64
|
pip install "MertCapkin_GraphCraft[graphstack]"
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
For visual review and aesthetic PNG checks, add the `visual` extra:
|
|
66
68
|
|
|
67
69
|
```powershell
|
|
68
|
-
pip install "MertCapkin_GraphCraft[graphstack]
|
|
70
|
+
pip install "MertCapkin_GraphCraft[graphstack,visual]"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Install (GitHub)
|
|
74
|
+
|
|
75
|
+
```powershell
|
|
76
|
+
pip install "MertCapkin_GraphCraft[graphstack] @ git+https://github.com/MertCapkin/GraphCraft.git@v2.0.0"
|
|
69
77
|
```
|
|
70
78
|
|
|
71
79
|
GraphStack + Graphify install automatically via the `[graphstack]` extra from PyPI.
|
|
@@ -156,7 +164,14 @@ Full detail: [docs/FLOW.md](docs/FLOW.md) · [orchestrator/GRAPHCRAFT.md](orches
|
|
|
156
164
|
| `graphcraft design query "screens"` | GraphCraft | Query design graph |
|
|
157
165
|
| `graphcraft design validate` | GraphCraft | Validate design graph |
|
|
158
166
|
| `graphcraft design harmony` | GraphCraft | Component harmony check |
|
|
167
|
+
| `graphcraft design evaluate` | GraphCraft | Aesthetic rubric (contrast, touch targets) |
|
|
168
|
+
| `graphcraft design bridge` | GraphCraft | Design ↔ code bridge map |
|
|
159
169
|
| `graphcraft stitch import .` | GraphCraft | Import Stitch prototype |
|
|
170
|
+
| `graphcraft stitch mcp install` | GraphCraft | Stitch MCP for Cursor |
|
|
171
|
+
| `graphcraft visual review` | GraphCraft | PNG reference vs implementation |
|
|
172
|
+
| `graphcraft ui validate all` | GraphCraft | Validate UI lib vs design tokens |
|
|
173
|
+
| `graphcraft cycle status` | GraphCraft | Design phase + GraphStack role |
|
|
174
|
+
| `graphcraft gate check` | GraphCraft | Design gate before ui-core edits |
|
|
160
175
|
| `python -m graphstack cycle start …` | GraphStack | Start dev cycle |
|
|
161
176
|
| `python -m graphstack graph query "…"` | GraphStack | Query code graph |
|
|
162
177
|
|
|
@@ -26,16 +26,22 @@ GraphCraft → design layer (graphcraft-out/, design-system/)
|
|
|
26
26
|
|
|
27
27
|
**Requirements:** Python 3.8+, Git, [Cursor](https://cursor.sh)
|
|
28
28
|
|
|
29
|
-
### Install (PyPI
|
|
29
|
+
### Install (PyPI)
|
|
30
30
|
|
|
31
31
|
```powershell
|
|
32
32
|
pip install "MertCapkin_GraphCraft[graphstack]"
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
For visual review and aesthetic PNG checks, add the `visual` extra:
|
|
36
36
|
|
|
37
37
|
```powershell
|
|
38
|
-
pip install "MertCapkin_GraphCraft[graphstack]
|
|
38
|
+
pip install "MertCapkin_GraphCraft[graphstack,visual]"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Install (GitHub)
|
|
42
|
+
|
|
43
|
+
```powershell
|
|
44
|
+
pip install "MertCapkin_GraphCraft[graphstack] @ git+https://github.com/MertCapkin/GraphCraft.git@v2.0.0"
|
|
39
45
|
```
|
|
40
46
|
|
|
41
47
|
GraphStack + Graphify install automatically via the `[graphstack]` extra from PyPI.
|
|
@@ -126,7 +132,14 @@ Full detail: [docs/FLOW.md](docs/FLOW.md) · [orchestrator/GRAPHCRAFT.md](orches
|
|
|
126
132
|
| `graphcraft design query "screens"` | GraphCraft | Query design graph |
|
|
127
133
|
| `graphcraft design validate` | GraphCraft | Validate design graph |
|
|
128
134
|
| `graphcraft design harmony` | GraphCraft | Component harmony check |
|
|
135
|
+
| `graphcraft design evaluate` | GraphCraft | Aesthetic rubric (contrast, touch targets) |
|
|
136
|
+
| `graphcraft design bridge` | GraphCraft | Design ↔ code bridge map |
|
|
129
137
|
| `graphcraft stitch import .` | GraphCraft | Import Stitch prototype |
|
|
138
|
+
| `graphcraft stitch mcp install` | GraphCraft | Stitch MCP for Cursor |
|
|
139
|
+
| `graphcraft visual review` | GraphCraft | PNG reference vs implementation |
|
|
140
|
+
| `graphcraft ui validate all` | GraphCraft | Validate UI lib vs design tokens |
|
|
141
|
+
| `graphcraft cycle status` | GraphCraft | Design phase + GraphStack role |
|
|
142
|
+
| `graphcraft gate check` | GraphCraft | Design gate before ui-core edits |
|
|
130
143
|
| `python -m graphstack cycle start …` | GraphStack | Start dev cycle |
|
|
131
144
|
| `python -m graphstack graph query "…"` | GraphStack | Query code graph |
|
|
132
145
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "MertCapkin_GraphCraft"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "2.0.0"
|
|
8
8
|
description = "Mobile game/app design layer on GraphStack — design graph, style packs, aesthetic engine"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -24,8 +24,9 @@ dependencies = ["pyyaml>=6"]
|
|
|
24
24
|
[project.optional-dependencies]
|
|
25
25
|
graphstack = ["MertCapkin_GraphStack[graphify]>=4.7,<5"]
|
|
26
26
|
graphify = ["graphifyy>=0.7,<0.9"]
|
|
27
|
+
visual = ["pillow>=9"]
|
|
27
28
|
dev = ["pytest>=7"]
|
|
28
|
-
full = ["MertCapkin_GraphCraft[graphstack,graphify,dev]"]
|
|
29
|
+
full = ["MertCapkin_GraphCraft[graphstack,graphify,visual,dev]"]
|
|
29
30
|
|
|
30
31
|
[project.urls]
|
|
31
32
|
Homepage = "https://github.com/MertCapkin/GraphCraft"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MertCapkin_GraphCraft
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Mobile game/app design layer on GraphStack — design graph, style packs, aesthetic engine
|
|
5
5
|
Author: GraphCraft contributors
|
|
6
6
|
License: MIT
|
|
@@ -22,10 +22,12 @@ Provides-Extra: graphstack
|
|
|
22
22
|
Requires-Dist: MertCapkin_GraphStack[graphify]<5,>=4.7; extra == "graphstack"
|
|
23
23
|
Provides-Extra: graphify
|
|
24
24
|
Requires-Dist: graphifyy<0.9,>=0.7; extra == "graphify"
|
|
25
|
+
Provides-Extra: visual
|
|
26
|
+
Requires-Dist: pillow>=9; extra == "visual"
|
|
25
27
|
Provides-Extra: dev
|
|
26
28
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
27
29
|
Provides-Extra: full
|
|
28
|
-
Requires-Dist: MertCapkin_GraphCraft[dev,graphify,graphstack]; extra == "full"
|
|
30
|
+
Requires-Dist: MertCapkin_GraphCraft[dev,graphify,graphstack,visual]; extra == "full"
|
|
29
31
|
Dynamic: license-file
|
|
30
32
|
|
|
31
33
|
<div align="center">
|
|
@@ -56,16 +58,22 @@ GraphCraft → design layer (graphcraft-out/, design-system/)
|
|
|
56
58
|
|
|
57
59
|
**Requirements:** Python 3.8+, Git, [Cursor](https://cursor.sh)
|
|
58
60
|
|
|
59
|
-
### Install (PyPI
|
|
61
|
+
### Install (PyPI)
|
|
60
62
|
|
|
61
63
|
```powershell
|
|
62
64
|
pip install "MertCapkin_GraphCraft[graphstack]"
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
For visual review and aesthetic PNG checks, add the `visual` extra:
|
|
66
68
|
|
|
67
69
|
```powershell
|
|
68
|
-
pip install "MertCapkin_GraphCraft[graphstack]
|
|
70
|
+
pip install "MertCapkin_GraphCraft[graphstack,visual]"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Install (GitHub)
|
|
74
|
+
|
|
75
|
+
```powershell
|
|
76
|
+
pip install "MertCapkin_GraphCraft[graphstack] @ git+https://github.com/MertCapkin/GraphCraft.git@v2.0.0"
|
|
69
77
|
```
|
|
70
78
|
|
|
71
79
|
GraphStack + Graphify install automatically via the `[graphstack]` extra from PyPI.
|
|
@@ -156,7 +164,14 @@ Full detail: [docs/FLOW.md](docs/FLOW.md) · [orchestrator/GRAPHCRAFT.md](orches
|
|
|
156
164
|
| `graphcraft design query "screens"` | GraphCraft | Query design graph |
|
|
157
165
|
| `graphcraft design validate` | GraphCraft | Validate design graph |
|
|
158
166
|
| `graphcraft design harmony` | GraphCraft | Component harmony check |
|
|
167
|
+
| `graphcraft design evaluate` | GraphCraft | Aesthetic rubric (contrast, touch targets) |
|
|
168
|
+
| `graphcraft design bridge` | GraphCraft | Design ↔ code bridge map |
|
|
159
169
|
| `graphcraft stitch import .` | GraphCraft | Import Stitch prototype |
|
|
170
|
+
| `graphcraft stitch mcp install` | GraphCraft | Stitch MCP for Cursor |
|
|
171
|
+
| `graphcraft visual review` | GraphCraft | PNG reference vs implementation |
|
|
172
|
+
| `graphcraft ui validate all` | GraphCraft | Validate UI lib vs design tokens |
|
|
173
|
+
| `graphcraft cycle status` | GraphCraft | Design phase + GraphStack role |
|
|
174
|
+
| `graphcraft gate check` | GraphCraft | Design gate before ui-core edits |
|
|
160
175
|
| `python -m graphstack cycle start …` | GraphStack | Start dev cycle |
|
|
161
176
|
| `python -m graphstack graph query "…"` | GraphStack | Query code graph |
|
|
162
177
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
scripts/MertCapkin_GraphCraft.egg-info/PKG-INFO
|
|
6
|
+
scripts/MertCapkin_GraphCraft.egg-info/SOURCES.txt
|
|
7
|
+
scripts/MertCapkin_GraphCraft.egg-info/dependency_links.txt
|
|
8
|
+
scripts/MertCapkin_GraphCraft.egg-info/entry_points.txt
|
|
9
|
+
scripts/MertCapkin_GraphCraft.egg-info/requires.txt
|
|
10
|
+
scripts/MertCapkin_GraphCraft.egg-info/top_level.txt
|
|
11
|
+
scripts/graphcraft/__init__.py
|
|
12
|
+
scripts/graphcraft/__main__.py
|
|
13
|
+
scripts/graphcraft/bootstrap.py
|
|
14
|
+
scripts/graphcraft/cli.py
|
|
15
|
+
scripts/graphcraft/constants.py
|
|
16
|
+
scripts/graphcraft/design_audit.py
|
|
17
|
+
scripts/graphcraft/design_brief_utils.py
|
|
18
|
+
scripts/graphcraft/design_state.py
|
|
19
|
+
scripts/graphcraft/doctor.py
|
|
20
|
+
scripts/graphcraft/gate_cmd.py
|
|
21
|
+
scripts/graphcraft/init_cmd.py
|
|
22
|
+
scripts/graphcraft/installer.py
|
|
23
|
+
scripts/graphcraft/aesthetic/__init__.py
|
|
24
|
+
scripts/graphcraft/aesthetic/cli.py
|
|
25
|
+
scripts/graphcraft/aesthetic/config_loader.py
|
|
26
|
+
scripts/graphcraft/aesthetic/contrast.py
|
|
27
|
+
scripts/graphcraft/aesthetic/evaluate.py
|
|
28
|
+
scripts/graphcraft/aesthetic/research.py
|
|
29
|
+
scripts/graphcraft/assets/.graphcraft-assets-version
|
|
30
|
+
scripts/graphcraft/assets/graphcraft.config.yaml
|
|
31
|
+
scripts/graphcraft/assets/.cursor/commands/graphcraft.md
|
|
32
|
+
scripts/graphcraft/assets/.cursor/rules/graphcraft.mdc
|
|
33
|
+
scripts/graphcraft/assets/.cursor/skills/design-strategist/DESIGN_STRATEGIST.md
|
|
34
|
+
scripts/graphcraft/assets/.cursor/skills/designer/DESIGNER.md
|
|
35
|
+
scripts/graphcraft/assets/.cursor/skills/mobile-app/MOBILE_APP.md
|
|
36
|
+
scripts/graphcraft/assets/.cursor/skills/mobile-game/MOBILE_GAME.md
|
|
37
|
+
scripts/graphcraft/assets/.cursor/skills/stitch-import/STITCH_IMPORT.md
|
|
38
|
+
scripts/graphcraft/assets/.cursor/skills/visual-review/VISUAL_REVIEW.md
|
|
39
|
+
scripts/graphcraft/assets/.stitch/metadata.template.json
|
|
40
|
+
scripts/graphcraft/assets/design-system/tokens.base.json
|
|
41
|
+
scripts/graphcraft/assets/design-system/tokens.json
|
|
42
|
+
scripts/graphcraft/assets/design-system/components/button.example.yaml
|
|
43
|
+
scripts/graphcraft/assets/design/screens/login.example.yaml
|
|
44
|
+
scripts/graphcraft/assets/handoff/AESTHETIC_BRIEF.md
|
|
45
|
+
scripts/graphcraft/assets/handoff/DESIGN_BRIEF.md
|
|
46
|
+
scripts/graphcraft/assets/orchestrator/GRAPHCRAFT.md
|
|
47
|
+
scripts/graphcraft/assets/packages/assets/README.md
|
|
48
|
+
scripts/graphcraft/assets/packages/ui-core/README.md
|
|
49
|
+
scripts/graphcraft/assets/packages/ui-core/flutter/README.md
|
|
50
|
+
scripts/graphcraft/assets/packages/ui-core/flutter/pubspec.yaml
|
|
51
|
+
scripts/graphcraft/assets/packages/ui-core/flutter/lib/graphcraft_ui_core.dart
|
|
52
|
+
scripts/graphcraft/assets/packages/ui-core/flutter/lib/tokens.dart
|
|
53
|
+
scripts/graphcraft/assets/packages/ui-core/flutter/lib/components/button_primary.dart
|
|
54
|
+
scripts/graphcraft/assets/packages/ui-core/flutter/lib/screens/login_screen.dart
|
|
55
|
+
scripts/graphcraft/assets/packages/ui-core/godot/README.md
|
|
56
|
+
scripts/graphcraft/assets/packages/ui-core/godot/plugin.cfg
|
|
57
|
+
scripts/graphcraft/assets/packages/ui-core/godot/plugin.gd
|
|
58
|
+
scripts/graphcraft/assets/packages/ui-core/godot/tokens.gd
|
|
59
|
+
scripts/graphcraft/assets/packages/ui-core/godot/components/button_primary.gd
|
|
60
|
+
scripts/graphcraft/assets/packages/ui-core/godot/screens/login_screen.gd
|
|
61
|
+
scripts/graphcraft/assets/packages/ui-core/rn/README.md
|
|
62
|
+
scripts/graphcraft/assets/packages/ui-core/rn/package.json
|
|
63
|
+
scripts/graphcraft/assets/packages/ui-core/rn/tsconfig.json
|
|
64
|
+
scripts/graphcraft/assets/packages/ui-core/rn/src/index.ts
|
|
65
|
+
scripts/graphcraft/assets/packages/ui-core/rn/src/theme.ts
|
|
66
|
+
scripts/graphcraft/assets/packages/ui-core/rn/src/tokens.ts
|
|
67
|
+
scripts/graphcraft/assets/packages/ui-core/rn/src/components/ButtonPrimary.tsx
|
|
68
|
+
scripts/graphcraft/assets/packages/ui-core/rn/src/components/index.ts
|
|
69
|
+
scripts/graphcraft/assets/packages/ui-core/rn/src/screens/LoginScreen.tsx
|
|
70
|
+
scripts/graphcraft/assets/packages/ui-core/unity/GraphCraft.UI.asmdef
|
|
71
|
+
scripts/graphcraft/assets/packages/ui-core/unity/README.md
|
|
72
|
+
scripts/graphcraft/assets/packages/ui-core/unity/Runtime/Components/ButtonPrimary.cs
|
|
73
|
+
scripts/graphcraft/assets/packages/ui-core/unity/Runtime/Screens/LoginScreen.cs
|
|
74
|
+
scripts/graphcraft/assets/packages/ui-core/unity/Runtime/Tokens/DesignTokens.cs
|
|
75
|
+
scripts/graphcraft/assets/packs/mobile-app/STACKS.md
|
|
76
|
+
scripts/graphcraft/assets/packs/mobile-game/STACKS.md
|
|
77
|
+
scripts/graphcraft/assets/packs/stitch/README.md
|
|
78
|
+
scripts/graphcraft/assets/packs/styles/minimal-dark/style.yaml
|
|
79
|
+
scripts/graphcraft/assets/packs/styles/warm-light/style.yaml
|
|
80
|
+
scripts/graphcraft/cycle/__init__.py
|
|
81
|
+
scripts/graphcraft/cycle/cli.py
|
|
82
|
+
scripts/graphcraft/design_graph/__init__.py
|
|
83
|
+
scripts/graphcraft/design_graph/bridge.py
|
|
84
|
+
scripts/graphcraft/design_graph/builder.py
|
|
85
|
+
scripts/graphcraft/design_graph/cli.py
|
|
86
|
+
scripts/graphcraft/design_graph/harmony.py
|
|
87
|
+
scripts/graphcraft/design_graph/query.py
|
|
88
|
+
scripts/graphcraft/design_graph/report.py
|
|
89
|
+
scripts/graphcraft/design_graph/schema.py
|
|
90
|
+
scripts/graphcraft/design_graph/stitch_adapter.py
|
|
91
|
+
scripts/graphcraft/stitch/__init__.py
|
|
92
|
+
scripts/graphcraft/stitch/cli.py
|
|
93
|
+
scripts/graphcraft/stitch/fetch.py
|
|
94
|
+
scripts/graphcraft/stitch/import_cmd.py
|
|
95
|
+
scripts/graphcraft/stitch/mcp.py
|
|
96
|
+
scripts/graphcraft/stitch/validate.py
|
|
97
|
+
scripts/graphcraft/ui/__init__.py
|
|
98
|
+
scripts/graphcraft/ui/cli.py
|
|
99
|
+
scripts/graphcraft/ui/tokens_emit.py
|
|
100
|
+
scripts/graphcraft/ui/validate.py
|
|
101
|
+
scripts/graphcraft/visual/__init__.py
|
|
102
|
+
scripts/graphcraft/visual/cli.py
|
|
103
|
+
scripts/graphcraft/visual/png_utils.py
|
|
104
|
+
scripts/graphcraft/visual/review.py
|
|
@@ -4,10 +4,13 @@ pyyaml>=6
|
|
|
4
4
|
pytest>=7
|
|
5
5
|
|
|
6
6
|
[full]
|
|
7
|
-
MertCapkin_GraphCraft[dev,graphify,graphstack]
|
|
7
|
+
MertCapkin_GraphCraft[dev,graphify,graphstack,visual]
|
|
8
8
|
|
|
9
9
|
[graphify]
|
|
10
10
|
graphifyy<0.9,>=0.7
|
|
11
11
|
|
|
12
12
|
[graphstack]
|
|
13
13
|
MertCapkin_GraphStack[graphify]<5,>=4.7
|
|
14
|
+
|
|
15
|
+
[visual]
|
|
16
|
+
pillow>=9
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""GraphCraft — mobile game/app design layer on GraphStack.
|
|
2
2
|
|
|
3
3
|
Entry point: ``python -m graphcraft <command>``
|
|
4
|
-
Commands: ``init``, ``install``, ``doctor``, ``design``, ``stitch``
|
|
4
|
+
Commands: ``init``, ``install``, ``doctor``, ``design``, ``stitch``, ``aesthetic``, ``visual``, ``ui``, ``cycle``, ``gate``
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "0.
|
|
7
|
+
__version__ = "2.0.0"
|
|
8
8
|
__all__ = ["__version__"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""GraphCraft aesthetic engine."""
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Aesthetic engine CLI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from ..constants import DESIGN_GRAPH_JSON
|
|
10
|
+
from ..design_graph.query import load_graph
|
|
11
|
+
from .evaluate import format_evaluate_summary, run_evaluate, write_aesthetic_report
|
|
12
|
+
from .research import init_inspiration, validate_inspiration
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run(argv: list[str]) -> int:
|
|
16
|
+
if not argv or argv[0] in ("-h", "--help"):
|
|
17
|
+
print("Usage: graphcraft aesthetic <evaluate|research> ...")
|
|
18
|
+
return 0
|
|
19
|
+
|
|
20
|
+
cmd, rest = argv[0], argv[1:]
|
|
21
|
+
|
|
22
|
+
if cmd == "evaluate":
|
|
23
|
+
p = argparse.ArgumentParser(prog="graphcraft aesthetic evaluate")
|
|
24
|
+
p.add_argument("root", nargs="?", default=".")
|
|
25
|
+
p.add_argument("--screen", default=None)
|
|
26
|
+
p.add_argument("--style", default=None)
|
|
27
|
+
p.add_argument("--graph", default=str(DESIGN_GRAPH_JSON))
|
|
28
|
+
args = p.parse_args(rest)
|
|
29
|
+
root = Path(args.root).resolve()
|
|
30
|
+
graph_path = Path(args.graph)
|
|
31
|
+
if not graph_path.is_file():
|
|
32
|
+
print(f"Missing {graph_path} — run: graphcraft design update .")
|
|
33
|
+
return 1
|
|
34
|
+
result = run_evaluate(
|
|
35
|
+
root,
|
|
36
|
+
load_graph(graph_path),
|
|
37
|
+
screen_id=args.screen,
|
|
38
|
+
style_id=args.style,
|
|
39
|
+
)
|
|
40
|
+
report_path = write_aesthetic_report(root, result)
|
|
41
|
+
print(format_evaluate_summary(result))
|
|
42
|
+
print(f" -> {report_path}")
|
|
43
|
+
return 0 if result["overall"] in ("PASS", "WARN") else 1
|
|
44
|
+
|
|
45
|
+
if cmd == "research":
|
|
46
|
+
if not rest or rest[0] in ("-h", "--help"):
|
|
47
|
+
print("Usage: graphcraft aesthetic research <init|validate> [root]")
|
|
48
|
+
return 0
|
|
49
|
+
action = rest[0]
|
|
50
|
+
sub_rest = rest[1:]
|
|
51
|
+
p = argparse.ArgumentParser(prog=f"graphcraft aesthetic research {action}")
|
|
52
|
+
p.add_argument("root", nargs="?", default=".")
|
|
53
|
+
p.add_argument("--force", action="store_true", help="overwrite INSPIRATION.md (init only)")
|
|
54
|
+
args = p.parse_args(sub_rest)
|
|
55
|
+
root = Path(args.root).resolve()
|
|
56
|
+
|
|
57
|
+
if action == "init":
|
|
58
|
+
path = init_inspiration(root, force=args.force)
|
|
59
|
+
print(f"Created {path}")
|
|
60
|
+
return 0
|
|
61
|
+
|
|
62
|
+
if action == "validate":
|
|
63
|
+
issues = validate_inspiration(root)
|
|
64
|
+
if issues:
|
|
65
|
+
for i in issues:
|
|
66
|
+
print(f" ISSUE: {i}")
|
|
67
|
+
return 1
|
|
68
|
+
print("INSPIRATION validation: PASS")
|
|
69
|
+
return 0
|
|
70
|
+
|
|
71
|
+
print(f"Unknown research action: {action}")
|
|
72
|
+
return 1
|
|
73
|
+
|
|
74
|
+
print(f"Unknown aesthetic subcommand: {cmd}")
|
|
75
|
+
return 1
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == "__main__":
|
|
79
|
+
raise SystemExit(run(sys.argv[1:]))
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Load GraphCraft project configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import yaml
|
|
10
|
+
except ImportError:
|
|
11
|
+
yaml = None # type: ignore
|
|
12
|
+
|
|
13
|
+
from ..constants import CONFIG_FILE, STYLES_DIR
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_config(root: Path) -> dict[str, Any]:
|
|
17
|
+
path = root / CONFIG_FILE
|
|
18
|
+
if not path.is_file():
|
|
19
|
+
return {}
|
|
20
|
+
if yaml is None:
|
|
21
|
+
raise RuntimeError("PyYAML required: pip install pyyaml")
|
|
22
|
+
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
|
23
|
+
return data if isinstance(data, dict) else {}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def active_style_id(config: dict[str, Any]) -> str:
|
|
27
|
+
style = (config.get("design") or {}).get("style", "style:minimal-dark")
|
|
28
|
+
return str(style)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def aesthetic_settings(config: dict[str, Any]) -> dict[str, Any]:
|
|
32
|
+
return dict(config.get("aesthetic") or {})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def design_settings(config: dict[str, Any]) -> dict[str, Any]:
|
|
36
|
+
return dict(config.get("design") or {})
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def load_style_pack(root: Path, style_id: str) -> dict[str, Any]:
|
|
40
|
+
if yaml is None:
|
|
41
|
+
raise RuntimeError("PyYAML required: pip install pyyaml")
|
|
42
|
+
slug = style_id.split(":", 1)[-1] if ":" in style_id else style_id
|
|
43
|
+
path = root / STYLES_DIR / slug / "style.yaml"
|
|
44
|
+
if not path.is_file():
|
|
45
|
+
return {}
|
|
46
|
+
data = yaml.safe_load(path.read_text(encoding="utf-8"))
|
|
47
|
+
return data if isinstance(data, dict) else {}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""WCAG contrast helpers for token hex values."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from typing import Tuple
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_HEX_RE = re.compile(r"^#([0-9a-fA-F]{6})$")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def parse_hex(color: str) -> Tuple[float, float, float] | None:
|
|
13
|
+
color = color.strip()
|
|
14
|
+
if not _HEX_RE.match(color):
|
|
15
|
+
return None
|
|
16
|
+
r = int(color[1:3], 16) / 255.0
|
|
17
|
+
g = int(color[3:5], 16) / 255.0
|
|
18
|
+
b = int(color[5:7], 16) / 255.0
|
|
19
|
+
return r, g, b
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _linearize(channel: float) -> float:
|
|
23
|
+
if channel <= 0.03928:
|
|
24
|
+
return channel / 12.92
|
|
25
|
+
return ((channel + 0.055) / 1.055) ** 2.4
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def relative_luminance(rgb: Tuple[float, float, float]) -> float:
|
|
29
|
+
r, g, b = (_linearize(c) for c in rgb)
|
|
30
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def contrast_ratio(foreground: str, background: str) -> float | None:
|
|
34
|
+
fg = parse_hex(foreground)
|
|
35
|
+
bg = parse_hex(background)
|
|
36
|
+
if fg is None or bg is None:
|
|
37
|
+
return None
|
|
38
|
+
l1 = relative_luminance(fg)
|
|
39
|
+
l2 = relative_luminance(bg)
|
|
40
|
+
lighter = max(l1, l2)
|
|
41
|
+
darker = min(l1, l2)
|
|
42
|
+
return (lighter + 0.05) / (darker + 0.05)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def passes_contrast(foreground: str, background: str, minimum: float = 4.5) -> bool | None:
|
|
46
|
+
ratio = contrast_ratio(foreground, background)
|
|
47
|
+
if ratio is None:
|
|
48
|
+
return None
|
|
49
|
+
return ratio >= minimum
|