pele-animate 0.11.0 → 0.13.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
@@ -7,7 +7,7 @@ The source stays valid Mermaid, so GitHub or Obsidian still show a normal diagra
7
7
 
8
8
  - Nodes appear in order (BFS from the sources, or pinned with a `%% pa:` comment), edges draw in, labels fade in.
9
9
  - 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).
10
- - `@{ icon: "name" }` nodes become illustrations from a glyph pack. Unknown names fall back to a plain Pele box.
10
+ - `@{ icon: "name" }` nodes become illustrations from a glyph pack. Unknown names get a neutral rounded-square glyph.
11
11
  - Sequence diagrams: participant boxes in a row get the tallest height (Pele sizes each to its own text). Group and box titles are bold.
12
12
  - Idle state is the finished picture; `prefers-reduced-motion` turns the motion off. Light and dark themes.
13
13
 
@@ -59,7 +59,7 @@ npm i pele-animate pele
59
59
  import { mount } from 'pele';
60
60
  import { watch } from 'pele-animate';
61
61
  import { icons } from 'pele-animate/glyphs';
62
- import 'pele-animate/preset-doverunner'; // optional extra glyphs
62
+ import 'pele-animate/preset-doverunner'; // the illustrated `doverunner-*` glyphs; skip it to use only Tabler packs
63
63
  import 'pele-animate/style.css';
64
64
 
65
65
  for (const el of document.querySelectorAll('pre.mermaid')) {
@@ -74,15 +74,17 @@ Mermaid source:
74
74
  ```mermaid
75
75
  flowchart LR
76
76
  %% pa: 1=P 2=O 3=D
77
- P@{ icon: "player", form: "square", h: 88, label: "Player" }
78
- O@{ icon: "server", form: "square", h: 88, label: "OTT service" }
79
- D@{ icon: "key", form: "square", h: 88, label: "DRM server" }
77
+ P@{ icon: "doverunner-player", form: "square", h: 88, label: "Player" }
78
+ O@{ icon: "doverunner-server", form: "square", h: 88, label: "OTT service" }
79
+ D@{ icon: "doverunner-key", form: "square", h: 88, label: "DRM server" }
80
80
  P <-->|auth token| O
81
81
  P <-->|token / license| D
82
82
  ```
83
83
 
84
84
  `form: "square", h: 88` makes a large frameless glyph; leave both out for a small icon in a frame.
85
- `%% pa: 1=P 2=O 3=D` pins nodes to steps (optional). Sequence diagrams animate actors, then messages in order.
85
+ `%% pa: 1=P 2=O 3=D` pins nodes to steps (optional). `X>Y` pins the edge from X to Y, so an edge between nodes that are
86
+ already visible can have its own step: `%% pa: 1=A,B 2=C,B>C 3=C>B`. Pin the nodes first; an edge pinned before its target appears lands early.
87
+ Sequence diagrams animate actors, then messages in order.
86
88
 
87
89
  ## API
88
90
 
@@ -91,12 +93,30 @@ flowchart LR
91
93
  | `watch(container, source?)` | Animate the SVG inside `container` (and every re-render of it); adds the scene panel and step mode (click / Enter); pass `{ controls: false }` as a third argument for click-to-replay instead |
92
94
  | `animate(svg, { hover, source })` | Animate one SVG; you handle re-renders |
93
95
  | `replay(svg)` | Play the intro again |
94
- | `parseOrder(source)` | Read the `%% pa:` pins |
96
+ | `parseOrder(source)` | Read the `%% pa:` pins: `Map(nodeId or 'X>Y' -> level)` |
97
+ | `svg.paSteps` | Set by `animate()`: one array per step, each item `[element, parts that animate in]`. Step mode uses it; read it to check the order |
95
98
  | `registerGlyphs(pack, strokeWidth = 1.1)` (`/glyphs`) | Add glyphs: `{ name: '<inner markup of a 24x24 svg>' }`; colors via `--pa-solid` / `--pa-light` |
96
- | `icons` (`/glyphs`) | Pele `icons` resolver |
99
+ | `icons` (`/glyphs`) | Pele `icons` resolver; unknown names get a neutral rounded square, since Pele ships no icons of its own |
97
100
 
98
- Generic glyphs: `player`, `server`, `key`, `document`, `shield`, `phone`, `cloud`. `preset-doverunner`: `package`, `token`, `lock`,
99
- `database`, `video`, `media`, `encoder`, `storage`, `plugin`, `variants`, `watermark`, `bits-a`, `bits-b`.
101
+ Illustrated glyphs (filled, two-tone, DoveRunner style) come from `pele-animate/preset-doverunner` and are all named `doverunner-<name>`: `player`, `server`, `key`, `document`, `shield`, `phone`, `cloud`, `package`, `token`, `lock`, `database`, `video`, `media`, `encoder`, `storage`, `plugin`, `variants`, `watermark`,
102
+ `bits-a`, `bits-b`. Plain names (`server`, `lock`, ...) are Tabler's.
103
+
104
+ ### Tabler icon packs
105
+
106
+ About 4,300 line icons from [Tabler Icons](https://github.com/tabler/tabler-icons) (MIT), split by Tabler's own categories. Import only what you need:
107
+
108
+ ```js
109
+ import 'pele-animate/tabler/devices'; // also: system, database, development, communication, charts, ...
110
+ ```
111
+
112
+ Then use any name from that category: `A@{ icon: "device-tv", form: "square", h: 88 }`. The illustrated glyphs are prefixed `doverunner-`, so no Tabler name is shadowed.
113
+ Tabler icons are stroke-only, so the stroke width is adjustable: set `--pa-stroke` on the container (default `1.5`; Tabler draws at 2 and
114
+ designs every icon to work at other widths). Categories: see `tabler/` (Brand, Letters, Numbers, Zodiac and Gender are left out).
115
+ Regenerate with `node scripts/build-tabler.mjs <tabler-icons checkout>`. License notice: `THIRD-PARTY-NOTICES.md`.
116
+
117
+ ```css
118
+ .pa-scene { --pa-stroke: 1; }
119
+ ```
100
120
 
101
121
  ## Theme
102
122
 
@@ -0,0 +1,28 @@
1
+ # Third-party notices
2
+
3
+ ## Tabler Icons
4
+
5
+ The `tabler/*.js` glyph packs are generated from [Tabler Icons](https://github.com/tabler/tabler-icons) 3.49.0 (outline set)
6
+ by `scripts/build-tabler.mjs`. Icon names and categories are Tabler's own.
7
+
8
+ MIT License
9
+
10
+ Copyright (c) 2020-2026 Paweł Kuna
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
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
- // Returning null makes pele fall back to its default node.
13
- export const icons = (name) => reg.get(name) ?? null;
14
-
15
- registerGlyphs({
16
- 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}"/>`,
17
- 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}"/>`,
18
- 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}"/>`,
19
- 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}"/>`,
20
- 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"/>`,
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,6 +1,6 @@
1
1
  {
2
2
  "name": "pele-animate",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Animated, illustrated SVG scenes from plain Mermaid code, as a post-processor for Pele.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -13,10 +13,11 @@
13
13
  ".": "./pele-animate.js",
14
14
  "./glyphs": "./glyphs.js",
15
15
  "./preset-doverunner": "./preset-doverunner.js",
16
- "./style.css": "./pele-animate.css"
16
+ "./style.css": "./pele-animate.css",
17
+ "./tabler/*": "./tabler/*.js"
17
18
  },
18
- "files": ["pele-animate.js", "pele-animate.css", "glyphs.js", "preset-doverunner.js", "README.md", "LICENSE"],
19
- "sideEffects": ["*.css", "./preset-doverunner.js"],
19
+ "files": ["pele-animate.js", "pele-animate.css", "glyphs.js", "preset-doverunner.js", "tabler", "THIRD-PARTY-NOTICES.md", "README.md", "LICENSE"],
20
+ "sideEffects": ["*.css", "./preset-doverunner.js", "./tabler/*.js"],
20
21
  "peerDependencies": { "pele": "^1.7.0" },
21
22
  "devDependencies": { "pele": "^1.7.0" }
22
23
  }
package/pele-animate.css CHANGED
@@ -58,8 +58,9 @@
58
58
  .pa-scene.pa-stepping { flex-direction: column; align-items: center; gap: .75rem; }
59
59
  .pa-controls { display: flex; align-items: center; gap: .125rem; padding: .25rem; border-radius: 999px; cursor: default;
60
60
  background: var(--pele-surface); color: var(--pele-fg); border: 1px solid var(--pele-border); font: 500 .8rem/1 system-ui, sans-serif; }
61
- .pa-controls button { width: 2rem; height: 2rem; padding: 0; border: 0; border-radius: 50%; background: none; color: inherit; font: inherit; font-size: 1rem; cursor: pointer; }
62
- .pa-controls button:hover:not(:disabled) { background: var(--pele-surface-alt); }
63
- .pa-controls button:disabled { opacity: .35; cursor: default; }
61
+ .pa-scene .pa-controls > * { margin: 0; } /* host sites often add sibling margins (e.g. prose `* + *` rules) */
62
+ .pa-controls button { display: flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; padding: 0; border: 0; border-radius: 50%; background: none; color: inherit; font: inherit; font-size: 1rem; cursor: pointer; }
63
+ .pa-controls button:hover:not([aria-disabled=true]) { background: var(--pele-surface-alt); }
64
+ .pa-controls button[aria-disabled=true] { opacity: .35; cursor: default; }
64
65
  .pa-controls button:focus-visible { outline: 2px solid var(--pa-solid); }
65
- .pa-count { min-width: 4ch; padding: 0 .5rem; text-align: center; font-variant-numeric: tabular-nums; }
66
+ .pa-count { min-width: 4ch; line-height: 2rem; padding: 0 .5rem; text-align: center; font-variant-numeric: tabular-nums; }
package/pele-animate.js CHANGED
@@ -6,7 +6,8 @@ const MAX_INTRO = 3; // a long diagram squeezes its steps so the intro never run
6
6
  const TOKEN = 0.5; // seconds a token takes to cross an edge
7
7
  const reduced = () => matchMedia('(prefers-reduced-motion: reduce)').matches;
8
8
 
9
- // `%% pa: 1=A,B 2=C` pins nodes to steps (1-based); returns Map(nodeId -> level). Everything else keeps its BFS level.
9
+ // `%% pa: 1=A,B 2=C 3=A>B` pins nodes to steps (1-based); `X>Y` pins the edge from X to Y. Returns Map(nodeId or 'X>Y' -> level).
10
+ // Everything else keeps its BFS level.
10
11
  export function parseOrder(source = '') {
11
12
  const m = source.match(/^\s*%%\s*pa:\s*(.+)$/m);
12
13
  const levels = new Map();
@@ -103,8 +104,11 @@ export function animate(svg, { hover = svg, source = '' } = {}) {
103
104
  // Start after the source is up, but never so early that the arrow lands before its target appears (pinned steps).
104
105
  edges.forEach((e, i) => {
105
106
  const [s, d] = pairs[i] ?? [];
106
- step.set(e, Math.max(level.get(s) ?? 0, level.get(d) ?? 0));
107
- times.set(e, Math.max((level.get(s) ?? 0) * u + 0.3 * k, (level.get(d) ?? 0) * u - 0.5 * k));
107
+ const pin = level.get(`${s}>${d}`); // edge pinned to a step: starts with that step, once its source is up
108
+ step.set(e, pin ?? Math.max(level.get(s) ?? 0, level.get(d) ?? 0));
109
+ times.set(e, pin !== undefined
110
+ ? Math.max(pin * u, (level.get(s) ?? 0) * u + 0.3 * k)
111
+ : Math.max((level.get(s) ?? 0) * u + 0.3 * k, (level.get(d) ?? 0) * u - 0.5 * k));
108
112
  });
109
113
  }
110
114
 
@@ -169,6 +173,15 @@ export function animate(svg, { hover = svg, source = '' } = {}) {
169
173
  }
170
174
 
171
175
  const STEP_MS = 1200; // autoplay pace in step mode
176
+ // Control icons are SVG, not text glyphs: glyphs like ‹ and ▶ sit at different heights in every font.
177
+ const icon = (d, fill) => `<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" ${fill ? 'fill="currentColor"' : 'fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"'}>${d}</svg>`;
178
+ const ICON = {
179
+ prev: icon('<path d="M15 5l-7 7 7 7"/>'),
180
+ next: icon('<path d="M9 5l7 7-7 7"/>'),
181
+ play: icon('<path d="M8 5v14l11-7z"/>', 1),
182
+ pause: icon('<path d="M7 5h3.5v14H7zM13.5 5H17v14h-3.5z"/>', 1),
183
+ exit: icon('<path d="M6 6l12 12M18 6L6 18"/>'),
184
+ };
172
185
 
173
186
  // Show steps 0..k and hide the rest; `pop` animates the elements of step k.
174
187
  function showStep(svg, k, pop) {
@@ -197,17 +210,18 @@ export function watch(container, source = '', { controls = true } = {}) {
197
210
  bar.setAttribute('role', 'toolbar');
198
211
  bar.setAttribute('aria-label', 'Step through the diagram');
199
212
  bar.title = ''; // an empty title stops the container's tooltip showing through the gaps
200
- bar.innerHTML = '<button type="button" data-a="prev" aria-label="Previous step" title="Previous step (\u2190)">\u2039</button>'
213
+ bar.innerHTML = '<button type="button" data-a="prev" aria-label="Previous step" title="Previous step (\u2190)">' + ICON.prev + '</button>'
201
214
  + '<button type="button" data-a="play"></button>'
202
- + '<button type="button" data-a="next" aria-label="Next step" title="Next step (\u2192)">\u203A</button>'
215
+ + '<button type="button" data-a="next" aria-label="Next step" title="Next step (\u2192)">' + ICON.next + '</button>'
203
216
  + '<span class="pa-count" aria-live="polite" title="Current step"></span>'
204
- + '<button type="button" data-a="exit" aria-label="Exit step mode" title="Exit step mode (Esc)">\u2715\uFE0E</button>';
217
+ + '<button type="button" data-a="exit" aria-label="Exit step mode" title="Exit step mode (Esc)">' + ICON.exit + '</button>';
205
218
  const btn = (a) => bar.querySelector(`[data-a=${a}]`);
206
219
  const last = () => (cur()?.paSteps?.length ?? 1) - 1;
207
220
  const ui = () => {
208
- btn('prev').disabled = k <= 0;
209
- btn('next').disabled = k >= last();
210
- btn('play').textContent = timer ? '\u275A\u275A' : '\u25B6\uFE0E';
221
+ // aria-disabled, not `disabled`: a disabled button passes hover to the container, whose tooltip then shows over it
222
+ btn('prev').setAttribute('aria-disabled', String(k <= 0));
223
+ btn('next').setAttribute('aria-disabled', String(k >= last()));
224
+ btn('play').innerHTML = timer ? ICON.pause : ICON.play;
211
225
  const label = timer ? 'Pause (Space)' : 'Play (Space)';
212
226
  btn('play').setAttribute('aria-label', label);
213
227
  btn('play').title = label;
@@ -251,7 +265,8 @@ export function watch(container, source = '', { controls = true } = {}) {
251
265
  const actions = { prev: () => manual(k - 1), next: () => manual(k + 1), play: toggle, exit };
252
266
  bar.addEventListener('click', (e) => {
253
267
  e.stopPropagation(); // else the container's click would re-enter step mode right after Exit
254
- actions[e.target.closest('button')?.dataset.a]?.();
268
+ const b = e.target.closest('button');
269
+ if (b?.getAttribute('aria-disabled') !== 'true') actions[b?.dataset.a]?.();
255
270
  });
256
271
 
257
272
  const run = () => {
@@ -1,4 +1,4 @@
1
- // DoveRunner vocabulary (DRM / forensic watermarking / packaging). Add on top of the generic pack in glyphs.js.
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
- 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}"/>`,
16
- 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}"/>`,
17
- 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}"/>`,
18
- 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"/>`,
19
- 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}"/>`,
20
- 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}"/>`,
21
- 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}"/>`,
22
- 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>`,
23
- 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}"/>`,
24
- 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}"/>`,
25
- 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}"/>`,
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,23 @@
1
+ // Tabler Icons 3.49.0 (MIT, (c) Paweł Kuna), category "Animals". Generated by scripts/build-tabler.mjs; see THIRD-PARTY-NOTICES.md.
2
+ import { registerTabler } from '../glyphs.js';
3
+ export const pack = {
4
+ "bat": "<path d=\"M17 16c.74 -2.286 2.778 -3.762 5 -3c-.173 -2.595 .13 -5.314 -2 -7.5c-1.708 2.648 -3.358 2.557 -5 2.5v-4l-3 2l-3 -2v4c-1.642 .057 -3.292 .148 -5 -2.5c-2.13 2.186 -1.827 4.905 -2 7.5c2.222 -.762 4.26 .714 5 3c2.593 0 3.889 .952 5 4c1.111 -3.048 2.407 -4 5 -4\"/><path d=\"M9 8a3 3 0 0 0 6 0\"/>",
5
+ "cat": "<path d=\"M20 3v10a8 8 0 1 1 -16 0v-10l3.432 3.432a7.963 7.963 0 0 1 4.568 -1.432c1.769 0 3.403 .574 4.728 1.546l3.272 -3.546\"/><path d=\"M2 16h5l-4 4\"/><path d=\"M22 16h-5l4 4\"/><path d=\"M11 16a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\"/><path d=\"M9 11v.01\"/><path d=\"M15 11v.01\"/>",
6
+ "deer": "<path d=\"M3 3c0 2 1 3 4 3c2 0 3 1 3 3\"/><path d=\"M21 3c0 2 -1 3 -4 3c-2 0 -3 .333 -3 3\"/><path d=\"M12 18c-1 0 -4 -3 -4 -6c0 -2 1.333 -3 4 -3s4 1 4 3c0 3 -3 6 -4 6\"/><path d=\"M15.185 14.889l.095 -.18a4 4 0 1 1 -6.56 0\"/><path d=\"M17 3c0 1.333 -.333 2.333 -1 3\"/><path d=\"M7 3c0 1.333 .333 2.333 1 3\"/><path d=\"M7 6c-2.667 .667 -4.333 1.667 -5 3\"/><path d=\"M17 6c2.667 .667 4.333 1.667 5 3\"/><path d=\"M8.5 10l-1.5 -1\"/><path d=\"M15.5 10l1.5 -1\"/><path d=\"M12 15h.01\"/>",
7
+ "dog": "<path d=\"M11 5h2\"/><path d=\"M19 12c-.667 5.333 -2.333 8 -5 8h-4c-2.667 0 -4.333 -2.667 -5 -8\"/><path d=\"M11 16c0 .667 .333 1 1 1s1 -.333 1 -1h-2\"/><path d=\"M12 18v2\"/><path d=\"M10 11v.01\"/><path d=\"M14 11v.01\"/><path d=\"M5 4l6 .97l-6.238 6.688a1.021 1.021 0 0 1 -1.41 .111a.953 .953 0 0 1 -.327 -.954l1.975 -6.815\"/><path d=\"M19 4l-6 .97l6.238 6.688c.358 .408 .989 .458 1.41 .111a.953 .953 0 0 0 .327 -.954l-1.975 -6.815\"/>",
8
+ "dragon": "<path d=\"M10.706 8.849l-5.706 -3.301l-2 6.452l3.5 -1.973l.5 2.973l3.555 -1.385\"/><path d=\"M15 9c0 3.5 4 3 4 7c0 3 -3 5 -5.5 5s-6 -.5 -6.5 -5c2 2 6.592 3.043 7.5 1c1.094 -2.461 -4 -3.459 -4 -6.5c0 -2.062 .5 -2.5 1.8 -3.2\"/><path d=\"M18 6a3 3 270 1 0 -3 3h5l1 -3h-3\"/><path d=\"M15 3h-8l5 3\"/>",
9
+ "fish-bone": "<path d=\"M16.69 7.44a6.973 6.973 0 0 0 -1.69 4.56a6.97 6.97 0 0 0 1.699 4.571c1.914 -.684 3.691 -2.183 5.301 -4.565c-1.613 -2.384 -3.394 -3.883 -5.312 -4.565\"/><path d=\"M2 9.504a40.73 40.73 0 0 0 2.422 2.504a39.679 39.679 0 0 0 -2.422 2.498\"/><path d=\"M18 11v.01\"/><path d=\"M4.422 12h10.578\"/><path d=\"M7 10v4\"/><path d=\"M11 8v8\"/>",
10
+ "fish-hook-off": "<path d=\"M16 9v3m-.085 3.924a5 5 0 0 1 -9.915 -.924v-4l3 3\"/><path d=\"M14 7a2 2 0 1 0 4 0a2 2 0 1 0 -4 0\"/><path d=\"M16 5v-2\"/><path d=\"M3 3l18 18\"/>",
11
+ "fish-hook": "<path d=\"M16 9v6a5 5 0 0 1 -10 0v-4l3 3\"/><path d=\"M14 7a2 2 0 1 0 4 0a2 2 0 1 0 -4 0\"/><path d=\"M16 5v-2\"/>",
12
+ "fish-off": "<path d=\"M16.69 7.44a6.973 6.973 0 0 0 -1.63 3.635\"/><path d=\"M2 9.504c5.307 5.948 10.293 8.57 14.597 7.1m2.583 -1.449c.988 -.788 1.93 -1.836 2.82 -3.153c-3 -4.443 -6.596 -5.812 -10.564 -4.548m-2.764 1.266c-2.145 1.266 -4.378 3.215 -6.672 5.786\"/><path d=\"M18 11v.01\"/><path d=\"M11.153 11.169c-.287 .777 -.171 1.554 .347 2.331\"/><path d=\"M3 3l18 18\"/>",
13
+ "fish": "<path d=\"M16.69 7.44a6.973 6.973 0 0 0 -1.69 4.56c0 1.747 .64 3.345 1.699 4.571\"/><path d=\"M2 9.504c7.715 8.647 14.75 10.265 20 2.498c-5.25 -7.761 -12.285 -6.142 -20 2.504\"/><path d=\"M18 11v.01\"/><path d=\"M11.5 10.5c-.667 1 -.667 2 0 3\"/>",
14
+ "horse": "<path d=\"M7 10l-.85 8.507a1.357 1.357 0 0 0 1.35 1.493h.146a2 2 0 0 0 1.857 -1.257l.994 -2.486a2 2 0 0 1 1.857 -1.257h1.292a2 2 0 0 1 1.857 1.257l.994 2.486a2 2 0 0 0 1.857 1.257h.146a1.37 1.37 0 0 0 1.364 -1.494l-.864 -9.506h-8c0 -3 -3 -5 -6 -5l-3 6l2 2l3 -2\"/><path d=\"M22 14v-2a3 3 0 0 0 -3 -3\"/>",
15
+ "horseshoe": "<path d=\"M19 17c.5 -1.242 2 -2 2 -5s-1 -9 -9 -9s-9 6 -9 9s1.495 3.749 2 5l-2 1l2 3l2.406 -1.147c1.25 -.714 1.778 -2.08 1.203 -3.363c-1.078 -2.407 -1.609 -8.49 3.391 -8.49s4.469 6.083 3.39 8.49c-.574 1.284 -.045 2.649 1.204 3.363l2.406 1.147l2 -3l-2 -1\"/>",
16
+ "paw-off": "<path d=\"M11.168 11.154c-.71 .31 -1.184 1.107 -2 2.593c-.942 1.703 -2.846 1.845 -3.321 3.291c-.097 .265 -.145 .677 -.143 .962c0 1.176 .787 2 1.8 2c1.259 0 3 -1 4.5 -1s3.241 1 4.5 1c.927 0 1.664 -.689 1.783 -1.708\"/><path d=\"M20.188 8.082a1.039 1.039 0 0 0 -.406 -.082h-.015c-.735 .012 -1.56 .75 -1.993 1.866c-.519 1.335 -.28 2.7 .538 3.052c.129 .055 .267 .082 .406 .082c.739 0 1.575 -.742 2.011 -1.866c.516 -1.335 .273 -2.7 -.54 -3.052l-.001 0\"/><path d=\"M11 6.992a3.608 3.608 0 0 0 -.04 -.725c-.203 -1.297 -1.047 -2.267 -1.932 -2.267a1.237 1.237 0 0 0 -.758 .265\"/><path d=\"M16.456 6.733c.214 -1.376 -.375 -2.594 -1.32 -2.722a1.164 1.164 0 0 0 -.162 -.011c-.885 0 -1.728 .97 -1.93 2.267c-.214 1.376 .375 2.594 1.32 2.722c.054 .007 .108 .011 .162 .011c.885 0 1.73 -.974 1.93 -2.267\"/><path d=\"M5.69 12.918c.816 -.352 1.054 -1.719 .536 -3.052c-.436 -1.124 -1.271 -1.866 -2.009 -1.866c-.14 0 -.277 .027 -.407 .082c-.816 .352 -1.054 1.719 -.536 3.052c.436 1.124 1.271 1.866 2.009 1.866c.14 0 .277 -.027 .407 -.082\"/><path d=\"M3 3l18 18\"/>",
17
+ "paw": "<path d=\"M14.7 13.5c-1.1 -2 -1.441 -2.5 -2.7 -2.5c-1.259 0 -1.736 .755 -2.836 2.747c-.942 1.703 -2.846 1.845 -3.321 3.291c-.097 .265 -.145 .677 -.143 .962c0 1.176 .787 2 1.8 2c1.259 0 3 -1 4.5 -1s3.241 1 4.5 1c1.013 0 1.8 -.823 1.8 -2c0 -.285 -.049 -.697 -.146 -.962c-.475 -1.451 -2.512 -1.835 -3.454 -3.538\"/><path d=\"M20.188 8.082a1.039 1.039 0 0 0 -.406 -.082h-.015c-.735 .012 -1.56 .75 -1.993 1.866c-.519 1.335 -.28 2.7 .538 3.052c.129 .055 .267 .082 .406 .082c.739 0 1.575 -.742 2.011 -1.866c.516 -1.335 .273 -2.7 -.54 -3.052l-.001 0\"/><path d=\"M9.474 9c.055 0 .109 0 .163 -.011c.944 -.128 1.533 -1.346 1.32 -2.722c-.203 -1.297 -1.047 -2.267 -1.932 -2.267c-.055 0 -.109 0 -.163 .011c-.944 .128 -1.533 1.346 -1.32 2.722c.204 1.293 1.048 2.267 1.933 2.267\"/><path d=\"M16.456 6.733c.214 -1.376 -.375 -2.594 -1.32 -2.722a1.164 1.164 0 0 0 -.162 -.011c-.885 0 -1.728 .97 -1.93 2.267c-.214 1.376 .375 2.594 1.32 2.722c.054 .007 .108 .011 .162 .011c.885 0 1.73 -.974 1.93 -2.267\"/><path d=\"M5.69 12.918c.816 -.352 1.054 -1.719 .536 -3.052c-.436 -1.124 -1.271 -1.866 -2.009 -1.866c-.14 0 -.277 .027 -.407 .082c-.816 .352 -1.054 1.719 -.536 3.052c.436 1.124 1.271 1.866 2.009 1.866c.14 0 .277 -.027 .407 -.082\"/>",
18
+ "pig-money": "<path d=\"M15 11v.01\"/><path d=\"M5.173 8.378a3 3 0 1 1 4.656 -1.377\"/><path d=\"M16 4v3.803a6.019 6.019 0 0 1 2.658 3.197h1.341a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-1.342c-.336 .95 -.907 1.8 -1.658 2.473v2.027a1.5 1.5 0 0 1 -3 0v-.583a6.04 6.04 0 0 1 -1 .083h-4a6.04 6.04 0 0 1 -1 -.083v.583a1.5 1.5 0 0 1 -3 0v-2l0 -.027a6 6 0 0 1 4 -10.473h2.5l4.5 -3\"/>",
19
+ "pig-off": "<path d=\"M15 11v.01\"/><path d=\"M10 6h1.499l4.5 -3l0 3.803a6.019 6.019 0 0 1 2.658 3.197h1.341a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-1.342c-.057 .16 -.12 .318 -.19 .472m-1.467 2.528v1.5a1.5 1.5 0 0 1 -3 0v-.583a6.04 6.04 0 0 1 -1 .083h-4a6.04 6.04 0 0 1 -1 -.083v.583a1.5 1.5 0 0 1 -3 0v-2l0 -.027a6 6 0 0 1 1.5 -9.928\"/><path d=\"M3 3l18 18\"/>",
20
+ "pig": "<path d=\"M15 11v.01\"/><path d=\"M16 3l0 3.803a6.019 6.019 0 0 1 2.658 3.197h1.341a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-1.342a6.008 6.008 0 0 1 -1.658 2.473v2.027a1.5 1.5 0 0 1 -3 0v-.583a6.04 6.04 0 0 1 -1 .083h-4a6.04 6.04 0 0 1 -1 -.083v.583a1.5 1.5 0 0 1 -3 0v-2l0 -.027a6 6 0 0 1 4 -10.473h2.5l4.5 -3\"/>",
21
+ "spider": "<path d=\"M5 4v2l5 5\"/><path d=\"M2.5 9.5l1.5 1.5h6\"/><path d=\"M4 19v-2l6 -6\"/><path d=\"M19 4v2l-5 5\"/><path d=\"M21.5 9.5l-1.5 1.5h-6\"/><path d=\"M20 19v-2l-6 -6\"/><path d=\"M8 15a4 4 0 1 0 8 0a4 4 0 1 0 -8 0\"/><path d=\"M10 9a2 2 0 1 0 4 0a2 2 0 1 0 -4 0\"/>",
22
+ };
23
+ registerTabler(pack);