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.
- package/README.md +12 -6
- package/claude/.claude-plugin/plugin.json +8 -0
- package/claude/.mcp.json +10 -0
- package/claude/skills/gum-jsx/SKILL.md +317 -0
- package/claude/skills/gum-jsx/references/layout.md +132 -0
- package/claude/skills/gum-jsx/references/networks.md +90 -0
- package/claude/skills/gum-jsx/references/plotting.md +129 -0
- package/claude/skills/gum-jsx/references/shapes.md +138 -0
- package/claude/skills/gum-jsx/references/symbolic.md +141 -0
- package/claude/skills/gum-jsx/references/text.md +114 -0
- package/claude/skills/gum-jsx/references/utilities.md +123 -0
- package/docs/code/group.jsx +1 -1
- package/docs/code/points.jsx +1 -1
- package/docs/code/rect.jsx +1 -1
- package/docs/code/stack.jsx +1 -1
- package/docs/code/symfield.jsx +1 -1
- package/docs/code/sympoints.jsx +1 -1
- package/docs/gala/complex_plot.jsx +4 -4
- package/docs/gala/metal_grid.jsx +1 -1
- package/docs/gala/plot_manual.jsx +2 -2
- package/docs/text/colors.md +1 -1
- package/docs/text/element.md +2 -0
- package/docs/text/graph.md +4 -2
- package/docs/text/group.md +2 -2
- package/docs/text/gum.md +1 -1
- package/docs/text/network.md +1 -1
- package/docs/text/plot.md +1 -1
- package/docs/text/symline.md +0 -2
- package/package.json +28 -35
- package/scripts/claude.ts +29 -0
- package/scripts/{cli.js → cli.ts} +23 -11
- package/scripts/mcp.ts +52 -0
- package/scripts/skill.ts +57 -0
- package/scripts/test.ts +32 -0
- package/src/elems/core.ts +740 -0
- package/src/elems/geometry.ts +600 -0
- package/src/elems/layout.ts +515 -0
- package/src/elems/network.ts +257 -0
- package/src/elems/plot.ts +702 -0
- package/src/elems/slide.ts +93 -0
- package/src/elems/symbolic.ts +346 -0
- package/src/elems/text.ts +424 -0
- package/src/{eval.js → eval.ts} +16 -6
- package/src/fonts/fonts.browser.ts +20 -0
- package/src/fonts/fonts.node.ts +17 -0
- package/src/fonts/fonts.ts +34 -0
- package/src/gum.ts +30 -0
- package/src/lib/const.ts +54 -0
- package/src/{math.js → lib/math.ts} +26 -14
- package/src/{parse.js → lib/parse.ts} +32 -24
- package/src/{term.js → lib/term.ts} +5 -5
- package/src/{text.js → lib/text.ts} +29 -24
- package/src/lib/theme.ts +140 -0
- package/src/lib/types.ts +49 -0
- package/src/lib/utils.ts +819 -0
- package/src/{meta.js → meta.ts} +14 -6
- package/src/{render.js → render.ts} +37 -13
- package/src/types/linebreak.d.ts +13 -0
- package/src/types/opentype.d.ts +381 -0
- package/index.d.ts +0 -1271
- package/scripts/server.js +0 -69
- package/src/defaults.js +0 -177
- package/src/fonts.browser.js +0 -16
- package/src/fonts.js +0 -32
- package/src/fonts.node.js +0 -17
- package/src/gum.js +0 -3416
- 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
|
-
|
|
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.
|
|
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 |
|
|
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 |
|
|
67
|
+
cat input.jsx | bun run cli -f png > output.png
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Display a `gum.jsx` file
|
|
70
|
+
Display a `gum.jsx` file in the terminal:
|
|
71
71
|
```bash
|
|
72
|
-
cat input.jsx |
|
|
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 |
|
package/claude/.mcp.json
ADDED
|
@@ -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
|
+
```
|