gum-jsx 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +12 -6
  2. package/claude/.claude-plugin/plugin.json +8 -0
  3. package/claude/.mcp.json +10 -0
  4. package/claude/skills/gum-jsx/SKILL.md +317 -0
  5. package/claude/skills/gum-jsx/references/layout.md +132 -0
  6. package/claude/skills/gum-jsx/references/networks.md +90 -0
  7. package/claude/skills/gum-jsx/references/plotting.md +129 -0
  8. package/claude/skills/gum-jsx/references/shapes.md +138 -0
  9. package/claude/skills/gum-jsx/references/symbolic.md +141 -0
  10. package/claude/skills/gum-jsx/references/text.md +114 -0
  11. package/claude/skills/gum-jsx/references/utilities.md +123 -0
  12. package/docs/code/group.jsx +1 -1
  13. package/docs/code/points.jsx +1 -1
  14. package/docs/code/rect.jsx +1 -1
  15. package/docs/code/stack.jsx +1 -1
  16. package/docs/code/symfield.jsx +1 -1
  17. package/docs/code/sympoints.jsx +1 -1
  18. package/docs/gala/complex_plot.jsx +4 -4
  19. package/docs/gala/metal_grid.jsx +1 -1
  20. package/docs/gala/plot_manual.jsx +2 -2
  21. package/docs/text/colors.md +1 -1
  22. package/docs/text/element.md +2 -0
  23. package/docs/text/graph.md +4 -2
  24. package/docs/text/group.md +2 -2
  25. package/docs/text/gum.md +1 -1
  26. package/docs/text/network.md +1 -1
  27. package/docs/text/plot.md +1 -1
  28. package/docs/text/symline.md +0 -2
  29. package/package.json +28 -35
  30. package/scripts/claude.ts +29 -0
  31. package/scripts/{cli.js → cli.ts} +23 -11
  32. package/scripts/mcp.ts +52 -0
  33. package/scripts/skill.ts +57 -0
  34. package/scripts/test.ts +32 -0
  35. package/src/elems/core.ts +740 -0
  36. package/src/elems/geometry.ts +600 -0
  37. package/src/elems/layout.ts +515 -0
  38. package/src/elems/network.ts +257 -0
  39. package/src/elems/plot.ts +702 -0
  40. package/src/elems/slide.ts +93 -0
  41. package/src/elems/symbolic.ts +346 -0
  42. package/src/elems/text.ts +424 -0
  43. package/src/{eval.js → eval.ts} +16 -6
  44. package/src/fonts/fonts.browser.ts +20 -0
  45. package/src/fonts/fonts.node.ts +17 -0
  46. package/src/fonts/fonts.ts +34 -0
  47. package/src/gum.ts +30 -0
  48. package/src/lib/const.ts +54 -0
  49. package/src/{math.js → lib/math.ts} +26 -14
  50. package/src/{parse.js → lib/parse.ts} +32 -24
  51. package/src/{term.js → lib/term.ts} +5 -5
  52. package/src/{text.js → lib/text.ts} +29 -24
  53. package/src/lib/theme.ts +140 -0
  54. package/src/lib/types.ts +49 -0
  55. package/src/lib/utils.ts +819 -0
  56. package/src/{meta.js → meta.ts} +14 -6
  57. package/src/{render.js → render.ts} +37 -13
  58. package/src/types/linebreak.d.ts +13 -0
  59. package/src/types/opentype.d.ts +381 -0
  60. package/index.d.ts +0 -1271
  61. package/scripts/server.js +0 -69
  62. package/src/defaults.js +0 -177
  63. package/src/fonts.browser.js +0 -16
  64. package/src/fonts.js +0 -32
  65. package/src/fonts.node.js +0 -17
  66. package/src/gum.js +0 -3416
  67. package/src/utils.js +0 -384
package/README.md CHANGED
@@ -15,7 +15,7 @@ Head to **[compendiumlabs.ai/gum](https://compendiumlabs.ai/gum)** for a live de
15
15
  # Installation
16
16
 
17
17
  ```bash
18
- npm install gum-jsx
18
+ bun i gum-jsx
19
19
  ```
20
20
 
21
21
  # Usage
@@ -53,23 +53,23 @@ const svg = elem.svg()
53
53
 
54
54
  # CLI
55
55
 
56
- You can use the `gum` command to convert `gum.jsx` into SVG text or PNG data. At that point you can either pipe them to a file or even display them directly in the terminal using `chafa`! For the latter you need a terminal that supports images, such as `ghostty`. There are a bunch of code examples in `docs/code/` and `docs/gallery/` to try out.
56
+ You can use the `gum` command to convert `gum.jsx` into SVG text or PNG data. You can even just display it directly in the terminal! For the latter you need a terminal that supports images, such as `ghostty` or `kitty`. There are a bunch of code examples in `docs/code/` and `docs/gallery/` to try out.
57
57
 
58
58
  Generate an SVG from a `gum.jsx` file:
59
59
 
60
60
  ```bash
61
- cat input.jsx | npx gum > output.svg
61
+ cat input.jsx | bun run cli -f svg > output.svg
62
62
  ```
63
63
 
64
64
  Generate a PNG from a `gum.jsx` file:
65
65
 
66
66
  ```bash
67
- cat input.jsx | npx gum -f png > output.png
67
+ cat input.jsx | bun run cli -f png > output.png
68
68
  ```
69
69
 
70
- Display a `gum.jsx` file with `chafa`:
70
+ Display a `gum.jsx` file in the terminal:
71
71
  ```bash
72
- cat input.jsx | npx gum | chafa -s 75 -
72
+ cat input.jsx | bun run cli
73
73
  ```
74
74
 
75
75
  CLI options:
@@ -78,3 +78,9 @@ CLI options:
78
78
  |--------|-------------|---------|
79
79
  | `-s, --size <size>` | Image size in pixels | 500 |
80
80
  | `-t, --theme <theme>` | Theme: `light` or `dark` | light |
81
+ | `-w, --width <width>` | Width of the PNG | null |
82
+ | `-h, --height <height>` | Height of the PNG | null |
83
+ | `-f, --format <format>` | Format: `svg` or `png` | `svg` |
84
+ | `-b, --background <color>` | Background color | null (transparent) |
85
+ | `-o, --output <output>` | Output file | null (stdout) |
86
+ | `-u, --update` | Live update display | false |
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "gum-jsx",
3
+ "description": "Plugin for the gum.jsx graphics language.",
4
+ "version": "1.0.0",
5
+ "author": {
6
+ "name": "Douglas Hanley"
7
+ }
8
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "mcpServers": {
3
+ "gum-jsx": {
4
+ "type": "stdio",
5
+ "command": "gum-mcp",
6
+ "args": [],
7
+ "env": {}
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,317 @@
1
+ ---
2
+ name: gum-jsx
3
+ description: Create plots, diagrams, and other visualizations with the "gum.jsx" language.
4
+ ---
5
+
6
+ # Introduction
7
+
8
+ The `gum.jsx` language allows for the elegant and concise creation of SVG visualizations. It has a React-like JSX syntax, but it does not actually use React internally. When interpreted, it produces pure SVG of a specified size. It is a library of `Element` derived components such as `Circle`, `Stack`, `Plot`, `Network`, and many more. Some of these map closely to standard SVG objects, while others are higher level abstractions and layout containers. You can add standard SVG attributes (like `fill`, `stroke`, `stroke-width`, `opacity`, etc.) to any `Element` component and they will be applied to the resulting SVG.
9
+
10
+ *Proportional values*: In most cases, values are passed in proportional floating point terms. So to place an object in the center of its parent, you would specify a position of `[0.5, 0.5]`. When dealing with inherently absolute concepts like `stroke-width`, standard SVG units are used, and numerical values assumed to be specified in pixels. Most `Element` objects fill the standard coordinate space `[0, 0, 1, 1]` by default. To reposition them, either pass the appropriate internal arguments (such as `pos` or `rad`) or use a layout component such as `Box` or `Stack` to arrange them.
11
+
12
+ *Aspect ratio*: Any `Element` object can have an aspect ratio `aspect`. If `aspect` is not defined, it will stretch to fit any box, while if `aspect` is defined it will be sized so as to fit within the specified rectangle while maintaining its aspect ratio. However, when `expand` is set to `true`, the element will be resized so as to instead cover the specified rectangle, while maintaining its aspect ratio.
13
+
14
+ *Subunit arguments*: For compound elements that inherit `Group`, some keyword arguments are passed down to the constituent parts. For instance, in [Plot](/docs/Plot), one can specify arguments intended for the `XAxis` unit by prefixing them with `xaxis-`. For example, setting the `stroke-width` for this subunit can be achieved with `xaxis-stroke-width`.
15
+
16
+ *Functional approach*: Avoid explicit for loops. There are `numpy`-like functions such as `range` and `linspace` for generating arrays, `zip` for combining arrays, and `palette` for interpolating colors. Additionally, you can use `map` to generate a list of elements (such as bars for a bar plot).
17
+
18
+ *Style tips*: There will be cases where a user prompt does not fully specify every detail. In these cases, use your best judgment and consider the following suggestions:
19
+ - Text should be legible and not overlap. Usually a text element `yrad` of about `0.1` to `0.2` works well
20
+ - Points and other small features should be visible but not overwhelming. Usually a size of about `0.03` is good for small features
21
+ - The figure should have appropriate outer margins so that extended features like tick labels do not get cut off. Usually a margin of about `0.1` to `0.2` works well. The best way to create outer margins is to wrap the final output in a `Box` or `Frame` component
22
+ - When the aspect ratio of the figure is not determined, a good default is to use `2` for things like plots and diagrams
23
+ - The top-level `<svg>` element will have `fill="none"` and `stroke="black"` applied automatically, so you only need to specify these attributes when they differ from these defaults
24
+
25
+ # Examples
26
+
27
+ Below are some examples of user prompts and code output.
28
+
29
+ **Example 1: Basic Circle**
30
+
31
+ Prompt: Create a blue circle that is enclosed in a rounded box. It should mostly fill the box, but not completely.
32
+
33
+ Generated code:
34
+ ```jsx
35
+ <Frame padding margin rounded>
36
+ <Circle fill={blue} />
37
+ </Frame>
38
+ ```
39
+
40
+ *Notes*: We used boolean defaults for `padding`, `margin`, and `rounded`. These will get mapped to `padding={0.1}`, `margin={0.1}`, and `rounded={0.1}` respectively. This adds a little bit of a Tailwind-like flavor and is used throughout the library. Adding a `margin` on the outside is usually good so things like borders don't get clipped.
41
+
42
+ **Example 2: Symbolic Plot**
43
+
44
+ Prompt: Create a simple plot of a sine wave titled "Sine Wave" with dashed grid lines.
45
+
46
+ Generated code:
47
+ ```jsx
48
+ <Plot aspect={2} margin={0.2} ylim={[-1.5, 1.5]} title="Sine Wave" grid grid-stroke-dasharray={4}>
49
+ <SymLine fy={sin} xlim={[0, 2*pi]} />
50
+ </Plot>
51
+ ```
52
+
53
+ **Example 3: Custom Component**
54
+
55
+ Prompt: Create two rounded boxes side by side. Left one should be blue, right one should be red.
56
+
57
+ Generated code:
58
+ ```jsx
59
+ const Squire = attr => <Square rounded {...attr} />
60
+ return <HStack spacing>
61
+ <Squire fill={blue} />
62
+ <Squire fill={red} />
63
+ </HStack>
64
+ ```
65
+
66
+ Note: Because this is two squares (unit aspect ratio) stacked side by side, the `HStack` will have an aspect ratio of 2.
67
+
68
+ # Utilities
69
+
70
+ Here are the handy array functions provided by the library. All of these mimic the behavior of their counterparts in Python and `numpy`. This can be useful for generating `Element` objects from arrays:
71
+ ```typescript
72
+ function zip(...arrs: any[]): any[]
73
+ function range(start: number, end: number, step: number): number[]
74
+ function linspace(start: number, end: number, num: number): number[]
75
+ function enumerate(x: any[]): any[]
76
+ function repeat(x: any, n: number): any[]
77
+ function lingrid(xlim: range, ylim: range, N: number): number[][]
78
+ ```
79
+
80
+ Some of the most commonly used mathematical constants are pre-defined in the global scope:
81
+ ```javascript
82
+ const e = Math.E // base of the natural logarithm
83
+ const pi = Math.PI // ratio of circumference to diameter
84
+ const phi = (1 + sqrt(5)) / 2 // golden ratio
85
+ const r2d = 180 / Math.PI // conversion from radians to degrees
86
+ const d2r = Math.PI / 180 // conversion from degrees to radians
87
+ ```
88
+
89
+ Additionally, there is a default `gum.jsx` color palette that is pre-defined in the global scope, but you can also use any valid CSS color string:
90
+ ```javascript
91
+ const none = 'none'
92
+ const white = '#ffffff'
93
+ const black = '#000000'
94
+ const blue = '#1e88e5'
95
+ const red = '#ff0d57'
96
+ const green = '#4caf50'
97
+ const yellow = '#ffb300'
98
+ const purple = '#9c27b0'
99
+ const gray = '#f0f0f0'
100
+ ```
101
+
102
+ To interpolate colors between color values, you can use these functions:
103
+ ```typescript
104
+ function interp(c1: string, c2: string, x: number): string
105
+ function palette(c1: string, c2: string, clim: range): number => string
106
+ ```
107
+
108
+ # Documentation
109
+
110
+ Below is the full documentation for the core \`gum.jsx\` components: \`Element\`, \`Group\`, and \`Box\`. All of the other components are derived from these and many use them as sub-components. Understanding these three components will give you a good foundation for working with the library.
111
+
112
+ ## Element
113
+
114
+ The base class for all `gum.jsx` objects. You will usually not be working with this object directly unless you are implementing your own custom elements. An **Element** has a few methods that can be overriden, each of which takes a **Context** object as an argument. The vast majority of implementations will override only `props` and `inner` (for non-unary elements).
115
+
116
+ The position and size of an element are specified in the internal coordinates (`coord`) of its parent, which defaults to the unit square. Rectangles are always specified in `[left, top, right, bottom]` format. You can also specify the placement by specifying `pos` and `rad` or various combinations of `xrad`/`yrad` and `xrect`/`yrect`. When not specified, `rect` defaults to the unit square.
117
+
118
+ Parameters:
119
+ - `tag` = `g` — the SVG tag associated with this element
120
+ - `unary` = `false` — whether there is inner text for this element
121
+ - `aspect` = `null` — the width to height ratio for this element
122
+ - `pos` — the desired position of the center of the child's rectangle
123
+ - `rad` ­— the desired radius of the child's rectangle (can be single number or pair)
124
+ - `xrad`/`yrad` ­— specify the radius for a specific dimension (and expand the other)
125
+ - `rect` — a fully specified rectangle to place the child in (this will override `pos`/`rad`)
126
+ - `xrect`/`yrect` ­— specify the rectangle for a specific dimension
127
+ - `aspect` — the aspect ratio of the child's rectangle
128
+ - `expand` — when `true`, instead of embedding the child within `rect`, it will make the child just large enough to fully contain `rect`
129
+ - `align` — how to align the child when it doesn't fit exactly within `rect`, options are `left`, `right`, `center`, or a fractional position (can set vertical and horizontal separately with a pair)
130
+ - `rotate` — how much to rotate the child by (degrees counterclockwise)
131
+ - `spin` — like rotate but will maintain the same size
132
+ - `vflip/hflip` — flip the child horizontally or vertically
133
+ - `flex` ­— override to set `aspect = null`
134
+ - `...` = `{}` — additional attributes that are included in `props`
135
+
136
+ Methods:
137
+ - `props(ctx)` — returns a dictionary of attributes for the SVG element. The default implementation returns the non-null `attr` passed to the constructor
138
+ - `inner(ctx)` — returns the inner text of the SVG element (for non-unary). Defaults to returing empty string
139
+ - `svg(ctx)` — returns the rendered SVG of the element as a `String`. Default implementation constructs SVG from `tag`, `unary`, `props`, and `inner`
140
+
141
+ **Example**
142
+
143
+ Prompt: create a custom triangle element called `Tri` and use it to create a triangle with a gray fill
144
+
145
+ Generated code:
146
+ ```jsx
147
+ const Tri = ({ pos0, pos1, pos2, ...attr }) => <Shape {...attr}>{[pos0, pos1, pos2]}</Shape>
148
+ return <Tri pos0={[0.5, 0.1]} pos1={[0.9, 0.9]} pos2={[0.1, 0.9]} fill={gray} />
149
+ ```
150
+
151
+ ## Group
152
+
153
+ *Inherits*: **Element**
154
+
155
+ This is the main container class that all compound elements are derived from. It accepts a list of child elements and attempts to place them according to their declared properties. Child placement positions are specified in the group's internal coordinates (`coord`), which defaults to the unit square. The coordinate space is specified in `[left, top, right, bottom]` format.
156
+
157
+ The child's `aspect` is an important determinant of its placement. When it has a `null` aspect, it will fit exactly in the given `rect`. However, when it does have an aspect, it needs to be adjusted in the case that the given `rect` does not have the same aspect. The `expand` and `align` specification arguments govern how this adjustment is made.
158
+
159
+ Parameters:
160
+ - `children` = `[]` — a list of child elements
161
+ - `aspect` = `null` — the aspect ratio of the group's rectangle (can pass `'auto'` to infer from the children)
162
+ - `coord` = `[0, 0, 1, 1]` — the internal coordinate space to use for child elements (can pass `'auto'` to contain children's rects)
163
+ - `xlim`/`ylim` = `null` — specify the `coord` limits for a specific dimension
164
+ - `clip` = `false` — clip children to the group's rectangle if `true` (or a custom shape if specified)
165
+
166
+ **Example**
167
+
168
+ Prompt: a square in the top left and a circle in the bottom right
169
+
170
+ Generated code:
171
+ ```jsx
172
+ <Group>
173
+ <Rectangle pos={[0.3, 0.3]} rad={0.1} spin={15} />
174
+ <Ellipse pos={[0.7, 0.7]} rad={0.1} />
175
+ </Group>
176
+ ```
177
+
178
+ ## Box
179
+
180
+ *Inherits*: **Group** > **Element**
181
+
182
+ This is a simple container class allowing you to add padding, margins, and a border to a single **Element**. It's pretty versatile and is often used to set up the outermost positioning of a figure. Mirroring the standard CSS definitions, padding is space inside the border and margin is space outside the border. This has no border by default, but there is a specialized subclass of this called **Frame** that defaults to `border = 1`.
183
+
184
+ **Box** can be pretty handly in various situations. It is differentiated from **Group** in that it will adopt the `aspect` of the child element. This is useful if you want to do something like shift an element up or down by a certain amount while maintaining its aspect ratio. Simply wrap it in a **Box** and set child's `pos` to the desired offset.
185
+
186
+ There are multiple ways to specify padding and margins. If given as a scalar, it is constant across all sides. If two values are given, they correspond to the horizontal and vertical sides. If four values are given, they correspond to `[left, top, right, bottom]`.
187
+
188
+ The `adjust` flag controls whether padding/margins are adjusted for the aspect ratio. If `true`, horizontal and vertical components are scaled so that their ratio is equal to the `child` element's aspect ratio. This yields padding/margins of constant apparent size regardless of aspect ratio. If `false`, the inputs are used as-is.
189
+
190
+ Parameters:
191
+ - `padding` = `0` / `0.1` — the padding to be added (inside border)
192
+ - `margin` = `0` / `0.1` — the margin to be added (outside border)
193
+ - `border` = `0` / `1` — the border width to use (stroke in pixels)
194
+ - `rounded` = `0` / `0.1` — the border rounding to use (proportional to the box size)
195
+ - `adjust` = `true` — whether to adjust values for aspect ratio
196
+ - `shape` = `Rect` — the shape class to use for the border
197
+ - `clip` = `false` — whether to clip the contents to the border shape
198
+
199
+ Subunit names:
200
+ - `border` — keywords to pass to border, such as `stroke` or `stroke-dasharray`
201
+
202
+ **Example**
203
+
204
+ Prompt: the text "hello!" in a frame with a dashed border and rounded corners
205
+
206
+ Generated code:
207
+ ```jsx
208
+ <Box padding border rounded border-stroke-dasharray={5}>
209
+ <Text>hello!</Text>
210
+ </Box>
211
+ ```
212
+
213
+ # References
214
+
215
+ Below is a list of topics to reference for documentation and usage examples for the various components. Every `gum.jsx` component is documented here. Your code must either use these components or create its own custom components. Before using a component, be sure to read the relevant reference to fully understand its parameters and capabilities.
216
+
217
+ ## Layout
218
+
219
+ **File**: [layout](references/layout.md)
220
+
221
+ These are the raw layout components that assist you in arranging elements in a figure. They typically take a list of child elements and arrange them in a specified way. `Box` is a simple container element that can be used to add padding, border, and rounded corners to a group of elements.
222
+
223
+ `Stack` lets you arrange elements in a vertical or horizontal stack (like `flexbox` in CSS) in a way that respects the aspect ratio of the child elements. Typically you would use the specialized subclasses `VStack` and `HStack` for vertical and horizontal stacks, respectively. `Grid` does something similar but for a 2D grid of rows and columns (like `grid` in CSS).
224
+
225
+ `Points` is different in that it takes a list of locations and arranges a given element at each of those locations (with the default element being `Dot`, a solid filled `Circle`).
226
+
227
+ **Components**:
228
+ - *Box*: a box with a padding, border, and rounded corners
229
+ - *Stack*/*VStack*/*HStack*: arrange elements vertically or horizontally
230
+ - *Grid*: arrange elements in a grid of specified size
231
+ - *Points*: arrange one element at each of a list of locations
232
+
233
+ ## Shapes
234
+
235
+ **File**: [shapes](references/shapes.md)
236
+
237
+ These are the basic geometric shapes that can be used to create more complex figures. Both `Rect` and `Ellipse` are aspectless by default but can be given an aspect ratio to control their shape (i.e., a circle is an `Ellipse` with an aspect of `1`).
238
+
239
+ `Line` is actually more general than just a single straight line. It can be used to draw piecewise linear paths by passing a list of points. For the case of simple unit lines, use `UnitLine` and its specialized variants `VLine` and `HLine` instead. For closed paths, either pass `closed` to `Line` or use `Shape` instead.
240
+
241
+ For multi-segment Bézier splines, `Spline` is the way to go. It takes a list of control points and draws a smooth cubic spline through them. You can control the tension of the spline with the `curve` parameter (default is `0.5`). This also accepts a `closed` parameter to draw a closed spline.
242
+
243
+ **Components**:
244
+ - *Rect*: a rectangle
245
+ - *Ellipse*: an ellipse
246
+ - *Line*/*Shape*: a piecewise linear path (possibly closed)
247
+ - *Spline*: a multi-segment Bézier spline (possibly closed)
248
+ - *UnitLine*/*VLine*/*HLine*: a single unit line
249
+
250
+ ## Text
251
+
252
+ **File**: [text](references/text.md)
253
+
254
+ These are components that can be used to create text elements. `Text` is a fairly sophisticated component that handles text wrapping, line spacing, and other text-related features. You can specify the wrap width (in "ems", that is, in proportion to the line height) with the `wrap` parameter and the alignment with the `justify` parameter. Feel free to intersperse non-text elements with text elements to create more complex layouts.
255
+
256
+ `TextStack` is a simple component that stacks text elements vertically. Specifying a `wrap` width will cause every child element to be wrapped to the specified width. You can specify the vertical spacing between the elements with the `spacing` parameter. The `TitleFrame` is a `Frame` subclass that automatically adds a boxed title to the top of the frame. Finally, `Slide` is basically a `TextStack` wrapped in a `TitleFrame`.
257
+
258
+ `Latex` does what it sounds like: it renders a single LaTeX equation. This uses MathJax under the hood, so it supports most but not all inline LaTeX features.
259
+
260
+ **Components**:
261
+ - *Text*: a text element with wrapping
262
+ - *TextStack*: a stack of text elements
263
+ - *TitleFrame*: a frame with a title
264
+ - *Slide*: a slide with a title and content
265
+ - *Latex*: a single LaTeX equation
266
+
267
+ ## Symbolic
268
+
269
+ **File**: [symbolic](references/symbolic.md)
270
+
271
+ These components allow you to plot functions symbolically. That is, they accept functions as arguments and plot them accordingly. Functions can be specified as [x => y], [y => x], or [t => (x,y)]. You can control the range over which the domain is sampled with the `tlim`/`xlim`/`ylim` parameters. You can also control the number of samples to take with the `N` parameter.
272
+
273
+ These clearly extend their non-`Sym` counterparts by adding the ability to plot functions symbolically. The only additional element is `SymFill`, which plots a filled area between two functions. For this one, passing a constant to either `fy1` or `fy2` is equivalent to passing a constant function.
274
+
275
+ **Components**:
276
+ - *SymPoints*: plot points functionally
277
+ - *SymLine*/*SymShape*: plot a curve functionally (possibly closed)
278
+ - *SymSpline*: plot a Bézier spline functionally (possibly closed)
279
+ - *SymFill*: plot a filled area between two functions
280
+
281
+ ## Plotting
282
+
283
+ **File**: [plotting](references/plotting.md)
284
+
285
+ There are components for creating various types of plots. The core element is `Graph`, which is a container element that accepts a list of children to plot over a specified coordinate system (`xlim`/`ylim`/`coord`). `Plot` is a `Graph` subclass that adds axes (with `Axis`/`HAxis`/`VAxis`), labels, and other plot-specific features. `BarPlot` is a help element that wraps a `Bars` element inside of a `Plot`.
286
+
287
+ The `Plot` element in particular is highly customizable, and you can pass arguments to sub-components using `axis`/`label`/`title` prefixes. For instance, to specify the stroke width of the x-axis, you can use `xaxis-stroke-width`. This logic applies to other types of compound components as well.
288
+
289
+ **Components**:
290
+ - *Graph*: a graph containing multiple elements with a specified coordinate system
291
+ - *Plot*: a plot containing a graph, axes, and labels
292
+ - *Axis*/*HAxis*/*VAxis*: a single axis for a plot
293
+ - *Bars*/*BarPlot*: a bar plot (bare or wrapped in a `Plot`)
294
+
295
+ ## Networks
296
+
297
+ **File**: [networks](references/networks.md)
298
+
299
+ These are components for creating network diagrams. The core element is `Network`, which is a container element that accepts a list of `Node`s and `Edge`s, as well as potentially other elements like labels. A `Node` can specify an `id` to be used to reference it from an `Edge` as either the source (`from`) or destination (`to`). Default values for `Node` and `Edge` arguments can be specified with `node-` and `edge-` prefixed arguments passed to the `Network` element.
300
+
301
+ The `Edge` element has a `dir1` and `dir2` parameter to specify the direction of the arrowhead for the source and destination nodes, respectively. You can also toggle arrowheads on either side with `arrow`/`from-arrow`/`to-arrow` or specify the `curve` parameter to control the curvature of the edge.
302
+
303
+ **Components**:
304
+ - *Node*: a node in a network
305
+ - *Edge*: an edge in a network
306
+ - *Network*: a network containing nodes and edges
307
+
308
+ ## Utilities
309
+
310
+ **File**: [utilities](references/utilities.md)
311
+
312
+ These are the helper functions that are available in the library. They are not components themselves, but they are useful for creating and manipulating data. Many of them mimic the behavior of their counterparts in Python and `numpy` and are useful for generating `Element` objects from arrays. There are also some commonly used mathematical constants and tools for interpolating colors.
313
+
314
+ **Components**:
315
+ - *Math*: mathematical functions
316
+ - *Arrays*: array operations
317
+ - *Colors*: color operations
@@ -0,0 +1,132 @@
1
+ # Layout Elements
2
+
3
+ ## Box
4
+
5
+ *Inherits*: **Group** > **Element**
6
+
7
+ This is a simple container class allowing you to add padding, margins, and a border to a single **Element**. It's pretty versatile and is often used to set up the outermost positioning of a figure. Mirroring the standard CSS definitions, padding is space inside the border and margin is space outside the border. This has no border by default, but there is a specialized subclass of this called **Frame** that defaults to `border = 1`.
8
+
9
+ **Box** can be pretty handly in various situations. It is differentiated from **Group** in that it will adopt the `aspect` of the child element. This is useful if you want to do something like shift an element up or down by a certain amount while maintaining its aspect ratio. Simply wrap it in a **Box** and set child's `pos` to the desired offset.
10
+
11
+ There are multiple ways to specify padding and margins. If given as a scalar, it is constant across all sides. If two values are given, they correspond to the horizontal and vertical sides. If four values are given, they correspond to `[left, top, right, bottom]`.
12
+
13
+ The `adjust` flag controls whether padding/margins are adjusted for the aspect ratio. If `true`, horizontal and vertical components are scaled so that their ratio is equal to the `child` element's aspect ratio. This yields padding/margins of constant apparent size regardless of aspect ratio. If `false`, the inputs are used as-is.
14
+
15
+ Parameters:
16
+ - `padding` = `0` / `0.1` — the padding to be added (inside border)
17
+ - `margin` = `0` / `0.1` — the margin to be added (outside border)
18
+ - `border` = `0` / `1` — the border width to use (stroke in pixels)
19
+ - `rounded` = `0` / `0.1` — the border rounding to use (proportional to the box size)
20
+ - `adjust` = `true` — whether to adjust values for aspect ratio
21
+ - `shape` = `Rect` — the shape class to use for the border
22
+ - `clip` = `false` — whether to clip the contents to the border shape
23
+
24
+ Subunit names:
25
+ - `border` — keywords to pass to border, such as `stroke` or `stroke-dasharray`
26
+
27
+ **Example**
28
+
29
+ Prompt: the text "hello!" in a frame with a dashed border and rounded corners
30
+
31
+ Generated code:
32
+ ```jsx
33
+ <Box padding border rounded border-stroke-dasharray={5}>
34
+ <Text>hello!</Text>
35
+ </Box>
36
+ ```
37
+
38
+ ## Stack
39
+
40
+ *Inherits*: **Group** > **Element**
41
+
42
+ Stack one or more **Element** either vertically or horizontally. There are specialized components **VStack** and **HStack** that don't take the `direc` argument. Proportional spacing between children can be specified with the `spacing` parameter.
43
+
44
+ Elements can specify their own sizing with the `stack-size` parameter. If `stack-size` is not specified and `stack-expand` is not set to `false`, space will be distributed according to the child's aspect ratio. If `stack-expand` is set to `false`, the child will be given an even share of the remaining space.
45
+
46
+ Whenever possible, the aspect ratio of the overall stack is set so that all elements with defined aspect ratios will reach full width (in the **VStack** case) or full height (in the **HStack** case).
47
+
48
+ Child parameters:
49
+ - `stack-size` = `null` — the size of the child element
50
+ - `stack-expand` = `true` — whether to expand the child to fill the remaining space
51
+
52
+ Parameters:
53
+ - `direc` — the direction of stacking: `v` or `h`
54
+ - `spacing` = `0` — total amount of space to add between child elements
55
+
56
+ **Example**
57
+
58
+ Prompt: a wide blue rectangle on top, with red and green squares side by side on the bottom. each one has rounded corners.
59
+
60
+ Generated code:
61
+ ```jsx
62
+ <VStack spacing>
63
+ <Rectangle rounded fill={blue} />
64
+ <HStack stack-size={0.5} spacing>
65
+ <Square rounded fill={red} />
66
+ <Square rounded fill={green} />
67
+ </HStack>
68
+ </VStack>
69
+ ```
70
+
71
+ ## Grid
72
+
73
+ *Inherits*: **Group** > **Element**
74
+
75
+ This element arranges its children in a grid. The grid is specified by the number of rows and columns, and the gap between the cells. In the case where `widths` and `heights` are not specified, a reasonable effort is made to best accomodate the grid elements based on their aspects (if specified).
76
+
77
+ Parameters:
78
+ - `rows` = `N` — the number of rows in the grid (autodetected)
79
+ - `cols` = `M` — the number of columns in the grid (autodetected)
80
+ - `widths` = `[1/N,...]` — an array of widths for each column
81
+ - `heights` = `[1/M,...]` — an array of heights for each row
82
+ - `spacing` = `0` — the gap between the cells in the grid
83
+
84
+ **Example**
85
+
86
+ Prompt: draw a grid of square boxes filled in light gray. each box contains an arrow that is pointing in a particular direction. that direction rotates clockwise as we move through the grid.
87
+
88
+ Generated code:
89
+ ```jsx
90
+ <Frame padding rounded>
91
+ <Grid rows={3} spacing>
92
+ { linspace(0, 360, 10).slice(0, 9).map(th =>
93
+ <Frame padding rounded fill>
94
+ <Group aspect={1} spin={th}>
95
+ <Arrow direc={0} tail={1} pos={[1, 0.5]} rad={0.5} />
96
+ </Group>
97
+ </Frame>
98
+ ) }
99
+ </Grid>
100
+ </Frame>
101
+ ```
102
+
103
+ ## Points
104
+
105
+ *Inherits*: **Group** > **Element**
106
+
107
+ Place copies of a common shape at various points. The radius can be specified by the `size` keyword and overridden for particular children. The default shape is a black dot.
108
+
109
+ Keyword arguments:
110
+ - `children` — a list of points, where each point is either an `[x,y]` pair
111
+ - `shape` = `Dot` — the default shape to use for children
112
+ - `size` = `0.025` — the default radius to use for children
113
+ - `...` = `{}` — additional attributes are passed to the default shape (like `stroke` or `fill`)
114
+
115
+ **Example**
116
+
117
+ Prompt: A plot of three different increasing curves of varying steepness and multiple points spaced at regular intervals. The x-axis label is "time (seconds)", the y-axis label is "space (meters)", and the title is "Spacetime Vibes". There are axis ticks in both directions with assiated faint grid lines.
118
+
119
+ Generated code:
120
+ ```jsx
121
+ <Plot xlim={[-1, 1]} ylim={[-1, 1]} grid margin={0.3} aspect xlabel="time (seconds)" ylabel="space (meters)" title="Spacetime Vibes">
122
+ <Points size={0.02}>{[
123
+ [0, 0.5], [0.5, 0], [-0.5, 0], [0, -0.5]
124
+ ]}
125
+ </Points>
126
+ <Rectangle pos={[0.5, 0.5]} rad={0.1} />
127
+ <Circle pos={[-0.5, -0.5]} rad={0.1} />
128
+ {[0.5, 0.9, 1.5].map(a =>
129
+ <SymLine fy={x => sin(a*x)} />
130
+ )}
131
+ </Plot>
132
+ ```
@@ -0,0 +1,90 @@
1
+ # Networks Elements
2
+
3
+ ## Node
4
+
5
+ *Inherits*: **Frame** > **Element**
6
+
7
+ This encloses an element in a **Frame** at a particular position. If the `children` argument is a string, it will be automatically wrapped in a **Text** element. The primary usage of this is in the creation of networks using the **Network** component. You must provide an `id` argument to reference the node in an **Edge** element.
8
+
9
+ Parameters:
10
+ - `id` — a string to be used as the node identifier
11
+ - `children` — the element or text to be enclosed in the node box
12
+ - `yrad` = `0.1` — the radius of the node box (will adjust to aspect)
13
+ - `padding` = `0.1` — the padding of the node box
14
+ - `border` = `1` — the border width of the node box
15
+ - `rounded` = `0.05` — the radius of the corners of the node box
16
+ - `wrap` = `null` — the width (in ems) to wrap the text at (if `null`, the text will not be wrapped)
17
+ - `justify` = `'center'` — the horizontal justification of the text
18
+
19
+ **Example**
20
+
21
+ Prompt: Two boxes with text in them that have black borders and gray interiors. The box in the upper left says "hello" and the box in the lower right says "world!".
22
+
23
+ Generated code:
24
+ ```jsx
25
+ <Network aspect node-fill={gray}>
26
+ <Node id="hello" pos={[0.25, 0.25]}>Hello</Node>
27
+ <Node id="world" pos={[0.75, 0.75]}>World!</Node>
28
+ <Edge from="hello" to="world" />
29
+ </Network>
30
+ ```
31
+
32
+ ## Edge
33
+
34
+ *Inherits*: **Group** > **Element**
35
+
36
+ This creates a cubic spline path from one point to another with optional arrowheads at either or both ends. It is named **Edge** because of its usage in network diagrams with **Network**. The emanation directions are automatically inferred from the relative point positions but can be overriden as well.
37
+
38
+ Parameters:
39
+ - `from`/`to` — the beginning and ending **Node** for the path and where the optional arrowheads are placed, or a `[node, direc]` pair where `direc` specifies the emanation direction
40
+ - `from-dir`/`to-dir` — the emanation directions of the arrowheads, either `'n'`/`'s'`/`'e'`/`'w'` or a `[dx, dy]` pair
41
+ - `arrow`/`from-arrow`/`to-arrow` — toggles whether the respective arrowheads are included. Defaults to `true` for `to-arrow` and `false` for `from-arrow`, meaning a directed graph edge
42
+ - `arrow-size` = `0.03` — the arrowhead size to use for both arrows
43
+ - `arrow-base` = `false` — toggles whether the arrowhead base is included
44
+
45
+ Subunits:
46
+ - `arrow`/`from`/`to` — the respective arrowheads, with `arrow` being applied to both
47
+ - `spline` — the cubic spline path element
48
+
49
+ **Example**
50
+
51
+ Prompt: Two boxes with text in them that have black borders and gray interiors. The box in the upper left says "hello" and the box in the lower right says "world!". The arrowhead from "Hello" is filled in red and the arrowhead to "World!" is filled in blue.
52
+
53
+ Generated code:
54
+ ```jsx
55
+ <Network aspect node-fill={gray} edge-arrow>
56
+ <Node id="hello" pos={[0.25, 0.25]}>Hello</Node>
57
+ <Node id="world" pos={[0.75, 0.75]}>World!</Node>
58
+ <Edge from="hello" to="world" from-fill={red} to-fill={blue} />
59
+ </Network>
60
+ ```
61
+
62
+ ## Network
63
+
64
+ *Inherits*: **Group** > **Element**
65
+
66
+ Network diagrams can be created using the **Node** and **Edge** classes. This automatically processes Node and Edge children to create a network diagram. It will also display non-network elements as they would be displayed in a **Graph**.
67
+
68
+ You can specify the internal coordinate system using the `coord` argument, which is a 4-element array specifying the position of the bottom left corner and the width and height of the coordinate system. For example, `coord: [0, 0, 1, 1]` specifies the unit square. When using `Graph`, one can also pass in `xlim`/`ylim` arguments to specify the extent of the graph.
69
+
70
+ Parameters:
71
+ - `coord` — the internal coordinate system to use
72
+
73
+ Subunits:
74
+ - `node` — arguments applied to all nodes
75
+ - `edge` — arguments applied to all edges
76
+
77
+ **Example**
78
+
79
+ Prompt: A network with a node on the left saying "Hello world" and two nodes on the right, one saying "This is a test of wrapping capabilities" and the other containing a blue ellipse. There are arrows going from the left node to each of the right nodes. The nodes have gray backgrounds and rounded corners. The edges have white arrowheads.
80
+
81
+ Generated code:
82
+ ```jsx
83
+ <Network aspect={1.5} node-yrad={0.15} node-rounded node-fill={gray} edge-fill={white}>
84
+ <Node id="hello" pos={[0.25, 0.5]} wrap={3}>Hello world</Node>
85
+ <Node id="test" pos={[0.75, 0.25]} wrap={6}>This is a test of wrapping capabilities</Node>
86
+ <Node id="ball" pos={[0.75, 0.75]}><Ellipse aspect={1.5} fill={blue}/></Node>
87
+ <Edge from="hello" to="test" />
88
+ <Edge from="hello" to="ball" from-dir="s" curve={3} />
89
+ </Network>
90
+ ```