pele-animate 0.12.0 → 0.14.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 +28 -40
- package/THIRD-PARTY-NOTICES.md +28 -0
- package/docs/accessibility.md +20 -0
- package/docs/agents.md +63 -0
- package/docs/api.md +49 -0
- package/docs/compatibility.md +33 -0
- package/docs/contributing.md +24 -0
- package/docs/custom-icons.md +39 -0
- package/docs/diagram-types.md +43 -0
- package/docs/faq.md +30 -0
- package/docs/getting-started.md +66 -0
- package/docs/how-it-works.md +44 -0
- package/docs/icons.md +82 -0
- package/docs/migrating.md +58 -0
- package/docs/recipes.md +80 -0
- package/docs/security.md +19 -0
- package/docs/step-order.md +75 -0
- package/docs/theming.md +48 -0
- package/glyphs.js +10 -13
- package/package.json +12 -8
- package/preset-doverunner.js +23 -13
- package/skills/diagram-step-order/SKILL.md +43 -0
- package/skills/diagram-step-order/steps.js +15 -0
- package/skills/pele-animate/SKILL.md +131 -0
- package/skills/pele-animate/references/categories.md +42 -0
- package/skills/pele-animate/verify.js +14 -0
- package/tabler/animals.js +23 -0
- package/tabler/arrows.js +338 -0
- package/tabler/badges.js +27 -0
- package/tabler/buildings.js +100 -0
- package/tabler/charts.js +44 -0
- package/tabler/communication.js +126 -0
- package/tabler/computers.js +49 -0
- package/tabler/currencies.js +81 -0
- package/tabler/database.js +47 -0
- package/tabler/design.js +355 -0
- package/tabler/development.js +68 -0
- package/tabler/devices.js +368 -0
- package/tabler/document.js +214 -0
- package/tabler/e-commerce.js +160 -0
- package/tabler/electrical.js +24 -0
- package/tabler/extensions.js +18 -0
- package/tabler/food.js +101 -0
- package/tabler/games.js +53 -0
- package/tabler/gestures.js +22 -0
- package/tabler/health.js +92 -0
- package/tabler/laundry.js +45 -0
- package/tabler/logic.js +13 -0
- package/tabler/map.js +268 -0
- package/tabler/math.js +93 -0
- package/tabler/media.js +165 -0
- package/tabler/mood.js +57 -0
- package/tabler/nature.js +55 -0
- package/tabler/photography.js +57 -0
- package/tabler/shapes.js +192 -0
- package/tabler/sport.js +81 -0
- package/tabler/symbols.js +42 -0
- package/tabler/system.js +789 -0
- package/tabler/text.js +199 -0
- package/tabler/vehicles.js +95 -0
- package/tabler/version-control.js +21 -0
- package/tabler/weather.js +66 -0
- package/types/glyphs.d.ts +13 -0
- package/types/index.d.ts +33 -0
- package/types/preset-doverunner.d.ts +1 -0
- package/types/tabler-pack.d.ts +2 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Migrating
|
|
3
|
+
description: Breaking changes between releases, with the renames to apply.
|
|
4
|
+
order: 13
|
|
5
|
+
section: Reference
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Migrating
|
|
9
|
+
|
|
10
|
+
pele-animate stays on `0.x`: a minor release may break things. Pin a range such as `^0.13.0` and bump it deliberately.
|
|
11
|
+
|
|
12
|
+
## 0.12 to 0.13
|
|
13
|
+
|
|
14
|
+
Two breaking changes.
|
|
15
|
+
|
|
16
|
+
### 1. Illustrated glyphs are renamed `doverunner-<name>`
|
|
17
|
+
|
|
18
|
+
The plain names now belong to the Tabler icon packs. Rename the `@{ icon }` values in your Mermaid sources:
|
|
19
|
+
|
|
20
|
+
| Before | After |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `player` | `doverunner-player` |
|
|
23
|
+
| `server` | `doverunner-server` |
|
|
24
|
+
| `key` | `doverunner-key` |
|
|
25
|
+
| `document` | `doverunner-document` |
|
|
26
|
+
| `shield` | `doverunner-shield` |
|
|
27
|
+
| `phone` | `doverunner-phone` |
|
|
28
|
+
| `cloud` | `doverunner-cloud` |
|
|
29
|
+
| `package` | `doverunner-package` |
|
|
30
|
+
| `token` | `doverunner-token` |
|
|
31
|
+
| `lock` | `doverunner-lock` |
|
|
32
|
+
| `database` | `doverunner-database` |
|
|
33
|
+
| `video` | `doverunner-video` |
|
|
34
|
+
| `media` | `doverunner-media` |
|
|
35
|
+
| `encoder` | `doverunner-encoder` |
|
|
36
|
+
| `storage` | `doverunner-storage` |
|
|
37
|
+
| `plugin` | `doverunner-plugin` |
|
|
38
|
+
| `variants` | `doverunner-variants` |
|
|
39
|
+
| `watermark` | `doverunner-watermark` |
|
|
40
|
+
| `bits-a`, `bits-b` | `doverunner-bits-a`, `doverunner-bits-b` |
|
|
41
|
+
|
|
42
|
+
A search and replace over `icon: "<name>"` does it. Or switch to Tabler icons and drop the renamed ones; see [icons](./icons.md).
|
|
43
|
+
|
|
44
|
+
### 2. The glyphs moved into the preset
|
|
45
|
+
|
|
46
|
+
The seven glyphs that lived in `pele-animate/glyphs` are now in `pele-animate/preset-doverunner`. `pele-animate/glyphs` is only the
|
|
47
|
+
registry (`icons`, `registerGlyphs`, `registerTabler`). If you use any `doverunner-*` glyph, import the preset:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
import 'pele-animate/preset-doverunner';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### New in 0.13
|
|
54
|
+
|
|
55
|
+
- Tabler icon packs: `pele-animate/tabler/<category>`, with the `--pa-stroke` variable.
|
|
56
|
+
- `icons()` returns a neutral rounded square for unknown names, instead of a blank slot.
|
|
57
|
+
|
|
58
|
+
A missed rename shows up as that rounded square, not as an error, so look for unexpected squares after upgrading.
|
package/docs/recipes.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Recipes
|
|
3
|
+
description: Using pele-animate in Vite, SvelteKit, Astro, Nuxt, React and plain HTML, with what has been tested.
|
|
4
|
+
order: 8
|
|
5
|
+
section: Guides
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Recipes
|
|
9
|
+
|
|
10
|
+
Pele and pele-animate need the DOM, so in every framework the rule is the same: **mount on the client, after the page has
|
|
11
|
+
rendered.** Load them with dynamic `import()` inside the framework's mounted hook so server rendering never touches them.
|
|
12
|
+
|
|
13
|
+
The shape is always:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
const [{ mount }, { watch }, { icons }] = await Promise.all([
|
|
17
|
+
import('pele'),
|
|
18
|
+
import('pele-animate'),
|
|
19
|
+
import('pele-animate/glyphs'),
|
|
20
|
+
import('pele-animate/tabler/computers'), // your icon categories
|
|
21
|
+
import('pele-animate/style.css'),
|
|
22
|
+
]);
|
|
23
|
+
mount(el, src, { icons });
|
|
24
|
+
watch(el, src);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
| Framework | Status | Where the code goes |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| Plain HTML / Vite | Tested | A module script, as in [getting started](./getting-started.md) |
|
|
30
|
+
| Astro | Tested in production (the DoveRunner docs site) | A client `<script>` that finds the diagram elements |
|
|
31
|
+
| SvelteKit 3 | Tested (build and browser, static adapter) | `onMount(async () => { ... })` in the page or component |
|
|
32
|
+
| Nuxt 4 | Tested (build and browser, static generate) | `onMounted` in a `.client.vue` component |
|
|
33
|
+
| React / Next.js | Not tested | A client component (`'use client'`) with `useEffect` |
|
|
34
|
+
| Vue (no Nuxt) | Not tested | `onMounted` |
|
|
35
|
+
|
|
36
|
+
Notes for all of them:
|
|
37
|
+
|
|
38
|
+
- Give each diagram its own element (`<pre>` or `<div>`) holding the Mermaid source, and call `mount` and `watch` once per
|
|
39
|
+
element.
|
|
40
|
+
- If the page changes without a reload (client-side routing), mount again for the new elements.
|
|
41
|
+
- Importing the CSS (`pele-animate/style.css`) once is enough. In TypeScript, a CSS side-effect import needs a `*.css` module
|
|
42
|
+
declaration (Vite projects get it from `vite/client`).
|
|
43
|
+
- Static site generators are fine: nothing here needs a server.
|
|
44
|
+
|
|
45
|
+
## Astro
|
|
46
|
+
|
|
47
|
+
```astro
|
|
48
|
+
<pre class="mermaid" set:text={src}></pre>
|
|
49
|
+
<script>
|
|
50
|
+
// runs in the browser only
|
|
51
|
+
import { mount } from 'pele';
|
|
52
|
+
import { watch } from 'pele-animate';
|
|
53
|
+
import { icons } from 'pele-animate/glyphs';
|
|
54
|
+
import 'pele-animate/tabler/computers';
|
|
55
|
+
import 'pele-animate/style.css';
|
|
56
|
+
document.querySelectorAll('pre.mermaid').forEach((el) => {
|
|
57
|
+
const src = el.textContent ?? '';
|
|
58
|
+
mount(el as HTMLElement, src, { icons });
|
|
59
|
+
watch(el as HTMLElement, src);
|
|
60
|
+
});
|
|
61
|
+
</script>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## SvelteKit
|
|
65
|
+
|
|
66
|
+
```svelte
|
|
67
|
+
<script>
|
|
68
|
+
import { onMount } from 'svelte';
|
|
69
|
+
let el;
|
|
70
|
+
const src = 'flowchart LR\n A --> B';
|
|
71
|
+
onMount(async () => {
|
|
72
|
+
const [{ mount }, { watch }, { icons }] = await Promise.all([
|
|
73
|
+
import('pele'), import('pele-animate'), import('pele-animate/glyphs'), import('pele-animate/style.css'),
|
|
74
|
+
]);
|
|
75
|
+
mount(el, src, { icons });
|
|
76
|
+
watch(el, src);
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
<div bind:this={el}></div>
|
|
80
|
+
```
|
package/docs/security.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Security
|
|
3
|
+
description: Untrusted diagram text, and what pele-animate adds.
|
|
4
|
+
order: 12
|
|
5
|
+
section: Reference
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Security
|
|
9
|
+
|
|
10
|
+
- **Diagram text.** Pele escapes diagram text, filters links and styles, and limits source and output size. Read Pele's
|
|
11
|
+
[security page](https://pele.run/security) before rendering diagrams you did not write. pele-animate does not weaken any of
|
|
12
|
+
that: it reads the SVG after Pele renders it.
|
|
13
|
+
- **Pins.** The `%% pa:` comment is parsed with a simple pattern (step numbers and ids). It cannot run code.
|
|
14
|
+
- **Glyph markup is trusted.** `registerGlyphs()` and `registerTabler()` insert your markup into the page as SVG. Register only
|
|
15
|
+
markup you wrote or reviewed. The bundled Tabler and `doverunner-*` packs are static files in the package.
|
|
16
|
+
- **No network.** pele-animate makes no requests and loads no remote assets.
|
|
17
|
+
- **No eval.** Nothing in the package uses `eval` or generates code, so a content security policy without `unsafe-eval` works.
|
|
18
|
+
|
|
19
|
+
Report a vulnerability by opening an issue on the [GitHub repository](https://github.com/dkdev24/pele-animate) that asks for a private contact. Leave the details out of the public issue.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Step order
|
|
3
|
+
description: Choose the order things appear in, and how step mode works.
|
|
4
|
+
order: 6
|
|
5
|
+
section: Guides
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Step order
|
|
9
|
+
|
|
10
|
+
Every diagram is a list of **steps**. The intro plays them one after another, and step mode lets the reader move through
|
|
11
|
+
them. By default, the order follows the edges. A `%% pa:` comment lets you set it yourself.
|
|
12
|
+
|
|
13
|
+
## Default order
|
|
14
|
+
|
|
15
|
+
- **Flowchart:** nodes appear by level, counting from the nodes nothing points to. Each edge draws from its source once the source
|
|
16
|
+
is on screen, and its target appears as the edge lands. Branches of a decision appear together.
|
|
17
|
+
- **Sequence diagram:** actors first, then the messages in order.
|
|
18
|
+
|
|
19
|
+
## Pins
|
|
20
|
+
|
|
21
|
+
Add one comment line anywhere in the source:
|
|
22
|
+
|
|
23
|
+
```mermaid live
|
|
24
|
+
flowchart LR
|
|
25
|
+
%% pa: 1=A 2=B 3=C
|
|
26
|
+
A[Request] --> B[Validate] --> C[Respond]
|
|
27
|
+
A --> C
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`%% pa: 1=A 2=B,C` means: step 1 shows A, step 2 shows B and C. Steps are numbered from 1. Anything you do not pin keeps its default
|
|
31
|
+
level.
|
|
32
|
+
|
|
33
|
+
### Edge pins
|
|
34
|
+
|
|
35
|
+
`X>Y` pins the edge from X to Y to its own step, so an edge between two nodes that are already visible can be a step:
|
|
36
|
+
|
|
37
|
+
```mermaid live
|
|
38
|
+
flowchart LR
|
|
39
|
+
%% pa: 1=A,B 2=C 3=A>B
|
|
40
|
+
A[Client] --> B[Server]
|
|
41
|
+
B --> C[Database]
|
|
42
|
+
B --> A
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Rules that avoid surprises:
|
|
46
|
+
|
|
47
|
+
- **Pin the nodes first.** An edge pinned before its target appears lands early.
|
|
48
|
+
- A two-way edge (`A <--> B`) is pinned in the direction you wrote it first (`A>B`).
|
|
49
|
+
- Do not rename node ids after pinning: pins match ids.
|
|
50
|
+
- Translated pages keep the same ids, so copy the `%% pa:` line across languages after checking the ids match.
|
|
51
|
+
|
|
52
|
+
## Step mode
|
|
53
|
+
|
|
54
|
+
Click the diagram, or focus it and press Enter or Space. A small bar appears with previous, play/pause and next.
|
|
55
|
+
|
|
56
|
+
| Key | Action |
|
|
57
|
+
|---|---|
|
|
58
|
+
| Space | Play or pause |
|
|
59
|
+
| → | Next step |
|
|
60
|
+
| ← | Previous step |
|
|
61
|
+
| Esc | Leave step mode |
|
|
62
|
+
|
|
63
|
+
Pass `{ controls: false }` as the third argument of `watch()` to turn step mode off; a click then just replays the intro.
|
|
64
|
+
|
|
65
|
+
## Checking your order
|
|
66
|
+
|
|
67
|
+
After `animate()` runs, `svg.paSteps` is one array per step. Print what each step shows:
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
const svg = document.querySelector('.pa-scene svg.pele');
|
|
71
|
+
svg.paSteps.map((items, n) => `${n + 1}: ` + items.map(([el]) => el.textContent.trim() || el.dataset.id).join(' ; '));
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`parseOrder(source)` returns the parsed pins as a `Map` (node id or `'X>Y'` to a 0-based step), if you want to check them
|
|
75
|
+
without a browser.
|
package/docs/theming.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Theming
|
|
3
|
+
description: Colors, dark mode, stroke width and reduced motion.
|
|
4
|
+
order: 7
|
|
5
|
+
section: Guides
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Theming
|
|
9
|
+
|
|
10
|
+
`watch()` adds the class `pa-scene` to the container. That class gives the diagram its tinted panel and its colors. The
|
|
11
|
+
defaults are written with `:where()`, so any rule in your stylesheet wins without a specificity fight.
|
|
12
|
+
|
|
13
|
+
## Variables
|
|
14
|
+
|
|
15
|
+
Set these on the container (or any ancestor):
|
|
16
|
+
|
|
17
|
+
| Variable | What it controls | Default (light) |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `--pa-bg` | Panel background | `#efeafa` |
|
|
20
|
+
| `--pa-solid` | Strong color: lines, icon strokes, accents | `#4F378B` |
|
|
21
|
+
| `--pa-light` | Light fill: icon fills, group surfaces | `#e4dcf6` |
|
|
22
|
+
| `--pa-stroke` | Stroke width of Tabler icons | `1.5` |
|
|
23
|
+
| `--pele-*` | Any of Pele's own variables (`--pele-fg`, `--pele-surface`, ...) | Set from the `--pa-*` values |
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
.pa-scene {
|
|
27
|
+
--pa-bg: #f6f6f0;
|
|
28
|
+
--pa-solid: #0b5fff;
|
|
29
|
+
--pa-light: #dbe7ff;
|
|
30
|
+
--pa-stroke: 1.25;
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
For the full list of `--pele-*` variables, see Pele's [theming docs](https://pele.run).
|
|
35
|
+
|
|
36
|
+
## Dark mode
|
|
37
|
+
|
|
38
|
+
Dark colors apply when the system prefers dark, unless the page sets `data-theme="light"` on the root element. To force dark,
|
|
39
|
+
set `data-theme="dark"` on the root element. Both follow the same variables, so overriding `--pa-solid` and friends works in
|
|
40
|
+
either mode.
|
|
41
|
+
|
|
42
|
+
## Reduced motion
|
|
43
|
+
|
|
44
|
+
With `prefers-reduced-motion: reduce`, the intro and the tokens do not play: the finished picture shows.
|
|
45
|
+
|
|
46
|
+
## Scene frame
|
|
47
|
+
|
|
48
|
+
The panel, its padding and rounded corners come from `.pa-scene`. Override `border-radius`, `padding` or `margin` on it directly.
|
package/glyphs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Glyph registry. A glyph is the inner markup of a 24x24 SVG; colors come from --pa-* variables so packs can theme.
|
|
1
|
+
// Glyph registry. No art lives here: the illustrated glyphs are in preset-doverunner.js, named `doverunner-<name>`; plain names belong to the Tabler packs. A glyph is the inner markup of a 24x24 SVG; colors come from --pa-* variables so packs can theme.
|
|
2
2
|
// Pass `icons` to pele's render()/mount() options: mount(el, text, { icons }).
|
|
3
3
|
export const S = 'var(--pa-solid,#4F378B)';
|
|
4
4
|
export const L = 'var(--pa-light,#d9d0f0)';
|
|
@@ -9,15 +9,12 @@ const reg = new Map();
|
|
|
9
9
|
export function registerGlyphs(pack, strokeWidth = 1.1) {
|
|
10
10
|
for (const [name, markup] of Object.entries(pack)) reg.set(name, `<g stroke-width="${strokeWidth}">${markup}</g>`);
|
|
11
11
|
}
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
phone: `<rect x="6.5" y="2" width="11" height="20" rx="2.5" fill="${W}" stroke="${S}"/><path d="M10.5 3.8h3" stroke="${S}"/><rect x="8.5" y="6" width="7" height="4" rx="1" fill="${S}" stroke="none"/><path d="M8.5 12.5h7M8.5 15h7M8.5 17.5h4" stroke="${S}"/><path d="M10.5 20.2h3" stroke="${S}"/>`,
|
|
22
|
-
cloud: `<path d="M7 18a4 4 0 0 1-.6-7.96A5.5 5.5 0 0 1 17 8.5a4.75 4.75 0 0 1 .5 9.5z" fill="${L}" stroke="${S}"/>`,
|
|
23
|
-
});
|
|
12
|
+
// Tabler packs (tabler/*.js): outline icons drawn for any stroke width. Width comes from the CSS variable --pa-stroke, so a
|
|
13
|
+
// stylesheet can thicken or thin every Tabler glyph at once; `strokeWidth` is the fallback. Illustrated glyphs are all prefixed `doverunner-`, so Tabler names never collide.
|
|
14
|
+
export function registerTabler(pack, strokeWidth = 1.5) {
|
|
15
|
+
const g = (m) => `<g fill="none" stroke="${S}" stroke-linecap="round" stroke-linejoin="round" style="stroke-width:var(--pa-stroke,${strokeWidth})">${m}</g>`;
|
|
16
|
+
for (const [name, markup] of Object.entries(pack)) reg.set(name, g(markup));
|
|
17
|
+
}
|
|
18
|
+
// Unknown names get a neutral rounded square instead of Pele's blank icon slot (Pele ships no icons of its own).
|
|
19
|
+
const fallback = `<g fill="none" stroke="${S}" stroke-linecap="round" stroke-linejoin="round" style="stroke-width:var(--pa-stroke,1.5)"><rect x="4" y="4" width="16" height="16" rx="4"/></g>`;
|
|
20
|
+
export const icons = (name) => reg.get(name) ?? fallback;
|
package/package.json
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pele-animate",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.14.0",
|
|
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",
|
|
7
7
|
"homepage": "https://github.com/dkdev24/pele-animate#readme",
|
|
8
|
+
"packageManager": "pnpm@10.13.1",
|
|
9
|
+
"scripts": { "test": "node scripts/check-docs.mjs", "build": "pnpm -r --filter ./site build" },
|
|
8
10
|
"publishConfig": { "access": "public" },
|
|
9
11
|
"author": "Daniel Kim",
|
|
10
12
|
"repository": { "type": "git", "url": "git+https://github.com/dkdev24/pele-animate.git" },
|
|
11
13
|
"keywords": ["mermaid", "pele", "svg", "diagram", "animation"],
|
|
14
|
+
"types": "./types/index.d.ts",
|
|
12
15
|
"exports": {
|
|
13
|
-
".": "./pele-animate.js",
|
|
14
|
-
"./glyphs": "./glyphs.js",
|
|
15
|
-
"./preset-doverunner": "./preset-doverunner.js",
|
|
16
|
-
"./style.css": "./pele-animate.css"
|
|
16
|
+
".": { "types": "./types/index.d.ts", "default": "./pele-animate.js" },
|
|
17
|
+
"./glyphs": { "types": "./types/glyphs.d.ts", "default": "./glyphs.js" },
|
|
18
|
+
"./preset-doverunner": { "types": "./types/preset-doverunner.d.ts", "default": "./preset-doverunner.js" },
|
|
19
|
+
"./style.css": "./pele-animate.css",
|
|
20
|
+
"./tabler/*": { "types": "./types/tabler-pack.d.ts", "default": "./tabler/*.js" }
|
|
17
21
|
},
|
|
18
|
-
"files": ["pele-animate.js", "pele-animate.css", "glyphs.js", "preset-doverunner.js", "README.md", "LICENSE"],
|
|
19
|
-
"sideEffects": ["*.css", "./preset-doverunner.js"],
|
|
22
|
+
"files": ["pele-animate.js", "pele-animate.css", "glyphs.js", "preset-doverunner.js", "tabler", "types", "docs", "skills", "THIRD-PARTY-NOTICES.md", "README.md", "LICENSE"],
|
|
23
|
+
"sideEffects": ["*.css", "./preset-doverunner.js", "./tabler/*.js"],
|
|
20
24
|
"peerDependencies": { "pele": "^1.7.0" },
|
|
21
25
|
"devDependencies": { "pele": "^1.7.0" }
|
|
22
26
|
}
|
package/preset-doverunner.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// DoveRunner
|
|
1
|
+
// DoveRunner illustrated glyphs, all named `doverunner-<name>`: generic player/server/key/document/shield/phone/cloud, plus DRM / forensic watermarking / packaging vocabulary. Needs the registry in glyphs.js.
|
|
2
2
|
import { registerGlyphs, S, L, W } from './glyphs.js';
|
|
3
3
|
|
|
4
4
|
// A row of six video-segment chips; bit 1 = filled, bit 0 = outline.
|
|
@@ -12,17 +12,27 @@ const chips = (bits) =>
|
|
|
12
12
|
.join('');
|
|
13
13
|
|
|
14
14
|
registerGlyphs({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
'doverunner-player': `<defs><linearGradient id="pa-g-screen" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#6b4fb5"/><stop offset="1" stop-color="#2c1f52"/></linearGradient></defs><rect x="2" y="4" width="20" height="13" rx="2" fill="url(#pa-g-screen)" stroke="${S}"/><path d="M10 7.8v5.4l4.8-2.7z" fill="${W}" stroke="none"/><path d="M9 20.5h6M12 17v3.5" stroke="${S}"/>`,
|
|
16
|
+
'doverunner-server': `<rect x="3" y="3.5" width="18" height="7" rx="2" fill="${L}" stroke="${S}"/><rect x="3" y="13.5" width="18" height="7" rx="2" fill="${L}" stroke="${S}"/><circle cx="7" cy="7" r="1" fill="${S}" stroke="none"/><circle cx="7" cy="17" r="1" fill="${S}" stroke="none"/><path d="M12 7h6M12 17h6" stroke="${S}"/>`,
|
|
17
|
+
'doverunner-key': `<circle cx="8" cy="12" r="4.5" fill="${L}" stroke="${S}"/><circle cx="8" cy="12" r="1.4" fill="${S}" stroke="none"/><path d="M12.5 12H21M18 12v3.5M21 12v2.5" stroke="${S}"/>`,
|
|
18
|
+
'doverunner-document': `<path d="M6 2.5h8l4.5 4.5v14a1 1 0 0 1-1 1h-11.5a1 1 0 0 1-1-1v-17.5a1 1 0 0 1 1-1z" fill="${L}" stroke="${S}"/><path d="M14 2.5V7h4.5" fill="none" stroke="${S}"/><path d="M8.5 12h7M8.5 15.5h7" stroke="${S}"/>`,
|
|
19
|
+
'doverunner-shield': `<path d="M12 2.5l8 3v6c0 5-3.4 8.5-8 10-4.6-1.5-8-5-8-10v-6z" fill="${S}" stroke="none"/><path d="M8.5 12l2.6 2.6 4.6-5" fill="none" stroke="${W}" stroke-width="2.2"/>`,
|
|
20
|
+
'doverunner-phone': `<rect x="6.5" y="2" width="11" height="20" rx="2.5" fill="${W}" stroke="${S}"/><path d="M10.5 3.8h3" stroke="${S}"/><rect x="8.5" y="6" width="7" height="4" rx="1" fill="${S}" stroke="none"/><path d="M8.5 12.5h7M8.5 15h7M8.5 17.5h4" stroke="${S}"/><path d="M10.5 20.2h3" stroke="${S}"/>`,
|
|
21
|
+
'doverunner-cloud': `<path d="M7 18a4 4 0 0 1-.6-7.96A5.5 5.5 0 0 1 17 8.5a4.75 4.75 0 0 1 .5 9.5z" fill="${L}" stroke="${S}"/>`,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
registerGlyphs({
|
|
25
|
+
'doverunner-package': `<path d="M12 2.5l8.5 4.5v10L12 21.5 3.5 17V7z" fill="${L}" stroke="${S}"/><path d="M3.5 7L12 11.5 20.5 7M12 11.5v10" fill="none" stroke="${S}"/><path d="M8 4.8l8.5 4.5" stroke="${S}"/>`,
|
|
26
|
+
'doverunner-token': `<path d="M3 7.5A1.5 1.5 0 0 1 4.5 6h15A1.5 1.5 0 0 1 21 7.5V10a2 2 0 0 0 0 4v2.5a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 16.5V14a2 2 0 0 0 0-4z" fill="${L}" stroke="${S}"/><circle cx="9" cy="12" r="2.2" fill="${S}" stroke="none"/><path d="M13.5 10.5h4.5M13.5 13.5h3" stroke="${S}"/>`,
|
|
27
|
+
'doverunner-lock': `<path d="M8.5 10.5V8a3.5 3.5 0 0 1 7 0v2.5" fill="none" stroke="${S}"/><rect x="5" y="10.5" width="14" height="10" rx="2" fill="${S}" stroke="none"/><circle cx="12" cy="15" r="1.5" fill="${W}" stroke="none"/><path d="M12 15.5v2.2" stroke="${W}"/>`,
|
|
28
|
+
'doverunner-video': `<rect x="2" y="6" width="13" height="12" rx="2" fill="${L}" stroke="${S}"/><path d="M15 10.8l6-3.6v9.6l-6-3.6z" fill="${S}" stroke="${S}"/><circle cx="5.6" cy="9.4" r="1" fill="${S}" stroke="none"/>`,
|
|
29
|
+
'doverunner-media': `<rect x="2" y="4" width="15" height="11" rx="2" fill="${L}" stroke="${S}"/><path d="M7.6 7.2v5.6l4.6-2.8z" fill="${S}" stroke="none"/><ellipse cx="14.8" cy="19" rx="2.3" ry="1.8" fill="${S}" stroke="none"/><path d="M17 19V9.5q3 .2 3.6 3.4" fill="none" stroke="${S}"/>`,
|
|
30
|
+
'doverunner-storage': `<ellipse cx="12" cy="6" rx="8" ry="2.6" fill="${L}" stroke="${S}"/><path d="M4 6l2.4 13.4c.4 1.3 3 2.1 5.6 2.1s5.2-.8 5.6-2.1L20 6" fill="${L}" stroke="${S}"/><path d="M4.6 9.6c1.6 1.2 4.2 1.8 7.4 1.8s5.8-.6 7.4-1.8" fill="none" stroke="${S}"/>`,
|
|
31
|
+
'doverunner-plugin': `<path d="M4 8h4.5a2.2 2.2 0 1 1 4.4 0H17v4.1a2.2 2.2 0 1 1 0 4.4V20H4z" fill="${L}" stroke="${S}"/><path d="M17 8h3v12h-3" fill="none" stroke="${S}"/>`,
|
|
32
|
+
'doverunner-variants': `<rect x="2.5" y="3" width="14" height="9.5" rx="2" fill="${L}" stroke="${S}"/><rect x="7.5" y="11.5" width="14" height="9.5" rx="2" fill="${W}" stroke="${S}"/><text x="9.5" y="10.4" font-size="6.5" font-weight="700" text-anchor="middle" fill="${S}" stroke="none">A</text><text x="14.5" y="19" font-size="6.5" font-weight="700" text-anchor="middle" fill="${S}" stroke="none">B</text>`,
|
|
33
|
+
'doverunner-watermark': `<rect x="2.5" y="4" width="19" height="16" rx="2" fill="${L}" stroke="${S}"/><path d="M12 7.4c2.9 3.3 4.2 5 4.2 7a4.2 4.2 0 0 1-8.4 0c0-2 1.3-3.7 4.2-7z" fill="${S}" stroke="none"/><path d="M10.2 14.6a1.9 1.9 0 0 0 1.4 1.9" fill="none" stroke="${W}"/>`,
|
|
34
|
+
'doverunner-encoder': `<rect x="1.5" y="4" width="9" height="16" rx="1.5" fill="${L}" stroke="${S}"/><rect x="4.3" y="7" width="3.4" height="10" rx=".6" fill="${W}" stroke="${S}"/><path d="M2.9 6.5h.9M2.9 10.5h.9M2.9 14.5h.9M8.2 6.5h.9M8.2 10.5h.9M8.2 14.5h.9" stroke="${S}"/><path d="M12 12h3.5M14 10l2 2-2 2" fill="none" stroke="${S}"/><rect x="17.6" y="6.2" width="2.4" height="2.8" rx=".5" fill="${S}" stroke="${S}"/><rect x="20.4" y="6.2" width="2.4" height="2.8" rx=".5" fill="${W}" stroke="${S}"/><rect x="17.6" y="10.6" width="2.4" height="2.8" rx=".5" fill="${W}" stroke="${S}"/><rect x="20.4" y="10.6" width="2.4" height="2.8" rx=".5" fill="${S}" stroke="${S}"/><rect x="17.6" y="15" width="2.4" height="2.8" rx=".5" fill="${S}" stroke="${S}"/><rect x="20.4" y="15" width="2.4" height="2.8" rx=".5" fill="${S}" stroke="${S}"/>`,
|
|
35
|
+
'doverunner-database': `<path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6" fill="${L}" stroke="${S}"/><ellipse cx="12" cy="6" rx="8" ry="3" fill="${L}" stroke="${S}"/><path d="M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3" fill="none" stroke="${S}"/>`,
|
|
26
36
|
});
|
|
27
37
|
// Thinner line: the chips are small even at full box size.
|
|
28
|
-
registerGlyphs({ 'bits-a': chips('011010'), 'bits-b': chips('101101') }, 0.5);
|
|
38
|
+
registerGlyphs({ 'doverunner-bits-a': chips('011010'), 'doverunner-bits-b': chips('101101') }, 0.5);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: diagram-step-order
|
|
3
|
+
description: Review and fix the animation step order of pele-animate diagrams (Mermaid code blocks in document pages) against the page text, and tune groups, icons and labels so the flow reads clearly. Use when converting existing Mermaid diagrams to pele-animate, or when asked to check or adjust step order, `%% pa:` pins, or step-by-step playback of a diagram.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Diagram step order
|
|
7
|
+
|
|
8
|
+
Goal: when a viewer steps through a diagram (click, then ←/→), each step shows what the surrounding text says happens next.
|
|
9
|
+
|
|
10
|
+
## What controls the order
|
|
11
|
+
|
|
12
|
+
- **Flowcharts:** nodes appear by BFS level from the sources. An edge appears with its later end. `%% pa: 1=A,B 2=C` (first line inside the block, after the diagram type) pins nodes to steps. `%% pa: 3=A>B` pins the edge from A to B (needed for a reply or any edge between nodes that are already visible). Pin nodes first: an edge pinned before its target exists lands early. Unpinned nodes keep their BFS level; gaps in step numbers are skipped when stepping.
|
|
13
|
+
- **Sequence diagrams:** step 1 is the participants, then one step per message in source order. Pins do nothing. Reordering messages changes what the diagram says, so never do it silently: if the order disagrees with the text, report it.
|
|
14
|
+
- Ties: two edges into the same node share a step. Request and reply between the same two nodes land together unless the reply is edge-pinned.
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
1. **Find the blocks** in the page and read the prose around each one (heading, the paragraph before and after, captions, numbered lists). Write down the order the text describes, one line per step.
|
|
19
|
+
2. **Probe the current order.** With the site running (restart a dev server after changing a locally copied library, then hard reload; a soft reload can show stale steps): open the page in a headless browser and evaluate `steps.js` in it (for example `agent-browser open <url>` then `agent-browser eval "$(cat steps.js)"`, or Playwright's `page.evaluate`). Each step prints its nodes, `[FROM_TO]` edges and quoted edge labels.
|
|
20
|
+
3. **Triage.**
|
|
21
|
+
- Sequence diagram: compare message order with the text, change nothing, flag mismatches.
|
|
22
|
+
- Linear chain or decision tree: BFS order is normally right (branches of a decision appear together). Say "no change" and why.
|
|
23
|
+
- Existing pins: a person tuned them. Keep their intent; refine only where the text clearly disagrees, and say so.
|
|
24
|
+
- Topology with lanes or groups: usually needs work.
|
|
25
|
+
4. **Fix** with pins and edge pins, then node declaration order and edge direction. Do not rename node ids (pins and CSS key on them) and do not change labels' meaning. Keep one idea per step: a request and its response are two steps; things that happen at the same moment share one.
|
|
26
|
+
5. **Appearance.** Follow the site's own diagram conventions file (group colour ids, icon set, label length). Within it: put nodes in groups by who owns them, use a glyph where one fits the meaning, keep edge labels to one short line, order nodes inside a lane so arrows run in the reading direction. Do not edit shared styles or the library; list any needed glyph or CSS as a follow-up.
|
|
27
|
+
6. **Mirror translations.** Translated pages have their own labels but the same node ids. Diff the ids between the two sources before copying a `%% pa:` line, then probe the translated page too.
|
|
28
|
+
7. **Re-probe** every changed diagram and confirm the printed steps match the order you wrote down in step 1.
|
|
29
|
+
|
|
30
|
+
## Lessons from the first run
|
|
31
|
+
|
|
32
|
+
- Probe every diagram you report on, linear chains included. "Read the source" is not a check; one run left some diagrams unprobed.
|
|
33
|
+
- A `<-->` edge is pinned in its first-written direction (`H>F` for `H <--> F`).
|
|
34
|
+
- When several agents work in parallel, give each its own browser session (`agent-browser --session <name>`) and tell them not to start, stop or restart the shared dev server.
|
|
35
|
+
- After changing a locally copied library, restart the dev server and clear its cache, or the page keeps the old module.
|
|
36
|
+
- Edge pins need a pele-animate release that supports them; until then they are ignored and the node order still applies.
|
|
37
|
+
- Tuned one language? Mirror the pins to the others in the same pass; a tuned EN page next to an untuned KO page is the usual miss.
|
|
38
|
+
|
|
39
|
+
## Report, one row per diagram
|
|
40
|
+
|
|
41
|
+
`page | n/total | before steps → after steps | one line tying the order to the text | changes (pins, groups, labels) | follow-ups`
|
|
42
|
+
|
|
43
|
+
Say "no change" with the reason when you leave one alone. The person reviewing reads this table, so keep each cell short and let the probe output carry the detail.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Paste into the browser (agent-browser eval "$(cat steps.js)"): lists, per animated diagram on the page, what each step reveals.
|
|
2
|
+
// Nodes by label, edges as [FROM_TO], edge labels in quotes. Relies on svg.paSteps, set by pele-animate animate().
|
|
3
|
+
(() => [...document.querySelectorAll('.pa-scene')].map((sc, i) => {
|
|
4
|
+
const svg = sc.querySelector('svg.pele');
|
|
5
|
+
if (!svg?.paSteps) return `#${i + 1} (no steps)`;
|
|
6
|
+
const kind = svg.classList.contains('pele-sequence') ? 'seq' : 'flow';
|
|
7
|
+
const txt = (el) => el.textContent.replace(/\s+/g, ' ').trim();
|
|
8
|
+
const lines = svg.paSteps.map((items, n) => ` ${n + 1}: ` + items.map(([el]) => {
|
|
9
|
+
if (el.classList.contains('pele-edge')) return `[${el.dataset.id.replace(/^L_/, '').replace(/_\d+$/, '')}]`;
|
|
10
|
+
if (el.classList.contains('pele-edge-label')) return `"${txt(el)}"`;
|
|
11
|
+
if (el.classList.contains('pele-lifeline')) return '|';
|
|
12
|
+
return txt(el) || el.dataset.id;
|
|
13
|
+
}).filter((x) => x !== '|').join(' ; ')).join('\n');
|
|
14
|
+
return `#${i + 1} ${kind}\n${lines}`;
|
|
15
|
+
}).join('\n'))()
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pele-animate
|
|
3
|
+
description: Add animated, step-by-step Mermaid diagrams to a project with pele-animate (an add-on for the Pele renderer): install, mount on the client, pick icons from the Tabler packs, set the step order with `%% pa:` pins, theme with CSS variables, and verify in a browser. Use whenever asked to animate Mermaid diagrams, add icons to a flowchart, or make a diagram step-through, or when the project already imports `pele-animate`. Do not use for plain static diagrams or other Mermaid renderers.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# pele-animate
|
|
7
|
+
|
|
8
|
+
pele-animate makes a [Pele](https://pele.run) diagram explain itself one step at a time: you choose the order things appear in,
|
|
9
|
+
readers step through it, and flowchart nodes can carry icons. It supports **flowcharts and sequence diagrams only**. Pele
|
|
10
|
+
does the layout; pele-animate is an unofficial add-on and not a theme package.
|
|
11
|
+
|
|
12
|
+
Your job when this skill is loaded: wire it into the project **and prove it renders**. Do not hand work back unverified.
|
|
13
|
+
|
|
14
|
+
## Hard rules
|
|
15
|
+
|
|
16
|
+
1. **Client only.** `pele` and `pele-animate` need the DOM. Load them with dynamic `import()` in the framework's mounted hook,
|
|
17
|
+
never in server code.
|
|
18
|
+
2. **Never invent icon names.** Unknown names do not fail: they render a plain rounded square. Look names up (see Icons) and
|
|
19
|
+
import the category that holds them.
|
|
20
|
+
3. **Import three things:** the resolver `icons` from `pele-animate/glyphs`, each icon category you use, and `pele-animate/style.css`.
|
|
21
|
+
4. **Do not rename node ids after pinning the order**: pins match ids.
|
|
22
|
+
5. **Verify in a browser** (last section). Reading the code is not a check.
|
|
23
|
+
|
|
24
|
+
## 1. Install
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm i pele-animate pele # or pnpm / yarn / bun; pele is a peer dependency (^1.7.0)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 2. Mount (client side)
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const [{ mount }, { watch }, { icons }] = await Promise.all([
|
|
34
|
+
import('pele'), import('pele-animate'), import('pele-animate/glyphs'),
|
|
35
|
+
import('pele-animate/tabler/computers'), // one import per icon category you use
|
|
36
|
+
import('pele-animate/style.css'),
|
|
37
|
+
]);
|
|
38
|
+
mount(el, src, { icons }); // Pele draws the SVG from the Mermaid text in `src`
|
|
39
|
+
watch(el, src); // pele-animate animates it (also on resize)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`el` is an element that holds the Mermaid source: a `<pre>` whose text is the diagram, or any element you set first with
|
|
43
|
+
`el.textContent = src`. Mount once per element. `await` at the top level works in current Vite builds; elsewhere wrap the code
|
|
44
|
+
in an `async` function.
|
|
45
|
+
Framework placement (Vite, Astro, SvelteKit, Nuxt, React): `docs/recipes.md` in the package, or the table below.
|
|
46
|
+
|
|
47
|
+
| Framework | Put it in |
|
|
48
|
+
|---|---|
|
|
49
|
+
| Plain HTML / Vite | A module script |
|
|
50
|
+
| Astro | A client `<script>` that finds the diagram elements |
|
|
51
|
+
| SvelteKit | `onMount(async () => { ... })` |
|
|
52
|
+
| Nuxt | `onMounted` in a `.client.vue` component |
|
|
53
|
+
| React / Next.js (untested) | A client component, `useEffect` |
|
|
54
|
+
|
|
55
|
+
TypeScript: a CSS side-effect import needs a `*.css` module declaration unless the project uses Vite's client types.
|
|
56
|
+
|
|
57
|
+
## 3. Write the diagram
|
|
58
|
+
|
|
59
|
+
Icon nodes use Mermaid's own syntax:
|
|
60
|
+
|
|
61
|
+
```mermaid
|
|
62
|
+
flowchart LR
|
|
63
|
+
%% pa: 1=C 2=L 3=S
|
|
64
|
+
C@{ icon: "http-get", form: "square", h: 88, label: "Request" }
|
|
65
|
+
L@{ icon: "load-balancer", form: "square", h: 88, label: "Load balancer" }
|
|
66
|
+
S@{ icon: "cloud-computing", form: "square", h: 88, label: "Cloud service" }
|
|
67
|
+
C <-->|route| L
|
|
68
|
+
L <-->|forward| S
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- `form: "square", h: 88` = large frameless icon. Leave both out for a small icon in a frame.
|
|
72
|
+
- **Sequence diagrams ignore icons** (the participant box shows its id).
|
|
73
|
+
- Keep node ids short and stable (`C`, `L`, `S`); labels are what people read.
|
|
74
|
+
|
|
75
|
+
### Icons: find the name, then import its category
|
|
76
|
+
|
|
77
|
+
4,368 Tabler outline icons in 36 categories, each its own module `pele-animate/tabler/<category>`. Category list with sample
|
|
78
|
+
names: `references/categories.md`. To find a name:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
# by keyword, across all categories (prints file:"name":)
|
|
82
|
+
grep -o '"[a-z0-9-]*server[a-z0-9-]*":' node_modules/pele-animate/tabler/*.js | head
|
|
83
|
+
# every name in one category
|
|
84
|
+
node -e "import('pele-animate/tabler/devices').then(m => console.log(Object.keys(m.pack).join(' ')))"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The file the keyword appears in tells you which category to import. A keyword grep also matches longer names (`user` matches
|
|
88
|
+
`user-bolt`), so confirm the exact name with an anchored check, e.g. `grep -l '"user":' node_modules/pele-animate/tabler/*.js`.
|
|
89
|
+
Abstract concepts often have no icon of their own (there is no `client`): pick a close synonym (`user`, `device-desktop`) and
|
|
90
|
+
label the node with the real word. Optional extras: `import 'pele-animate/preset-doverunner'`
|
|
91
|
+
adds 20 filled glyphs named `doverunner-<name>`; only use it if the project already does or the user asks for that look.
|
|
92
|
+
Custom glyphs: `registerGlyphs({ name: '<inner markup of a 24x24 svg>' })` from `pele-animate/glyphs`.
|
|
93
|
+
|
|
94
|
+
## 4. Step order
|
|
95
|
+
|
|
96
|
+
Default order follows the edges. Override with one comment line anywhere in the source:
|
|
97
|
+
|
|
98
|
+
- `%% pa: 1=A 2=B,C` : step 1 shows A, step 2 shows B and C (steps count from 1).
|
|
99
|
+
- `%% pa: 1=A,B 2=C 3=A>B` : `X>Y` pins the edge from X to Y to its own step. **Pin the nodes first.** A two-way edge
|
|
100
|
+
(`A <--> B`) is pinned in the direction you wrote first.
|
|
101
|
+
|
|
102
|
+
Click or Enter on a diagram starts step mode (prev / play / next; Space, ←, →, Esc). `watch(el, src, { controls: false })` turns that off.
|
|
103
|
+
To review the order of existing diagrams against the page text, use the `diagram-step-order` skill.
|
|
104
|
+
|
|
105
|
+
## 5. Theme
|
|
106
|
+
|
|
107
|
+
Set on the container (`.pa-scene`, added by `watch`): `--pa-bg` (panel), `--pa-solid` (strong color), `--pa-light` (light fill),
|
|
108
|
+
`--pa-stroke` (Tabler stroke width, default 1.5), plus any `--pele-*`. Dark mode follows `prefers-color-scheme`, or force it
|
|
109
|
+
with `data-theme="dark"` on the root element. `prefers-reduced-motion` turns the intro and tokens off.
|
|
110
|
+
|
|
111
|
+
## 6. Verify
|
|
112
|
+
|
|
113
|
+
Build or run the project, open the page in a headless browser, wait about 3 seconds (the intro starts when 30% of the diagram
|
|
114
|
+
is in view, so scroll it into view first), and evaluate `verify.js` (next to this file) in the page:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
agent-browser open http://localhost:PORT/page && agent-browser eval "$(cat verify.js)" # or Playwright page.evaluate
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Expect: `diagrams` equals the number you added; every `steps` entry above 0; `emptyIcons` empty; `fallbackIcons` empty unless a
|
|
121
|
+
plain square was intended. Fix by cause:
|
|
122
|
+
|
|
123
|
+
| Symptom | Cause |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `diagrams: 0` | `watch()` never ran: it was not client-side, or the element was not found |
|
|
126
|
+
| `fallbackIcons` lists a name | The name does not exist, or its category was not imported. Look it up again |
|
|
127
|
+
| Icons missing but names are right | The category import ran after `mount()`; import packs before mounting |
|
|
128
|
+
| `steps` is `[0]` or a single step | `%% pa:` pins mismatched ids, or the diagram type is unsupported |
|
|
129
|
+
| Looks unstyled | `pele-animate/style.css` not imported |
|
|
130
|
+
|
|
131
|
+
Print the order to compare with the text you meant: `svg.paSteps.map((items, n) => ...)`, or use `diagram-step-order/steps.js`.
|