@weasel-js/diagram 1.15.0 → 1.15.2

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 (35) hide show
  1. package/README.md +114 -5
  2. package/dist/{chunk-GR2DK4S2.js → chunk-6YQSQXQT.js} +1485 -266
  3. package/dist/chunk-6YQSQXQT.js.map +1 -0
  4. package/dist/{chunk-FDCODMFW.js → chunk-7BV2MBED.js} +906 -606
  5. package/dist/chunk-7BV2MBED.js.map +1 -0
  6. package/dist/{chunk-IYUU5KUY.js → chunk-FQVZWS24.js} +11 -101
  7. package/dist/chunk-FQVZWS24.js.map +1 -0
  8. package/dist/{chunk-AXL4JQBM.js → chunk-LPTNAYER.js} +3 -3
  9. package/dist/{chunk-AXL4JQBM.js.map → chunk-LPTNAYER.js.map} +1 -1
  10. package/dist/{chunk-DE7UILJA.js → chunk-QGL6QJE4.js} +183 -23
  11. package/dist/chunk-QGL6QJE4.js.map +1 -0
  12. package/dist/{dataTypes-BIkhAOc4.d.ts → dataTypes-1ch6cMtq.d.ts} +12 -3
  13. package/dist/effect-audio.d.ts +2 -2
  14. package/dist/effect-audio.js +7 -11
  15. package/dist/effect-audio.js.map +1 -1
  16. package/dist/effect.d.ts +5 -5
  17. package/dist/effect.js +13 -20
  18. package/dist/effect.js.map +1 -1
  19. package/dist/icons.table.js +44 -0
  20. package/dist/icons.table.js.map +1 -1
  21. package/dist/icons.table.json +44 -0
  22. package/dist/index.d.ts +932 -37
  23. package/dist/index.js +707 -34
  24. package/dist/index.js.map +1 -1
  25. package/dist/{labelTrait-BBjRgxbz.d.ts → labelTrait-moIciyXr.d.ts} +4 -0
  26. package/dist/layout.d.ts +3 -3
  27. package/dist/{layout.entry-CbmGuqE-.d.ts → layout.entry-zstuljAl.d.ts} +2 -2
  28. package/dist/layout.js +2 -2
  29. package/dist/{stageTypes-UiO25hcn.d.ts → stageTypes-B7oF8Lww.d.ts} +1 -1
  30. package/dist/{types-B0n2CNTW.d.ts → types-D5ybp8Xh.d.ts} +32 -1
  31. package/package.json +12 -11
  32. package/dist/chunk-DE7UILJA.js.map +0 -1
  33. package/dist/chunk-FDCODMFW.js.map +0 -1
  34. package/dist/chunk-GR2DK4S2.js.map +0 -1
  35. package/dist/chunk-IYUU5KUY.js.map +0 -1
@@ -20,6 +20,10 @@ interface DiagramLabel {
20
20
  * of the direction of travel** — above a left-to-right edge. Default 0,
21
21
  * which centers the label on the line. */
22
22
  offset?: number;
23
+ /** For `'start'` and `'end'` only: world units between the route's end and
24
+ * the label's near side, along the route, so a label at an end clears the
25
+ * shape the route leaves or meets. Default 0, which centers it on the end. */
26
+ inset?: number;
23
27
  /** Where label placement moved it, off a station something covered:
24
28
  * `at` a fraction of the route's length, `offset` as above. Read in place
25
29
  * of `at` and `offset`, which stay the author's preference. Written only
package/dist/layout.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { s as BodyFloor, B as BodySpec, k as Bounds, v as BuiltinOutline, x as DEFAULT_HOP_SIZE, y as DEFAULT_NODE_GAP, z as DEFAULT_RANK_GAP, e as DiagramNode, E as EdgeHop, J as EdgeLabelRoom, G as Graph, K as GraphEdge, N as GraphGroup, Q as GraphNode, U as HOPS_DOC_KEY, V as HopsDocValue, W as LayoutAxes, o as LayoutDirection, c as LayoutFn, d as LayoutOptions, p as LayoutPlan, n as LayoutPlanner, L as LayoutPorts, l as LayoutResult, M as MeasureRowText, O as Outline, X as OutlineDef, f as Port, P as PortAnchor, Y as PortSite, b as PortSpec, a as Row, Z as RowBox, _ as RowPort, $ as RowPortBox, R as RowTextStyle, a0 as Slot, a1 as anchorOffset, a2 as axesFor, a4 as bodyOutline, a6 as boxForContent, a8 as canvasMeasure, a9 as contentBox, aB as extent, af as graphOrder, aj as layoutBody, ak as layoutRowPorts, al as measureBody, am as outlineDetail, an as outlinePath, ao as packAcross, aq as pinnedSet, ar as planOf, as as plannerPlan, au as registerOutline, av as seededOrder, aw as settle, ax as sizeToBody, az as translated, aA as untilSettled } from './types-B0n2CNTW.js';
2
- export { e as AVOID_DEFAULTS, f as AvoidEdge, g as AvoidEnd, A as AvoidInput, h as AvoidLabel, i as AvoidObstacle, b as AvoidOptions, j as AvoidPort, a as AvoidRouter, c as AvoidRoutes, k as AvoidUpdateOptions, B as BodyNodeSpec, l as BuildBodyOptions, C as COMPASS, D as DEFAULT_PORTS, m as ForceBody, F as ForceOptions, n as ForceRelaxation, L as LabelPlacements, p as LayeredPlan, q as PORT_LABEL_GAP, r as PerimeterPortLabelBox, s as PlaceLabel, t as PlaceLabelsInput, d as PlaceLabelsOptions, u as PlaceRoute, P as PortsOptions, R as RowNodeData, w as backEdges, x as buildBody, y as chain, z as createAvoidRouter, E as edgeHops, G as footprintNode, H as force, I as forceRelaxation, J as forestOf, K as labelCenter, M as layered, N as layeredPlan, O as marginOf, Q as outlineFromD, S as outlinePolyline, T as placeLabels, U as portLabelBox, W as portOf, X as portSitesOf, Y as portsOf, Z as portsOnOutline, _ as radial, $ as ranksByLength, a0 as ranksOf, a1 as rayHit, a2 as routeHolds, a3 as subtreeBlocks, a4 as tree } from './layout.entry-CbmGuqE-.js';
3
- export { D as DiagramLabel, L as LabelSpot } from './labelTrait-BBjRgxbz.js';
1
+ export { s as BodyFloor, B as BodySpec, k as Bounds, v as BuiltinOutline, x as DEFAULT_HOP_SIZE, y as DEFAULT_NODE_GAP, z as DEFAULT_RANK_GAP, e as DiagramNode, E as EdgeHop, J as EdgeLabelRoom, G as Graph, K as GraphEdge, N as GraphGroup, Q as GraphNode, T as GridOptions, V as HOPS_DOC_KEY, W as HopsDocValue, X as LayoutAxes, o as LayoutDirection, c as LayoutFn, d as LayoutOptions, p as LayoutPlan, n as LayoutPlanner, L as LayoutPorts, l as LayoutResult, M as MeasureRowText, O as Outline, Y as OutlineDef, f as Port, P as PortAnchor, Z as PortSite, b as PortSpec, a as Row, _ as RowBox, $ as RowPort, a0 as RowPortBox, R as RowTextStyle, a1 as Slot, a2 as anchorOffset, a3 as axesFor, a5 as bodyOutline, a7 as boxForContent, a9 as canvasMeasure, aa as contentBox, aE as extent, ag as graphOrder, ah as grid, al as layoutBody, am as layoutRowPorts, an as measureBody, ao as outlineDetail, ap as outlinePath, aq as outlineSolid, ar as packAcross, at as pinnedSet, au as planOf, av as plannerPlan, ax as registerOutline, ay as seededOrder, az as settle, aA as sizeToBody, aC as translated, aD as untilSettled } from './types-D5ybp8Xh.js';
2
+ export { e as AVOID_DEFAULTS, f as AvoidEdge, g as AvoidEnd, A as AvoidInput, h as AvoidLabel, i as AvoidObstacle, b as AvoidOptions, j as AvoidPort, a as AvoidRouter, c as AvoidRoutes, k as AvoidUpdateOptions, B as BodyNodeSpec, l as BuildBodyOptions, C as COMPASS, D as DEFAULT_PORTS, m as ForceBody, F as ForceOptions, n as ForceRelaxation, L as LabelPlacements, p as LayeredPlan, q as PORT_LABEL_GAP, r as PerimeterPortLabelBox, s as PlaceLabel, t as PlaceLabelsInput, d as PlaceLabelsOptions, u as PlaceRoute, P as PortsOptions, R as RowNodeData, w as backEdges, x as buildBody, y as chain, z as createAvoidRouter, E as edgeHops, G as footprintNode, H as force, I as forceRelaxation, J as forestOf, K as labelCenter, M as layered, N as layeredPlan, O as marginOf, Q as outlineFromD, S as outlinePolyline, T as placeLabels, U as portLabelBox, W as portOf, X as portSitesOf, Y as portsOf, Z as portsOnOutline, _ as radial, $ as ranksByLength, a0 as ranksOf, a1 as rayHit, a2 as routeHolds, a3 as subtreeBlocks, a4 as tree } from './layout.entry-zstuljAl.js';
3
+ export { D as DiagramLabel, L as LabelSpot } from './labelTrait-moIciyXr.js';
4
4
  import '@weasel-js/geom';
5
5
  import '@weasel-js/core/math';
6
6
  import '@weasel-js/simulation';
@@ -1,7 +1,7 @@
1
- import { k as Bounds, X as OutlineDef, b as PortSpec, f as Port, T as GroupInset, e as DiagramNode, M as MeasureRowText, Z as RowBox, $ as RowPortBox, B as BodySpec, Q as GraphNode, h as DiagramNodeReader, g as DiagramNodeLike, E as EdgeHop, d as LayoutOptions, G as Graph, l as LayoutResult, c as LayoutFn, L as LayoutPorts, O as Outline } from './types-B0n2CNTW.js';
1
+ import { k as Bounds, Y as OutlineDef, b as PortSpec, f as Port, U as GroupInset, e as DiagramNode, M as MeasureRowText, _ as RowBox, a0 as RowPortBox, B as BodySpec, Q as GraphNode, h as DiagramNodeReader, g as DiagramNodeLike, E as EdgeHop, d as LayoutOptions, G as Graph, l as LayoutResult, c as LayoutFn, L as LayoutPorts, O as Outline } from './types-D5ybp8Xh.js';
2
2
  import { Vec2, PoseDescriptor, Path } from '@weasel-js/core/math';
3
3
  import { SimulationNode, createSimulation } from '@weasel-js/simulation';
4
- import { D as DiagramLabel, L as LabelSpot } from './labelTrait-BBjRgxbz.js';
4
+ import { D as DiagramLabel, L as LabelSpot } from './labelTrait-moIciyXr.js';
5
5
 
6
6
  /** An outline from SVG path data in a unit square — `(0, 0)` the box's
7
7
  * top-left, `(1, 1)` its bottom-right — stretched over each node's bounds.
package/dist/layout.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import './chunk-WDIE35AK.js';
2
- export { AVOID_DEFAULTS, DEFAULT_HOP_SIZE, HOPS_DOC_KEY, createAvoidRouter, edgeHops, placeLabels, radial } from './chunk-IYUU5KUY.js';
3
- export { COMPASS, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, PORT_LABEL_GAP, anchorOffset, axesFor, backEdges, bodyOutline, boxForContent, buildBody, canvasMeasure, chain, contentBox, extent, footprintNode, force, forceRelaxation, forestOf, graphOrder, labelCenter, layered, layeredPlan, layoutBody, layoutRowPorts, marginOf, measureBody, outlineDetail, outlineFromD, outlinePath, outlinePolyline, packAcross, pinnedSet, planOf, plannerPlan, portLabelBox, portOf, portSitesOf, portsOf, portsOnOutline, ranksByLength, ranksOf, rayHit, registerOutline, routeHolds, seededOrder, settle, sizeToBody, subtreeBlocks, translated, tree, untilSettled } from './chunk-FDCODMFW.js';
2
+ export { AVOID_DEFAULTS, DEFAULT_HOP_SIZE, HOPS_DOC_KEY, createAvoidRouter, edgeHops, placeLabels } from './chunk-FQVZWS24.js';
3
+ export { COMPASS, DEFAULT_NODE_GAP, DEFAULT_PORTS, DEFAULT_RANK_GAP, PORT_LABEL_GAP, anchorOffset, axesFor, backEdges, bodyOutline, boxForContent, buildBody, canvasMeasure, chain, contentBox, extent, footprintNode, force, forceRelaxation, forestOf, graphOrder, grid, labelCenter, layered, layeredPlan, layoutBody, layoutRowPorts, marginOf, measureBody, outlineDetail, outlineFromD, outlinePath, outlinePolyline, outlineSolid, packAcross, pinnedSet, planOf, plannerPlan, portLabelBox, portOf, portSitesOf, portsOf, portsOnOutline, radial, ranksByLength, ranksOf, rayHit, registerOutline, routeHolds, seededOrder, settle, sizeToBody, subtreeBlocks, translated, tree, untilSettled } from './chunk-7BV2MBED.js';
4
4
  //# sourceMappingURL=layout.js.map
5
5
  //# sourceMappingURL=layout.js.map
@@ -1,6 +1,6 @@
1
1
  import { Page } from '@weasel-js/core';
2
2
  import { Vec2 } from '@weasel-js/core/math';
3
- import { D as DiagramLabel } from './labelTrait-BBjRgxbz.js';
3
+ import { D as DiagramLabel } from './labelTrait-moIciyXr.js';
4
4
 
5
5
  /** An effects pipeline as plain data. It says what is wired to what and
6
6
  * nothing about how any of it is drawn. */
@@ -22,6 +22,8 @@ interface OutlineDef {
22
22
  path(bounds: Bounds): Path;
23
23
  /** Stroked only, over the fill: a cylinder's front rim, a note's fold. */
24
24
  detail?(bounds: Bounds): Path;
25
+ /** Filled in the stroke's color, over the fill: a start state's dot, a fork's bar. */
26
+ solid?(bounds: Bounds): Path;
25
27
  /** The largest box rows can occupy without leaving the shape. Default the bounds. */
26
28
  content?(bounds: Bounds): Bounds;
27
29
  /** The inverse of `content`: a box whose content is at least `content`. Default the content size. */
@@ -29,6 +31,14 @@ interface OutlineDef {
29
31
  }
30
32
 
31
33
  declare const BUILTINS: {
34
+ boundary: OutlineDef;
35
+ control: OutlineDef;
36
+ entity: OutlineDef;
37
+ collections: OutlineDef;
38
+ queue: OutlineDef;
39
+ start: OutlineDef;
40
+ end: OutlineDef;
41
+ bar: OutlineDef;
32
42
  component: OutlineDef;
33
43
  doubleRect: OutlineDef;
34
44
  event: OutlineDef;
@@ -48,6 +58,7 @@ declare const BUILTINS: {
48
58
  printer: OutlineDef;
49
59
  user: OutlineDef;
50
60
  globe: OutlineDef;
61
+ disk: OutlineDef;
51
62
  cylinder: OutlineDef;
52
63
  document: OutlineDef;
53
64
  note: OutlineDef;
@@ -59,6 +70,7 @@ declare const BUILTINS: {
59
70
  cloud: OutlineDef;
60
71
  actor: OutlineDef;
61
72
  doubleEllipse: OutlineDef;
73
+ person: OutlineDef;
62
74
  rect: OutlineDef;
63
75
  diamond: OutlineDef;
64
76
  stadium: OutlineDef;
@@ -93,6 +105,9 @@ declare function outlinePath(outline: Outline, bounds: Bounds): Path;
93
105
  /** The strokes `outline` draws over its fill — a cylinder's rim, a note's
94
106
  * fold — or null when it has none. */
95
107
  declare function outlineDetail(outline: Outline, bounds: Bounds): Path | null;
108
+ /** What `outline` fills in its stroke's color over its fill — a start state's
109
+ * dot — or null when it has none. */
110
+ declare function outlineSolid(outline: Outline, bounds: Bounds): Path | null;
96
111
  /**
97
112
  * The largest axis-aligned box a shape's content can occupy without leaving
98
113
  * the shape. Rows lay out in here, not in the bounds — a diamond's corners and
@@ -291,6 +306,20 @@ interface BuildGraphOptions<TPose> {
291
306
  */
292
307
  declare function buildGraph<TPose>(source: GraphSource<TPose>, opts?: BuildGraphOptions<TPose>): Graph;
293
308
 
309
+ /** How `grid` fills its cells. Ids are node and group ids. */
310
+ interface GridOptions {
311
+ /** Columns at the top level. Unset, as many as it has items: one row. */
312
+ columns?: number;
313
+ /** Columns inside each group, by its id. Unset, as many as the group has items. */
314
+ groupColumns?: Readonly<Record<string, number>>;
315
+ /** How many columns an item spans. Default 1; at most its grid's columns. */
316
+ spans?: Readonly<Record<string, number>>;
317
+ /** How many cells are left empty before an item. Default 0. */
318
+ skips?: Readonly<Record<string, number>>;
319
+ }
320
+ /** The grid layout: see the module comment. */
321
+ declare const grid: LayoutFn;
322
+
294
323
  /**
295
324
  * Layout: where the participants go.
296
325
  *
@@ -339,6 +368,8 @@ interface LayoutOptions {
339
368
  /** `chain` only: which side of the line everything else hangs on, along
340
369
  * the cross axis. Default `'after'`. */
341
370
  chainSide?: 'after' | 'before';
371
+ /** `grid` only: its columns, and each item's span and the empty cells before it. */
372
+ grid?: GridOptions;
342
373
  }
343
374
  /** The new top-left for each node that moves. A node that is already there is
344
375
  * absent, so an empty result means "nothing to do". */
@@ -849,4 +880,4 @@ interface EdgeHop {
849
880
  r: number;
850
881
  }
851
882
 
852
- export { type RowPortBox as $, DIAGRAM_TRAIT_KEY as A, type BodySpec as B, type ContainerRole as C, type DiagramGroup as D, type EdgeHop as E, type FontField as F, type Graph as G, DIVIDER_HEIGHT as H, type DiagramNodeEntry as I, type EdgeLabelRoom as J, type GraphEdge as K, type LayoutPorts as L, type MeasureRowText as M, type GraphGroup as N, type Outline as O, type PortAnchor as P, type GraphNode as Q, type RowTextStyle as R, type StyleField as S, type GroupInset as T, HOPS_DOC_KEY as U, type HopsDocValue as V, type LayoutAxes as W, type OutlineDef as X, type PortSite as Y, type RowBox as Z, type RowPort as _, type Row as a, type Slot as a0, anchorOffset as a1, axesFor as a2, bodyBox as a3, bodyOutline as a4, bodyTrait as a5, boxForContent as a6, buildGraph as a7, canvasMeasure as a8, contentBox as a9, untilSettled as aA, extent as aB, createDiagramNodes as aa, dataKeyReader as ab, diagramContainerOf as ac, diagramNodeOf as ad, expandGroupEdges as ae, graphOrder as af, headerBox as ag, insetOf as ah, isPinned as ai, layoutBody as aj, layoutRowPorts as ak, measureBody as al, outlineDetail as am, outlinePath as an, packAcross as ao, packClusters as ap, pinnedSet as aq, planOf as ar, plannerPlan as as, rankGaps as at, registerOutline as au, seededOrder as av, settle as aw, sizeToBody as ax, titleIdOf as ay, translated as az, type PortSpec as b, type LayoutFn as c, type LayoutOptions as d, type DiagramNode as e, type Port as f, type DiagramNodeLike as g, type DiagramNodeReader as h, type DiagramContainer as i, type ContainerHeader as j, type Bounds as k, type LayoutResult as l, type GraphSource as m, type LayoutPlanner as n, type LayoutDirection as o, type LayoutPlan as p, type GraphNodeLike as q, type BodyDivider as r, type BodyFloor as s, type BodyLayout as t, type BuildGraphOptions as u, type BuiltinOutline as v, DEFAULT_GROUP_INSET as w, DEFAULT_HOP_SIZE as x, DEFAULT_NODE_GAP as y, DEFAULT_RANK_GAP as z };
883
+ export { type RowPort as $, DIAGRAM_TRAIT_KEY as A, type BodySpec as B, type ContainerRole as C, type DiagramGroup as D, type EdgeHop as E, type FontField as F, type Graph as G, DIVIDER_HEIGHT as H, type DiagramNodeEntry as I, type EdgeLabelRoom as J, type GraphEdge as K, type LayoutPorts as L, type MeasureRowText as M, type GraphGroup as N, type Outline as O, type PortAnchor as P, type GraphNode as Q, type RowTextStyle as R, type StyleField as S, type GridOptions as T, type GroupInset as U, HOPS_DOC_KEY as V, type HopsDocValue as W, type LayoutAxes as X, type OutlineDef as Y, type PortSite as Z, type RowBox as _, type Row as a, type RowPortBox as a0, type Slot as a1, anchorOffset as a2, axesFor as a3, bodyBox as a4, bodyOutline as a5, bodyTrait as a6, boxForContent as a7, buildGraph as a8, canvasMeasure as a9, sizeToBody as aA, titleIdOf as aB, translated as aC, untilSettled as aD, extent as aE, contentBox as aa, createDiagramNodes as ab, dataKeyReader as ac, diagramContainerOf as ad, diagramNodeOf as ae, expandGroupEdges as af, graphOrder as ag, grid as ah, headerBox as ai, insetOf as aj, isPinned as ak, layoutBody as al, layoutRowPorts as am, measureBody as an, outlineDetail as ao, outlinePath as ap, outlineSolid as aq, packAcross as ar, packClusters as as, pinnedSet as at, planOf as au, plannerPlan as av, rankGaps as aw, registerOutline as ax, seededOrder as ay, settle as az, type PortSpec as b, type LayoutFn as c, type LayoutOptions as d, type DiagramNode as e, type Port as f, type DiagramNodeLike as g, type DiagramNodeReader as h, type DiagramContainer as i, type ContainerHeader as j, type Bounds as k, type LayoutResult as l, type GraphSource as m, type LayoutPlanner as n, type LayoutDirection as o, type LayoutPlan as p, type GraphNodeLike as q, type BodyDivider as r, type BodyFloor as s, type BodyLayout as t, type BuildGraphOptions as u, type BuiltinOutline as v, DEFAULT_GROUP_INSET as w, DEFAULT_HOP_SIZE as x, DEFAULT_NODE_GAP as y, DEFAULT_RANK_GAP as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weasel-js/diagram",
3
- "version": "1.15.0",
3
+ "version": "1.15.2",
4
4
  "description": "Node-link diagramming for weasel: any scene node becomes a diagram participant, with ports on its perimeter and an optional body builder for flowchart-shaped boxes.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,13 +33,13 @@
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": ">=18",
36
- "@weasel-js/animator": "1.15.0",
37
- "@weasel-js/audio": "1.15.0",
38
- "@weasel-js/core": "1.15.0",
39
- "@weasel-js/font": "1.15.0",
40
- "@weasel-js/geom": "1.15.0",
41
- "@weasel-js/react": "1.15.0",
42
- "@weasel-js/simulation": "1.15.0"
36
+ "@weasel-js/animator": "1.15.2",
37
+ "@weasel-js/audio": "1.15.2",
38
+ "@weasel-js/core": "1.15.2",
39
+ "@weasel-js/font": "1.15.2",
40
+ "@weasel-js/geom": "1.15.2",
41
+ "@weasel-js/react": "1.15.2",
42
+ "@weasel-js/simulation": "1.15.2"
43
43
  },
44
44
  "peerDependenciesMeta": {
45
45
  "@weasel-js/audio": {
@@ -50,9 +50,10 @@
50
50
  "table": "./dist/icons.table.json"
51
51
  },
52
52
  "dependencies": {
53
- "@weasel-js/clock": "1.15.0",
54
- "@weasel-js/headless": "1.15.0",
55
- "@weasel-js/icons": "1.15.0"
53
+ "@weasel-js/clock": "1.15.2",
54
+ "@weasel-js/ui-logic": "1.15.2",
55
+ "@weasel-js/icons": "1.15.2",
56
+ "@weasel-js/registry": "1.15.2"
56
57
  },
57
58
  "author": "orochi235",
58
59
  "homepage": "https://orochi235.github.io/weasel/",