pele-animate 0.14.0 → 0.15.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 CHANGED
@@ -1,78 +1,55 @@
1
1
  # pele-animate
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/pele-animate)](https://www.npmjs.com/package/pele-animate)
4
+ [![CI](https://github.com/dkdev24/pele-animate/actions/workflows/ci.yml/badge.svg)](https://github.com/dkdev24/pele-animate/actions/workflows/ci.yml)
5
+ [![license](https://img.shields.io/npm/l/pele-animate)](LICENSE)
6
+
3
7
  Mermaid diagrams that explain themselves one step at a time, with icons. You choose the order things appear in, readers
4
8
  step through it, and nodes can carry icons. A small post-processor for [Pele](https://github.com/obsidianmd/pele) (MIT),
5
9
  which renders the Mermaid; this adds the step order, the playback and the icons. It is not a theme package.
6
10
  Unofficial add-on; not affiliated with or endorsed by the Pele or Obsidian teams.
7
- The source stays valid Mermaid, so GitHub or Obsidian still show a normal diagram.
8
-
9
- - Nodes appear in order (BFS from the sources, or pinned with a `%% pa:` comment), edges draw in, labels fade in.
10
- - Hover or focus: tokens travel the edges in sequence. The intro plays once on scroll-in. Click (or Enter) enters step mode: previous / play-pause / next buttons, with Space (play/pause), ←/→ (step) and Esc (leave).
11
- - `@{ icon: "name" }` nodes become illustrations from a glyph pack. Unknown names get a neutral rounded-square glyph.
12
- - Sequence diagrams: participant boxes in a row get the tallest height (Pele sizes each to its own text). Group and box titles are bold.
13
- - Idle state is the finished picture; `prefers-reduced-motion` turns the motion off. Light and dark themes.
14
-
15
- ## Compare
16
-
17
- The same Mermaid source, three renderers. The pele-animate images loop: the intro draws in, then tokens travel the edges (as on hover).
18
- Regenerate with `examples/capture.sh`.
19
-
20
- ```mermaid
21
- flowchart LR
22
- A[Player] -->|auth token| B[OTT service]
23
- A -->|license request| C[DRM server]
24
- C -->|license| A
25
- ```
26
-
27
- | Renderer | Result |
28
- |---|---|
29
- | Mermaid | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/m1.png" width="560" alt="Flowchart rendered by Mermaid"> |
30
- | Pele | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/p1.png" width="560" alt="Flowchart rendered by Pele"> |
31
- | pele-animate | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/a1.gif" width="560" alt="Animated flowchart: nodes appear, edges draw in, tokens travel"> |
32
-
33
- ```mermaid
34
- sequenceDiagram
35
- Player->>OTT: sign in
36
- OTT-->>Player: token
37
- Player->>DRM: token
38
- DRM-->>Player: license
39
- ```
40
11
 
41
- | Renderer | Result |
42
- |---|---|
43
- | Mermaid | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/m2.png" width="560" alt="Sequence diagram rendered by Mermaid"> |
44
- | Pele | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/p2.png" width="560" alt="Sequence diagram rendered by Pele"> |
45
- | pele-animate | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/a2.gif" width="560" alt="Animated sequence diagram: messages appear in order, tokens travel"> |
46
-
47
- With icons (`@{ icon }` nodes from the Tabler `computers` pack, `%% pa: 1=C 2=L 3=S` pins the order):
12
+ **[Website](https://pele-animate.pages.dev/) · [Docs](docs/getting-started.md) · [npm](https://www.npmjs.com/package/pele-animate) · [Changelog](CHANGELOG.md)**
48
13
 
49
14
  <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/a3.gif" width="560" alt="Animated scene with Tabler icons: a request, a load balancer and a cloud service">
50
15
 
16
+ - **You set the order.** Nodes appear in the order of a `%% pa:` comment, or by default along the edges; edges draw in and labels fade in.
17
+ - **Readers step through it.** Click (or Enter) starts step mode: previous / play-pause / next buttons, Space, ←/→ and Esc. Hover or focus sends tokens along the edges.
18
+ - **Icons.** `@{ icon: "name" }` nodes use any of 4,368 [Tabler](https://github.com/tabler/tabler-icons) icons (loaded per category) or your own. Unknown names get a neutral rounded square.
19
+ - Flowcharts and sequence diagrams. The finished picture is the resting state; `prefers-reduced-motion` turns the motion off. Light and dark themes.
20
+ - The source stays valid Mermaid. One catch: GitHub's own Mermaid renderer does not know the icon names and draws "?" boxes, so the icon examples in this repository are shown as source text.
21
+
51
22
  ## Install
52
23
 
53
24
  ```sh
54
25
  npm i pele-animate pele
26
+ # or
27
+ pnpm add pele-animate pele
28
+ yarn add pele-animate pele
29
+ bun add pele-animate pele
55
30
  ```
56
31
 
32
+ `pele` is a peer dependency (`^1.7.0`): install it alongside. Both packages run in the browser and need the DOM, so mount them on the client (see [recipes](docs/recipes.md)). ESM only.
33
+
57
34
  ## Use
58
35
 
59
36
  ```js
60
37
  import { mount } from 'pele';
61
- import { watch } from 'pele-animate';
38
+ import { watch, prepare } from 'pele-animate';
62
39
  import { icons } from 'pele-animate/glyphs';
63
40
  import 'pele-animate/tabler/computers'; // one Tabler icon category; import as many as you need
64
41
  import 'pele-animate/style.css';
65
42
 
66
43
  for (const el of document.querySelectorAll('pre.mermaid')) {
67
44
  const src = el.textContent;
68
- mount(el, src, { icons });
45
+ mount(el, prepare(src), { icons });
69
46
  watch(el, src); // re-applies after Pele re-lays-out on resize
70
47
  }
71
48
  ```
72
49
 
73
50
  Mermaid source:
74
51
 
75
- ```mermaid
52
+ ```mermaid-icons
76
53
  flowchart LR
77
54
  %% pa: 1=C 2=L 3=S
78
55
  C@{ icon: "http-get", form: "square", h: 88, label: "Request" }
@@ -98,6 +75,38 @@ Everything is in [`docs/`](docs/getting-started.md), and ships inside the npm pa
98
75
  **Coding agents:** the package includes a skill, `skills/pele-animate/`, that wires the library into a project and checks the
99
76
  result in a browser. See [For coding agents](docs/agents.md).
100
77
 
78
+ ## Compare
79
+
80
+ The same Mermaid source, three renderers. The pele-animate images loop: the intro draws in, then tokens travel the edges (as on hover).
81
+ Regenerate with `examples/capture.sh`.
82
+
83
+ ```mermaid
84
+ flowchart LR
85
+ A[Client] -->|request| B[API]
86
+ A -->|sign in| C[Auth server]
87
+ C -->|token| A
88
+ ```
89
+
90
+ | Renderer | Result |
91
+ |---|---|
92
+ | Mermaid | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/m1.png" width="560" alt="Flowchart rendered by Mermaid"> |
93
+ | Pele | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/p1.png" width="560" alt="Flowchart rendered by Pele"> |
94
+ | pele-animate | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/a1.gif" width="560" alt="Animated flowchart: nodes appear, edges draw in, tokens travel"> |
95
+
96
+ ```mermaid
97
+ sequenceDiagram
98
+ Client->>API: sign in
99
+ API-->>Client: token
100
+ Client->>Data: query with token
101
+ Data-->>Client: result
102
+ ```
103
+
104
+ | Renderer | Result |
105
+ |---|---|
106
+ | Mermaid | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/m2.png" width="560" alt="Sequence diagram rendered by Mermaid"> |
107
+ | Pele | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/p2.png" width="560" alt="Sequence diagram rendered by Pele"> |
108
+ | pele-animate | <img src="https://raw.githubusercontent.com/dkdev24/pele-animate/main/examples/a2.gif" width="560" alt="Animated sequence diagram: messages appear in order, tokens travel"> |
109
+
101
110
  ## Credits and license
102
111
 
103
112
  MIT. Built on [Pele](https://github.com/obsidianmd/pele) by kepano (MIT); this is an unofficial add-on, not affiliated with or
package/docs/api.md CHANGED
@@ -14,6 +14,7 @@ TypeScript types ship with the package (`types/`).
14
14
  | Export | Signature | Description |
15
15
  |---|---|---|
16
16
  | `watch` | `watch(container: HTMLElement, source?: string, options?: { controls?: boolean }): void` | Marks the container as a scene (`pa-scene`), animates each SVG Pele renders into it and re-applies after Pele re-lays-out on resize. `controls: false` keeps click-to-replay instead of step mode. |
17
+ | `prepare` | `prepare(source?: string): string` | Returns the Mermaid source with icon-node labels padded so Pele lays out a box at least as wide as the icon (`h`). Pass its result to `mount()` and the original source to `watch()`. Without it, a label shorter than the icon puts edge ends and arrowheads under the icon. |
17
18
  | `animate` | `animate(svg: SVGSVGElement, options?: { hover?: Element; source?: string }): void` | Animates one rendered svg. `source` is read for `%% pa:` pins. Sets `svg.paSteps`. |
18
19
  | `replay` | `replay(svg: SVGSVGElement \| null \| undefined): void` | Plays the intro again. |
19
20
  | `parseOrder` | `parseOrder(source?: string): Map<string, number>` | Parses the `%% pa:` comment: node id, or `'X>Y'` for an edge, to a 0-based step. |
@@ -17,6 +17,7 @@ pnpm build # builds the site (a placeholder until the site lands)
17
17
 
18
18
  - The package is plain ESM at the repository root: no build step. The site lives in `site/`.
19
19
  - Docs are the Markdown files in `docs/`. A fenced block marked `mermaid` must render, and every `@{ icon }` name in it must exist.
20
+ - Fence convention: ```` ```mermaid live ```` is a diagram GitHub can also draw; the site animates it. A diagram with `@{ icon }` nodes uses ```` ```mermaid-icons live ````, because GitHub's Mermaid cannot draw icons (it shows "?" boxes), so GitHub shows the source text and the site animates it.
20
21
  - Tabler packs are generated: `node scripts/build-tabler.mjs <path to a tabler-icons checkout>` rewrites `tabler/*.js`. Do not edit those
21
22
  files by hand. The Tabler version is recorded in each file header and in `THIRD-PARTY-NOTICES.md`.
22
23
  - Add an entry to `CHANGELOG.md` for any user-visible change. Breaking changes also get a section in `docs/migrating.md`.
@@ -15,10 +15,14 @@ unofficial add-on for Pele and does not change how Pele lays out or draws diagra
15
15
 
16
16
  ```sh
17
17
  npm i pele-animate pele
18
+ # or
19
+ pnpm add pele-animate pele
20
+ yarn add pele-animate pele
21
+ bun add pele-animate pele
18
22
  ```
19
23
 
20
- `pele` is a peer dependency (`^1.7.0`). Both run in the browser: they need the DOM, so mount them on the client (see
21
- [recipes](./recipes.md) for frameworks).
24
+ `pele` is a peer dependency (`^1.7.0`): install it alongside. Both run in the browser and need the DOM, so mount them on the client (see
25
+ [recipes](./recipes.md) for frameworks). The packages are ESM only.
22
26
 
23
27
  ## First diagram
24
28
 
@@ -26,20 +30,20 @@ Put the Mermaid source in an element, then mount it with Pele and hand it to `wa
26
30
 
27
31
  ```js
28
32
  import { mount } from 'pele';
29
- import { watch } from 'pele-animate';
33
+ import { watch, prepare } from 'pele-animate';
30
34
  import { icons } from 'pele-animate/glyphs';
31
35
  import 'pele-animate/tabler/computers'; // icons: one Tabler category, import as many as you need
32
36
  import 'pele-animate/style.css';
33
37
 
34
38
  const el = document.querySelector('pre.mermaid');
35
39
  const src = el.textContent;
36
- mount(el, src, { icons }); // Pele draws the SVG
40
+ mount(el, prepare(src), { icons }); // Pele draws the SVG
37
41
  watch(el, src); // pele-animate animates it, and re-applies when Pele re-lays-out on resize
38
42
  ```
39
43
 
40
44
  The Mermaid source:
41
45
 
42
- ```mermaid live
46
+ ```mermaid-icons live
43
47
  flowchart LR
44
48
  %% pa: 1=C 2=L 3=S
45
49
  C@{ icon: "http-get", form: "square", h: 88, label: "Request" }
@@ -16,7 +16,7 @@ Two layers, one diagram:
16
16
 
17
17
  ## The calls
18
18
 
19
- - `mount(el, src, { icons })` is Pele's. The `icons` option is how glyphs get in (see [icons](./icons.md)).
19
+ - `mount(el, prepare(src), { icons })` is Pele's. The `icons` option is how glyphs get in (see [icons](./icons.md)).
20
20
  - `watch(el, src)` is pele-animate's. It marks the container as a scene (class `pa-scene`), animates each SVG Pele renders into
21
21
  it, and re-applies after Pele re-draws on resize. The intro is skipped on those re-draws once it has played.
22
22
  - `animate(svg, { source })` does one SVG. Use it if you render with Pele yourself and do not want `watch()`.
package/docs/icons.md CHANGED
@@ -9,17 +9,18 @@ section: Guides
9
9
 
10
10
  A flowchart node becomes an illustrated node with Mermaid's own `@{ }` syntax:
11
11
 
12
- ```mermaid live
12
+ ```mermaid-icons live
13
13
  flowchart LR
14
14
  A@{ icon: "device-desktop", form: "square", h: 88, label: "Laptop" }
15
15
  B@{ icon: "server", form: "square", h: 88, label: "Server" }
16
- A --> B
16
+ A -->|request| B
17
17
  ```
18
18
 
19
19
  Both names are in the Tabler `devices` category, so this needs `import 'pele-animate/tabler/devices'`.
20
20
 
21
21
  - `icon` is the glyph name. `label` is the caption.
22
22
  - `form: "square", h: 88` makes a large frameless icon. Leave both out for a small icon inside a frame.
23
+ - Call `mount(el, prepare(src), { icons })` with `prepare` from `pele-animate`. Pele sizes an icon node from its label, so a label shorter than `h` would put edge ends and arrowheads under the icon; `prepare` pads the label so the box fits.
23
24
  - Unknown names get a neutral rounded square, never a blank slot. Pele ships no icons of its own, so every name must come
24
25
  from a pack you import.
25
26
 
@@ -60,6 +61,7 @@ Brand, Letters, Numbers, Zodiac and Gender are not included. Counts are for Tabl
60
61
 
61
62
  Do not guess names. Look them up:
62
63
 
64
+ - The [icon browser](https://pele-animate.pages.dev/icons/) searches names and tags and copies a ready snippet; the same list is [icons.json](https://pele-animate.pages.dev/icons.json).
63
65
  - Tabler's own site, [tabler.io/icons](https://tabler.io/icons), lists names and categories (use the outline style).
64
66
  - In your project: `node_modules/pele-animate/tabler/<category>.js` lists every name in that category as an object key.
65
67
  - Names that exist in more than one place are not a problem: Tabler names are plain (`server`, `lock`), `doverunner-*` names are prefixed.
package/docs/recipes.md CHANGED
@@ -13,14 +13,14 @@ rendered.** Load them with dynamic `import()` inside the framework's mounted hoo
13
13
  The shape is always:
14
14
 
15
15
  ```js
16
- const [{ mount }, { watch }, { icons }] = await Promise.all([
16
+ const [{ mount }, { watch, prepare }, { icons }] = await Promise.all([
17
17
  import('pele'),
18
18
  import('pele-animate'),
19
19
  import('pele-animate/glyphs'),
20
20
  import('pele-animate/tabler/computers'), // your icon categories
21
21
  import('pele-animate/style.css'),
22
22
  ]);
23
- mount(el, src, { icons });
23
+ mount(el, prepare(src), { icons });
24
24
  watch(el, src);
25
25
  ```
26
26
 
@@ -49,13 +49,13 @@ Notes for all of them:
49
49
  <script>
50
50
  // runs in the browser only
51
51
  import { mount } from 'pele';
52
- import { watch } from 'pele-animate';
52
+ import { watch, prepare } from 'pele-animate';
53
53
  import { icons } from 'pele-animate/glyphs';
54
54
  import 'pele-animate/tabler/computers';
55
55
  import 'pele-animate/style.css';
56
56
  document.querySelectorAll('pre.mermaid').forEach((el) => {
57
57
  const src = el.textContent ?? '';
58
- mount(el as HTMLElement, src, { icons });
58
+ mount(el as HTMLElement, prepare(src), { icons });
59
59
  watch(el as HTMLElement, src);
60
60
  });
61
61
  </script>
@@ -69,10 +69,10 @@ Notes for all of them:
69
69
  let el;
70
70
  const src = 'flowchart LR\n A --> B';
71
71
  onMount(async () => {
72
- const [{ mount }, { watch }, { icons }] = await Promise.all([
72
+ const [{ mount }, { watch, prepare }, { icons }] = await Promise.all([
73
73
  import('pele'), import('pele-animate'), import('pele-animate/glyphs'), import('pele-animate/style.css'),
74
74
  ]);
75
- mount(el, src, { icons });
75
+ mount(el, prepare(src), { icons });
76
76
  watch(el, src);
77
77
  });
78
78
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pele-animate",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Step-by-step animated Mermaid diagrams with icons: an unofficial add-on for the Pele renderer.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/pele-animate.js CHANGED
@@ -77,6 +77,26 @@ function equalizeActors(svg) {
77
77
  }
78
78
  }
79
79
 
80
+ // Pele sizes an icon node's layout box from its label alone but draws the icon at `h`, so a label narrower than the icon puts
81
+ // the edge ends (and arrowheads) under the icon. Pad such labels with non-breaking spaces so the box is at least `h` wide.
82
+ // Use as: mount(el, prepare(src), { icons }); keep passing the original `src` to watch().
83
+ const NBSP = '\u00a0';
84
+ const WJ = '\u2060'; // zero-width, not whitespace: keeps Pele from trimming the padding
85
+ export function prepare(source = '') {
86
+ return source.replace(/@\{([^}]*)\}/g, (all, body) => {
87
+ const h = +/\bh:\s*(\d+)/.exec(body)?.[1];
88
+ if (!h) return all;
89
+ const label = /\blabel:\s*"([^"]*)"/.exec(body)?.[1] ?? '';
90
+ // ponytail: a character counts as ~7 px (a space too); a real measurer would be exact. Over-padding only widens the gap.
91
+ const need = Math.ceil(h / 7) - label.length;
92
+ if (need <= 0) return all;
93
+ const pad = NBSP.repeat(Math.ceil(need / 2));
94
+ const next = `label: "${WJ}${pad}${label}${pad}${WJ}"`;
95
+ return `@{${/\blabel:/.test(body) ? body.replace(/\blabel:\s*"[^"]*"/, next) : `${body.replace(/\s*$/, '')}, ${next} `}}`;
96
+ });
97
+ }
98
+
99
+
80
100
  export function animate(svg, { hover = svg, source = '' } = {}) {
81
101
  fitGlyphs(svg);
82
102
  equalizeActors(svg);
@@ -30,12 +30,12 @@ npm i pele-animate pele # or pnpm / yarn / bun; pele is a peer dependency
30
30
  ## 2. Mount (client side)
31
31
 
32
32
  ```js
33
- const [{ mount }, { watch }, { icons }] = await Promise.all([
33
+ const [{ mount }, { watch, prepare }, { icons }] = await Promise.all([
34
34
  import('pele'), import('pele-animate'), import('pele-animate/glyphs'),
35
35
  import('pele-animate/tabler/computers'), // one import per icon category you use
36
36
  import('pele-animate/style.css'),
37
37
  ]);
38
- mount(el, src, { icons }); // Pele draws the SVG from the Mermaid text in `src`
38
+ mount(el, prepare(src), { icons }); // Pele draws the SVG from the Mermaid text in `src`
39
39
  watch(el, src); // pele-animate animates it (also on resize)
40
40
  ```
41
41
 
@@ -58,7 +58,7 @@ TypeScript: a CSS side-effect import needs a `*.css` module declaration unless t
58
58
 
59
59
  Icon nodes use Mermaid's own syntax:
60
60
 
61
- ```mermaid
61
+ ```mermaid-icons
62
62
  flowchart LR
63
63
  %% pa: 1=C 2=L 3=S
64
64
  C@{ icon: "http-get", form: "square", h: 88, label: "Request" }
package/types/index.d.ts CHANGED
@@ -27,6 +27,8 @@ export function parseOrder(source?: string): Map<string, number>;
27
27
  export function animate(svg: SVGSVGElement, options?: AnimateOptions): void;
28
28
 
29
29
  /** Animate every svg Pele renders into `container`, re-applying after Pele re-lays-out on resize. */
30
+ /** Pad icon-node labels narrower than `h` so Pele's layout box is at least as wide as the drawn icon. Use as `mount(el, prepare(src), { icons })`; pass the original `src` to `watch()`. */
31
+ export function prepare(source?: string): string;
30
32
  export function watch(container: HTMLElement, source?: string, options?: WatchOptions): void;
31
33
 
32
34
  /** Play the intro again. */