figkit 0.1.0__py3-none-any.whl

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.
figkit/themes.py ADDED
@@ -0,0 +1,163 @@
1
+ """Ready-made themes. Start from one and ``.derive(...)`` your own."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .style import DEFAULT_THEME, MONO, SERIF, Style, Theme
6
+
7
+ __all__ = ["PAPER", "SLIDE", "DARK", "BLUEPRINT", "MINIMAL", "SOFT", "THEMES",
8
+ "get_theme"]
9
+
10
+ #: Muted, serif-labelled look for LaTeX papers.
11
+ PAPER = DEFAULT_THEME.derive(
12
+ name="paper",
13
+ font_family=SERIF,
14
+ font_size=12,
15
+ color="#111111",
16
+ stroke_width=1.1,
17
+ radius=3,
18
+ palette={
19
+ "text": "#111111", "muted": "#555555", "line": "#222222",
20
+ "surface": "#ffffff", "surface_alt": "#f0f0f0",
21
+ "primary": "#3B6EA5", "primary_soft": "#cfe0f2",
22
+ "accent": "#B5622A", "accent_soft": "#f2dcc9",
23
+ "good": "#3E7C4B", "good_soft": "#d6e8da", "bad": "#A93B3B",
24
+ },
25
+ box=Style(fill="#ffffff", stroke="#222222", stroke_width=1.1,
26
+ padding=(6, 10), radius=3),
27
+ arrow=Style(stroke="#222222", stroke_width=1.1, head_size=7),
28
+ panel=Style(stroke="#888888", stroke_width=0.9, radius=4),
29
+ label=Style(font_size=10.5, color="#333333"),
30
+ styles={
31
+ "block": Style(fill="#f2f2f2", stroke="#111111", stroke_width=1.2),
32
+ "blue": Style(fill="#cfe0f2", stroke="#3B6EA5"),
33
+ "green": Style(fill="#d6e8da", stroke="#3E7C4B"),
34
+ "warm": Style(fill="#f2dcc9", stroke="#B5622A"),
35
+ "ghost": Style(fill="none", stroke="#888888", stroke_dash="dashed"),
36
+ },
37
+ )
38
+
39
+ #: Bigger type and chunkier strokes, for slides and posters.
40
+ SLIDE = DEFAULT_THEME.derive(
41
+ name="slide",
42
+ font_size=19,
43
+ stroke_width=2.2,
44
+ radius=10,
45
+ box=Style(padding=(12, 18), stroke_width=2.2, radius=10),
46
+ arrow=Style(stroke_width=2.4, head_size=12),
47
+ label=Style(font_size=15),
48
+ )
49
+
50
+ #: Light-on-dark, for dark-mode blog posts.
51
+ DARK = DEFAULT_THEME.derive(
52
+ name="dark",
53
+ color="#e8eaed",
54
+ background="#141821",
55
+ stroke_width=1.5,
56
+ palette={
57
+ "text": "#e8eaed", "muted": "#9aa4b2", "line": "#8b95a5",
58
+ "surface": "#1b1f27", "surface_alt": "#252b36",
59
+ "primary": "#7aa2f7", "primary_soft": "#26344f",
60
+ "accent": "#e0af68", "accent_soft": "#3d3222",
61
+ "good": "#9ece6a", "good_soft": "#2b3a25", "bad": "#f7768e",
62
+ },
63
+ box=Style(fill="#252b36", stroke="#8b95a5", color="#e8eaed"),
64
+ text=Style(color="#e8eaed"),
65
+ label=Style(color="#c3cad6"),
66
+ arrow=Style(stroke="#aab4c4"),
67
+ panel=Style(stroke="#4a5364", fill="none"),
68
+ matrix=Style(stroke="#1b1f27"),
69
+ axis=Style(stroke="#9aa4b2"),
70
+ grid=Style(stroke="#333a47"),
71
+ styles={
72
+ "block": Style(fill="#2c3340", stroke="#aab4c4"),
73
+ "blue": Style(fill="#26344f", stroke="#7aa2f7"),
74
+ "green": Style(fill="#2b3a25", stroke="#9ece6a"),
75
+ "warm": Style(fill="#3d3222", stroke="#e0af68"),
76
+ "ghost": Style(fill="none", stroke="#5c6675", stroke_dash="dashed"),
77
+ "card": Style(fill="#222834", stroke="#39414f", radius=12),
78
+ },
79
+ )
80
+
81
+ #: Technical-drawing look: thin monochrome lines on a tinted ground.
82
+ BLUEPRINT = DEFAULT_THEME.derive(
83
+ name="blueprint",
84
+ background="#0b2447",
85
+ font_family=MONO,
86
+ font_size=12,
87
+ color="#dbeafe",
88
+ stroke_width=1.0,
89
+ radius=0,
90
+ palette={"text": "#dbeafe", "line": "#93c5fd", "surface": "#0f2f5c",
91
+ "primary": "#93c5fd", "muted": "#7ea6d8"},
92
+ box=Style(fill="none", stroke="#93c5fd", color="#dbeafe", radius=0),
93
+ arrow=Style(stroke="#93c5fd", head="open", head_size=8),
94
+ panel=Style(stroke="#5b8fc7", stroke_dash="dashed"),
95
+ text=Style(color="#dbeafe"),
96
+ label=Style(color="#bfdbfe", font_size=10),
97
+ styles={
98
+ "block": Style(fill="none", stroke="#93c5fd", stroke_width=1.4),
99
+ "blue": Style(fill="#173f70", stroke="#93c5fd"),
100
+ "green": Style(fill="#134e4a", stroke="#5eead4"),
101
+ "warm": Style(fill="#4a3417", stroke="#fbbf24"),
102
+ "ghost": Style(fill="none", stroke="#5b8fc7", stroke_dash="dashed"),
103
+ "plain": Style(fill="none", stroke="none"),
104
+ "card": Style(fill="none", stroke="#5b8fc7", radius=0),
105
+ },
106
+ )
107
+
108
+ #: No fills, no rounding — just hairlines and text.
109
+ MINIMAL = DEFAULT_THEME.derive(
110
+ name="minimal",
111
+ stroke_width=1.0,
112
+ radius=0,
113
+ box=Style(fill="none", stroke="#111111", stroke_width=1.0, radius=0),
114
+ arrow=Style(stroke="#111111", stroke_width=1.0, head="open", head_size=8),
115
+ panel=Style(stroke="#aaaaaa", stroke_width=0.8, radius=0),
116
+ styles={
117
+ "block": Style(fill="none", stroke="#111111", stroke_width=1.4),
118
+ "blue": Style(fill="none", stroke="#3B6EA5", stroke_width=1.4),
119
+ "green": Style(fill="none", stroke="#3E7C4B", stroke_width=1.4),
120
+ "warm": Style(fill="none", stroke="#B5622A", stroke_width=1.4),
121
+ "ghost": Style(fill="none", stroke="#aaaaaa", stroke_dash="dashed"),
122
+ "plain": Style(fill="none", stroke="none"),
123
+ "card": Style(fill="none", stroke="#cccccc", radius=0),
124
+ },
125
+ )
126
+
127
+ #: Rounded pastel cards with soft shadows, for product / blog diagrams.
128
+ SOFT = DEFAULT_THEME.derive(
129
+ name="soft",
130
+ font_size=14,
131
+ radius=12,
132
+ stroke_width=1.0,
133
+ palette={"surface": "#ffffff", "surface_alt": "#f6f7f9",
134
+ "primary": "#6366f1", "primary_soft": "#e0e7ff",
135
+ "accent": "#f97316", "accent_soft": "#ffedd5",
136
+ "good": "#10b981", "good_soft": "#d1fae5", "line": "#64748b"},
137
+ box=Style(fill="#ffffff", stroke="#e2e5ea", stroke_width=1.0, radius=12,
138
+ padding=(12, 16), shadow={"dy": 2, "blur": 6, "opacity": 0.12}),
139
+ arrow=Style(stroke="#94a3b8", stroke_width=1.6, head="stealth"),
140
+ panel=Style(fill="#f6f7f9", stroke="none", radius=16, padding=20),
141
+ styles={
142
+ "block": Style(fill="#f6f7f9", stroke="#e2e5ea"),
143
+ "blue": Style(fill="#e0e7ff", stroke="#c7d2fe"),
144
+ "green": Style(fill="#d1fae5", stroke="#a7f3d0"),
145
+ "warm": Style(fill="#ffedd5", stroke="#fed7aa"),
146
+ },
147
+ )
148
+
149
+ THEMES = {
150
+ "default": DEFAULT_THEME, "figkit": DEFAULT_THEME,
151
+ "paper": PAPER, "slide": SLIDE, "dark": DARK,
152
+ "blueprint": BLUEPRINT, "minimal": MINIMAL, "soft": SOFT,
153
+ }
154
+
155
+
156
+ def get_theme(name) -> Theme:
157
+ """Look up a built-in theme by name (or pass a Theme straight through)."""
158
+ if isinstance(name, Theme):
159
+ return name
160
+ key = str(name).lower()
161
+ if key not in THEMES:
162
+ raise KeyError(f"unknown theme {name!r}; available: {sorted(THEMES)}")
163
+ return THEMES[key]
@@ -0,0 +1,277 @@
1
+ Metadata-Version: 2.4
2
+ Name: figkit
3
+ Version: 0.1.0
4
+ Summary: Design figures with Python code — boxes, arrows, LaTeX and data, exported to SVG/PNG/PDF/HTML
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/philippspohn/figkit
7
+ Project-URL: Repository, https://github.com/philippspohn/figkit
8
+ Project-URL: Issues, https://github.com/philippspohn/figkit/issues
9
+ Project-URL: Changelog, https://github.com/philippspohn/figkit/blob/main/CHANGELOG.md
10
+ Project-URL: Agent manual, https://github.com/philippspohn/figkit/blob/main/AI_MANUAL.md
11
+ Keywords: svg,figures,diagrams,vector,graphics,latex,publication,illustration,scientific-visualization,matplotlib
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3 :: Only
22
+ Classifier: Topic :: Multimedia :: Graphics
23
+ Classifier: Topic :: Scientific/Engineering :: Visualization
24
+ Classifier: Topic :: Text Processing :: Markup
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: fonttools>=4.30
30
+ Provides-Extra: latex
31
+ Requires-Dist: matplotlib>=3.5; extra == "latex"
32
+ Provides-Extra: export
33
+ Requires-Dist: cairosvg>=2.5; extra == "export"
34
+ Provides-Extra: all
35
+ Requires-Dist: matplotlib>=3.5; extra == "all"
36
+ Requires-Dist: cairosvg>=2.5; extra == "all"
37
+ Provides-Extra: dev
38
+ Requires-Dist: matplotlib>=3.5; extra == "dev"
39
+ Requires-Dist: cairosvg>=2.5; extra == "dev"
40
+ Requires-Dist: pytest>=7.0; extra == "dev"
41
+ Requires-Dist: pyflakes>=3.0; extra == "dev"
42
+ Requires-Dist: build>=1.0; extra == "dev"
43
+ Requires-Dist: twine>=5.0; extra == "dev"
44
+ Dynamic: license-file
45
+
46
+ <p align="center">
47
+ <img src="https://raw.githubusercontent.com/philippspohn/figkit/main/docs/logo.png" alt="figkit" width="180">
48
+ </p>
49
+
50
+ <h1 align="center">figkit</h1>
51
+
52
+ <p align="center">
53
+ <a href="https://pypi.org/project/figkit/"><img alt="PyPI" src="https://img.shields.io/pypi/v/figkit.svg"></a>
54
+ <a href="https://pypi.org/project/figkit/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/figkit.svg"></a>
55
+ <a href="https://github.com/philippspohn/figkit/actions/workflows/ci.yml"><img alt="tests" src="https://github.com/philippspohn/figkit/actions/workflows/ci.yml/badge.svg"></a>
56
+ <a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
57
+ </p>
58
+
59
+ **Design figures with Python code.** Boxes, arrows, LaTeX, images and data —
60
+ laid out precisely, styled by a cascading theme, exported to SVG, PNG, PDF or
61
+ HTML.
62
+
63
+ figkit is for the kind of figure you'd otherwise assemble by hand in Figma or
64
+ draw.io: ML paper pipelines, architecture diagrams, research blog explainers.
65
+ Except it's code, so it's diffable, reproducible, parameterisable — and an LLM
66
+ can write it for you (see [`AI_MANUAL.md`](https://github.com/philippspohn/figkit/blob/main/AI_MANUAL.md)).
67
+
68
+ ```python
69
+ from figkit import *
70
+
71
+ with Figure(pad=24) as fig:
72
+ a = Box("Encoder", style="block", w=120)
73
+ b = Box("Decoder", style="blue").right_of(a, gap=60)
74
+ arrow(a.e, b.w, label="$z$")
75
+
76
+ fig.save("figure.svg")
77
+ fig.save("figure.png", scale=2)
78
+ ```
79
+
80
+ ![quickstart](https://raw.githubusercontent.com/philippspohn/figkit/main/docs/images/00_quickstart.png)
81
+
82
+ **Check your work without looking at it.** `fig.audit()` reports the mistakes
83
+ that are obvious in a picture and invisible in the code — and stays quiet about
84
+ deliberate overlap, so a clean report means something:
85
+
86
+ ```
87
+ >>> print(fig.audit())
88
+ figkit audit: 2 issues (1 overlap, 1 contrast) in 34 elements
89
+ overlap Box('Decoder') covers Text('$z$') (240px², 61% of it) at (196, 41)
90
+ contrast Box('Encoder'): text #dbeafe on #f3f4f6 has contrast 1.1:1 (want 3.0:1) at (60, 17)
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Install
96
+
97
+ ```bash
98
+ pip install figkit # core: layout, shapes, arrows, SVG/HTML export
99
+ pip install "figkit[latex]" # + inline $math$ (matplotlib)
100
+ pip install "figkit[export]" # + PNG/PDF export (cairosvg)
101
+ pip install "figkit[all]" # everything
102
+ ```
103
+
104
+ Only `fonttools` is required — it's what makes text measurement (and therefore
105
+ layout) accurate. The extras degrade rather than break: without `matplotlib`
106
+ an inline `$formula$` is set as plain text with a warning, and without a
107
+ rasteriser `save("f.png")` raises while SVG and HTML keep working. PNG/PDF
108
+ export also accepts `rsvg-convert`, `resvg`, `inkscape` or headless Chromium
109
+ if you'd rather not install cairo.
110
+
111
+ ---
112
+
113
+ ## What it does
114
+
115
+ **Accurate measurement.** figkit reads the actual font file and measures glyph
116
+ advances, so `Box("Feature Extractor")` is exactly as wide as its text plus its
117
+ padding — and everything you place relative to it lands where you expect.
118
+
119
+ **Live anchors.** `box.e` is a reference, not a coordinate. Move the box and
120
+ every arrow attached to it follows.
121
+
122
+ ```python
123
+ b = Box("model").right_of(a, gap=40)
124
+ link = arrow(a.e, b.w)
125
+ b.move(0, 120) # the arrow follows
126
+ ```
127
+
128
+ **Explicit placement, not auto-layout.** You say where things go; figkit does
129
+ the arithmetic.
130
+
131
+ ```python
132
+ fm = Box("$F_M$").right_of(extractor, gap=24, align="top")
133
+ fn = Box("$F_N$").right_of(extractor, gap=24, align="bottom")
134
+ solver = Box("FMap Solver", style="blue").right_of(fm, gap=40)
135
+
136
+ elbow(fm.e, solver.w, stub=12) # -| routing
137
+ mid = between(fm, fn) # vertically between two boxes
138
+ frame = fit(solver, cmn, pad=20, label="Fused operation", dash=True)
139
+ ```
140
+
141
+ **Cascading themes.** Base tokens, per-role overrides, CSS-style classes and a
142
+ colour palette — set once, applied everywhere.
143
+
144
+ ```python
145
+ T = PAPER.derive(
146
+ font_size=13, radius=4,
147
+ palette={"brand": "#3B6EA5"},
148
+ box=Style(fill="#ffffff", stroke="#222222", padding=(9, 13)),
149
+ styles={"solver": Style(fill="@brand", stroke="#1b1b1b")},
150
+ )
151
+ with Figure(theme=T) as fig:
152
+ Box("FMap Solver", classes="solver") # or style="solver block"
153
+ ```
154
+
155
+ Classes resolve lazily against whichever theme is in scope, so the same class
156
+ can mean different things inside a differently themed group.
157
+
158
+ **LaTeX anywhere.** Any `$...$` span in any string is typeset and emitted as
159
+ vector outlines, so exported files don't depend on installed fonts.
160
+
161
+ ```python
162
+ Box("$C_{\\mathcal{MN}} = \\phi^{\\dagger}_{\\mathcal{N}}\\Pi_{\\mathcal{NM}}\\phi_{\\mathcal{M}}$")
163
+ ```
164
+
165
+ **Data is just Python.** A `Frame` maps data coordinates to figure
166
+ coordinates; every mark it draws is an ordinary element you can anchor to.
167
+
168
+ ```python
169
+ fr = Frame(w=430, h=240, xlim=(0, 50), ylim=(0.35, 1.0))
170
+ fr.axes(xlabel="epoch", ylabel="accuracy", grid=True)
171
+ fr.line(xs, ys, stroke="@primary", lw=2)
172
+ arrow(note.se, fr.pt(50, 0.94)) # point at a data coordinate
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Gallery
178
+
179
+ Each figure below is produced by the script of the same name in
180
+ [`examples/`](https://github.com/philippspohn/figkit/tree/main/examples). The
181
+ first two are figkit reproductions of published figures, linked as reference —
182
+ they are not affiliated with or endorsed by their authors.
183
+
184
+ ### `01_pipeline.py` — an ML paper pipeline
185
+
186
+ Themes, relative placement, live anchors, inline LaTeX, colour matrices,
187
+ elbow routing and hand-built vector graphics. After the pipeline figure in
188
+ [URSSM](https://dongliangcao.github.io/urssm/).
189
+
190
+ ![pipeline](https://raw.githubusercontent.com/philippspohn/figkit/main/docs/images/01_pipeline.png)
191
+
192
+ ### `02_attribution.py` — a two-panel blog explainer
193
+
194
+ Programmatic node grids and hundreds of curved edges whose width and opacity
195
+ come straight from the data. After the replacement-model and attribution-graph
196
+ diagram in Anthropic's
197
+ [Circuit Tracing](https://transformer-circuits.pub/2025/attribution-graphs/methods.html).
198
+
199
+ ![attribution](https://raw.githubusercontent.com/philippspohn/figkit/main/docs/images/02_attribution.png)
200
+
201
+ ### `03_data_and_plots.py` — data-driven graphics
202
+
203
+ A coordinate frame, a legend, a table, a brace and a heatmap with a colour bar.
204
+
205
+ ![plots](https://raw.githubusercontent.com/philippspohn/figkit/main/docs/images/03_data_and_plots.png)
206
+
207
+ ### `05_rich_text_and_components.py` — spans, components and formulas
208
+
209
+ Per-word colour and strike-through, a `Component` publishing named ports, and
210
+ `LabelledMatrix` set as an equation with `hstack(align="baseline")`.
211
+
212
+ ![rich text](https://raw.githubusercontent.com/philippspohn/figkit/main/docs/images/05_rich_text_and_components.png)
213
+
214
+ ### `04_themes.py` — one diagram, seven themes
215
+
216
+ Not a single colour is set on an element — the theme cascade decides
217
+ everything.
218
+
219
+ ![themes](https://raw.githubusercontent.com/philippspohn/figkit/main/docs/images/04_themes.png)
220
+
221
+ ---
222
+
223
+ ## API tour
224
+
225
+ | | |
226
+ |---|---|
227
+ | **Canvas** | `Figure(w, h, pad, background, theme)`, `fig.save(...)`, `fig.to_svg()` |
228
+ | **Shapes** | `Box` `Pill` `Ellipse` `Circle` `Diamond` `Triangle` `Hexagon` `Parallelogram` `Chevron` `Star` `Cylinder` `Note` `Callout` |
229
+ | **Geometry** | `Line` `Polyline` `Polygon` `Path` `Dot` `Marker` |
230
+ | **Content** | `Text` `Label` `Span` (per-word colour / strike / underline) `Image` |
231
+ | **Composites** | `Matrix` `LabelledMatrix` `Vector` `ColorBar` `Table` `Legend` `Brace` `Bracket` `Panel` `Group` `Spacer` `Component` |
232
+ | **Connectors** | `arrow` `line` `elbow` `curve` `connect` `double_arrow` `self_loop` |
233
+ | **Placement** | `at` `move` `center_at` `right_of` `left_of` `above_of` `below_of` `inside` `align_to` `span_x` `resize` `rotate` |
234
+ | **Layout** | `align` `distribute_h/v` `spread_h/v` `hstack` (incl. `align="baseline"`) `vstack` `grid` `fit` `brace_around` `between` `center_on` `circular` `same_size` `bbox_of` |
235
+ | **Data** | `Frame` (`pt` `line` `scatter` `bars` `area_fill` `region` `axes` `gridlines`), `nice_ticks` |
236
+ | **Checking** | `fig.audit()` → `Report` (`overlap` `overflow` `contrast` `crossing` `degenerate` `offscreen`), `el.ignore_audit()` |
237
+ | **Style** | `Style` `Theme` `use_theme`, classes (`classes=`, `add_class`), themes `PAPER` `SLIDE` `DARK` `BLUEPRINT` `MINIMAL` `SOFT` |
238
+ | **Colour** | `mix` `lighten` `darken` `alpha` `colormap` `palette` `contrast_color` `to_hex` |
239
+
240
+ Anchors on every element: `n s e w ne nw se sw center`, plus `at_angle(deg)`,
241
+ `uv(u, v)` and offsets like `box.e + (6, 0)`. Connectors add `c.mid` and
242
+ `c.anchor_at(t)`, which stay live as the arrow moves.
243
+
244
+ ---
245
+
246
+ ## Design notes
247
+
248
+ * **Coordinates are px, y grows downward** — the SVG convention. `n` is the top.
249
+ * **The output is clean SVG.** No wrapper `<g>` soup, no embedded raster of
250
+ your text: real `<text>` elements by default, real `<path>` outlines when you
251
+ ask for `text_as_paths=True` (which PNG and PDF export do automatically).
252
+ * **Groups own their children.** `Group(a, b)` and `fit(a, b)` reparent, so the
253
+ cluster moves as a unit. Use `bbox_of([a, b])` when you only want the bounds.
254
+ * **Text is centred optically**, on the cap-height band, which is what looks
255
+ right for short labels in boxes.
256
+ * **No runtime layout engine.** Placement happens when you call it. That makes
257
+ the code easy to reason about and easy to debug — print a `bbox` and you know
258
+ exactly where something is.
259
+
260
+ ---
261
+
262
+ ## Development
263
+
264
+ ```bash
265
+ pip install -e ".[dev]"
266
+ pytest # 277 tests; every example must audit clean
267
+ python -m pyflakes figkit
268
+ python examples/01_pipeline.py
269
+ ```
270
+
271
+ See [CONTRIBUTING.md](https://github.com/philippspohn/figkit/blob/main/CONTRIBUTING.md) for what the test suite expects — in
272
+ particular, that new audit checks come with tests for the cases they must
273
+ *not* report.
274
+
275
+ ## License
276
+
277
+ MIT
@@ -0,0 +1,28 @@
1
+ figkit/__init__.py,sha256=P7M60JWyKK3A12mTpluJKB6zrRZxgByRp0c_HPLERyU,5045
2
+ figkit/audit.py,sha256=TYcPxQbz05fR1uRA4Uw2MGMdF1ZHZhivOkom1UnY2t8,23266
3
+ figkit/colors.py,sha256=hHA_DwVSYK0XVzmmckVUe7HTxGYS8YHVkzg6oxLsKy8,11567
4
+ figkit/component.py,sha256=RX8awtDt4xEl1B88CeD3Xgb3rLsbW6Wh7m_d-iiMBZc,4157
5
+ figkit/components.py,sha256=BS__IydHQrKH5m5okVUelQAf-l1qWcGq5zVdnlgR55A,28499
6
+ figkit/connectors.py,sha256=i9OL7YkGR7SKhrdOHU0EsjqmIQfsb9BCk0RXfFK2gKI,26745
7
+ figkit/core.py,sha256=9tGZVefWpKbFFA1Ksoyp0Lpm_6sFbEZT99ixlksscVQ,35372
8
+ figkit/export.py,sha256=A-Cb9xNXZ0FTG-yvPiTBN_hjhbmKQNAA7bNPAPNebaM,11118
9
+ figkit/figure.py,sha256=Nyb4fcaernE2KolJfoMgha9W7WoXRMGCucwMjyIOCbg,11329
10
+ figkit/fonts.py,sha256=X_LakcguGAWEyCync8_f30rT_Pc4aiD3wcwcO_9HBao,17953
11
+ figkit/frame.py,sha256=TLkitIaXNvkLHi6azTKzr9vsHVbH3M2KtgY0d7op5l0,15926
12
+ figkit/geom.py,sha256=01TkzUsz63nqBjOb3q1cK7IsTqNcb1ZTb90d8H8GZow,15502
13
+ figkit/image.py,sha256=b1O96JIOOd8_Ym8qH4aBtu753PAutKP7ig_RVSvvMb0,11159
14
+ figkit/layout.py,sha256=ZEX1NxDQbx4xwcvqxc1q3_qeUbzNtV9yoFJQ1NxLtCI,18702
15
+ figkit/mathtext.py,sha256=06_KvJ1WDjAv2H4RKeLKHypS9Uy8yKAdf0cIGPSiC-o,11190
16
+ figkit/paint.py,sha256=EEMRgmH3044zGIedUyKTjxJPpj3WD7ahSEE4WrZuqdQ,5373
17
+ figkit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ figkit/shapes.py,sha256=_ymTRucrImnLFeg4A9fvOHQ52FN2JsLBgSZ8aIl1OFU,27065
19
+ figkit/style.py,sha256=VYE6eE1sv_oC8F85tyWv2GNXKizFcdmm8xotfjoZAYc,18150
20
+ figkit/svgdoc.py,sha256=7LBxzHV_7js2DRKQPqkVAzxNENBYs6CKLrS4XdRCB_o,4301
21
+ figkit/svgpath.py,sha256=fc-QpU8GE5ITk7rzOCyy8Ej3O4tb3aF81IGCfEZQXt8,15770
22
+ figkit/text.py,sha256=bxcvIVqwJArRGd8sr6eeMFnCELQA4eBB9pKETONv_W8,23377
23
+ figkit/themes.py,sha256=OMEP_xoI5x_xEnyukq24NR6tz4uLzKoUXQDPmEBnxGE,6390
24
+ figkit-0.1.0.dist-info/licenses/LICENSE,sha256=sUbQmDzSHkWDvRX1a5lnjsMY4GCRuQr4A4S3eQV1-Fc,1076
25
+ figkit-0.1.0.dist-info/METADATA,sha256=3arboJpYWa0lu0LfPwwx4jmVdfht6zot2e5rBlqEz60,11767
26
+ figkit-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
27
+ figkit-0.1.0.dist-info/top_level.txt,sha256=cWFe7ZAY9YdgVfNq7yh-0oVBffEIxVxlikvrtPEQ_bU,7
28
+ figkit-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 figkit contributors
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 @@
1
+ figkit