@pixerate/flair 0.8.0 → 0.10.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/CHANGELOG.md +21 -0
- package/README.md +13 -6
- package/dist/catalog/index.d.ts +9 -3
- package/dist/catalog/index.js +2 -1
- package/dist/chunk-OHW7UG6D.js +336 -0
- package/dist/chunk-OHW7UG6D.js.map +1 -0
- package/dist/chunk-P5TSANZY.js +1 -0
- package/dist/{chunk-EQS4EXNM.js → chunk-SH66CNLC.js} +52 -6
- package/dist/chunk-SH66CNLC.js.map +1 -0
- package/dist/{chunk-FHXOMIQY.js → chunk-STGGN4MR.js} +2185 -209
- package/dist/chunk-STGGN4MR.js.map +1 -0
- package/dist/{chunk-TDMD5XAU.js → chunk-YACVME3D.js} +75 -4
- package/dist/{chunk-TDMD5XAU.js.map → chunk-YACVME3D.js.map} +1 -1
- package/dist/{chunk-EZRRKQFV.js → chunk-YLJWC4N2.js} +96 -1
- package/dist/chunk-YLJWC4N2.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/editor/index.d.ts +3 -4
- package/dist/editor/index.js +5 -4
- package/dist/editor/index.js.map +1 -1
- package/dist/index.d.ts +65 -6
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/dist/{renderer-0_Ap1tyi.d.ts → renderer-SNYZu__R.d.ts} +17 -0
- package/dist/svg-CpeanaE_.d.ts +375 -0
- package/dist/{types-CNPIrnTf.d.ts → types-D8uhzDyN.d.ts} +8 -2
- package/dist/vector/index.d.ts +21 -112
- package/dist/vector/index.js +8 -2
- package/package.json +1 -1
- package/dist/chunk-CFCLT2XL.js +0 -1
- package/dist/chunk-EQS4EXNM.js.map +0 -1
- package/dist/chunk-EZRRKQFV.js.map +0 -1
- package/dist/chunk-FHXOMIQY.js.map +0 -1
- package/dist/clock-BhdXWH-n.d.ts +0 -47
- package/dist/motion-Ce0lmzm3.d.ts +0 -179
- /package/dist/{chunk-CFCLT2XL.js.map → chunk-P5TSANZY.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @pixerate/flair
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7542ad5: Interaction: pointer uniforms, `SvgPlayer` triggers and 21 interaction effects.
|
|
8
|
+
|
|
9
|
+
- Shaders get two new built-ins: `iPointer` (xy while over the canvas, eased hover amount, seconds held or minus seconds since release) and `iClicks[8]` (the latest clicks: xy, `iTime` of the click, 1). `ShaderRenderer`, standalone pages and hovered `ThumbnailPool` thumbnails feed them; `ShaderFrames.render` takes `pointer` and `clicks` for scripted recordings. `PointerTracker`, `clicksUniform`, `MAX_CLICKS` and `HOVER_SECONDS` are exported.
|
|
10
|
+
- `SvgPlayer` takes `trigger: "hover" | "press" | "click"` (and `triggerTarget`): hover and press play forward while active and back after; click plays the next step on each click, wrapping round. `setActive(on)` and `advance()` let hosts drive it. Vector effects declare `trigger`.
|
|
11
|
+
- **interaction** (new category): click ripple, click burst, cursor glow, hover liquid, X-ray reveal, magnifier, holo card, press charge and hover swap shaders (each with an idle demo), and like button, toggle switch, checkbox, menu toggle, bookmark, copy, send and download buttons, link hover, button hover fill, tooltip pop and press button vector effects.
|
|
12
|
+
|
|
13
|
+
## 0.9.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- bf62436: Morphs: `morphPaths` / `morphSequence` and 13 new effects.
|
|
18
|
+
|
|
19
|
+
- `morphPaths(from, to)` and `morphSequence(paths)` in `/vector` turn any SVG paths (curves, arcs, relative commands, several pieces) into paths with one structure, so an `attrs` change on `d` blends them. Pieces pair by position and size; one without a partner grows from or shrinks to a point.
|
|
20
|
+
- **morph** (new category): feature morph (two photos, five matching points), silhouette morph (any silhouettes, logos or `textImage` words), and vector shape morph, icon toggle (play/pause, menu/close, plus/check, sun/moon, heart), morph sequence, gooey morph, particle morph and digit morph.
|
|
21
|
+
- **transition**: liquid morph, displacement, luma fade, particle swap and ink bleed.
|
|
22
|
+
- `SAMPLE_IMAGES` gains `portrait2`, `logo` and `heart`.
|
|
23
|
+
|
|
3
24
|
## 0.8.0
|
|
4
25
|
|
|
5
26
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -19,13 +19,14 @@ Flair gives products a library of good-looking, configurable visual effects (her
|
|
|
19
19
|
|
|
20
20
|
### Core Capabilities
|
|
21
21
|
|
|
22
|
-
- 🎨 **Effect catalog (`@pixerate/flair/catalog`)**:
|
|
22
|
+
- 🎨 **Effect catalog (`@pixerate/flair/catalog`)**: 132 effects, each with controls and presets. There are 84 WebGL2 shaders (gradients, organic textures, patterns, light, space, retro, image treatments, transparent overlays, text fills, image morphs, pointer interactions, transitions) and 48 animated SVG effects (loaders, status icons, animated titles, shape morphs, UI micro-interactions, charts, counters, node graphs). [Browse them live](https://pixerate.github.io/flair/).
|
|
23
23
|
- ⚡ **Shader engine**:
|
|
24
24
|
- Shadertoy-style GLSL ES 3.00 fragment shaders, with controls declared in the source (`// @control`), including image inputs.
|
|
25
25
|
- Compile errors come back with line numbers that match the source.
|
|
26
|
+
- Pointer input beyond Shadertoy's `iMouse`: `iPointer` (position while over the canvas, eased hover amount, seconds held or since release) and `iClicks[8]` (the latest clicks' positions and times), so effects answer hovers, presses and taps. `ShaderRenderer` and standalone pages feed them; `ShaderFrames` takes scripted `pointer` and `clicks` for recordings.
|
|
26
27
|
- Live previews (`ShaderRenderer`, with optional `{ alpha: true }` for transparent overlays) and many animated or hover-activated thumbnails on one context (`ThumbnailPool`).
|
|
27
28
|
- Frames at exact times (`ShaderFrames`), looping GIFs, and standalone HTML pages.
|
|
28
|
-
- ✒️ **Vector motion (`@pixerate/flair/vector`)**: animated SVG described as data. Catalog vector effects declare their controls in the picture (`{{name: type …}}`), text included. It covers attribute tweens, draw-on strokes, motion along paths, counters (`animateCount` / `formatCount` for DOM elements too), text written letter by letter (`write`, with `scramble` and `caret`) and view zooms. Every frame is a pure function of time (`svgFrame`), and `SvgPlayer` plays it (with `scrollTrigger`, `hideWhenPaused`,
|
|
29
|
+
- ✒️ **Vector motion (`@pixerate/flair/vector`)**: animated SVG described as data. Catalog vector effects declare their controls in the picture (`{{name: type …}}`), text included. It covers attribute tweens, draw-on strokes, motion along paths, counters (`animateCount` / `formatCount` for DOM elements too), text written letter by letter (`write`, with `scramble` and `caret`), shape morphs between any paths (`morphPaths`, `morphSequence`) and view zooms. Every frame is a pure function of time (`svgFrame`), and `SvgPlayer` plays it (with `scrollTrigger`, `hideWhenPaused`, `reset()`, and `trigger: "hover" | "press" | "click"` to play in answer to the pointer).
|
|
29
30
|
- 🎛️ **Effect editor (`@pixerate/flair/editor`)**:
|
|
30
31
|
- A headless editor for an effect's source, values, keyframes, presets and timeline.
|
|
31
32
|
- Built on [`@pixerate/editor`](https://github.com/Pixerate/editor)'s undo history and command registry, with no UI framework assumed.
|
|
@@ -42,7 +43,7 @@ Flair gives products a library of good-looking, configurable visual effects (her
|
|
|
42
43
|
| :--- | :--- | :--- |
|
|
43
44
|
| `@pixerate/flair` | Shader engine, vector motion, time and easing, colour, blending, transitions, scenes, interchange exporters | None (browser-safe) |
|
|
44
45
|
| `@pixerate/flair/catalog` | `EFFECTS`, `getEffect`, `findEffects`, `effectDefaults`, `renderVectorEffect`, `vectorControls`, GLSL helpers, sample images, `textImage` | None |
|
|
45
|
-
| `@pixerate/flair/vector` | `SvgMotion`, `svgFrame`, `svgView`, `SvgPlayer`, `animateCount`, `formatCount`, `svgMotionIssues` | None |
|
|
46
|
+
| `@pixerate/flair/vector` | `SvgMotion`, `svgFrame`, `svgView`, `SvgPlayer`, `animateCount`, `formatCount`, `morphPaths`, `morphSequence`, `svgMotionIssues` | None |
|
|
46
47
|
| `@pixerate/flair/editor` | `EffectEditor`, effect documents, keyframe tracks, renderer bindings, parameter-panel binding, agent tools and instructions | `@pixerate/editor` ≥ 0.29 (optional peer; only its dependency-free `/history`, `/commands`, `/tools`, `/animation` and `/parameters` subpaths) |
|
|
47
48
|
| `@pixerate/flair/node` | `exportMotionGraphic`: renders a shader to GIF/MP4 through headless Chrome and ffmpeg | Node.js |
|
|
48
49
|
|
|
@@ -55,7 +56,7 @@ The `flair` CLI inspects shaders, writes standalone pages and directs scenes (se
|
|
|
55
56
|
```mermaid
|
|
56
57
|
graph TD
|
|
57
58
|
subgraph Effects["Effects (no dependencies)"]
|
|
58
|
-
Catalog["catalog:
|
|
59
|
+
Catalog["catalog: 132 effects + presets"]
|
|
59
60
|
Shader["shader engine: controls, compile, render, GIF, HTML"]
|
|
60
61
|
Vector["vector motion: SvgMotion, SvgPlayer"]
|
|
61
62
|
Time["time: clocks, easing, keyframes, noise"]
|
|
@@ -131,7 +132,11 @@ animateCount({
|
|
|
131
132
|
|
|
132
133
|
Find effects with `findEffects({ text: "glow", category: "light", kind: "shader" })`. Each effect has an `id`, `name`, `description`, `category`, `tags` and optional `presets`. Image effects default to built-in sample pictures, so they look right before you set `uImage` to your own URL.
|
|
133
134
|
|
|
134
|
-
Overlay shaders (`category: "overlay"`) have `transparent: true`: they write coverage to `fragColor.a` and draw nothing elsewhere, so render them with `new ShaderRenderer(host, { alpha: true })` (or `new ThumbnailPool({ alpha: true })`) and lay the canvas over a picture, video or page. `
|
|
135
|
+
Overlay shaders (`category: "overlay"`) have `transparent: true`: they write coverage to `fragColor.a` and draw nothing elsewhere, so render them with `new ShaderRenderer(host, { alpha: true })` (or `new ThumbnailPool({ alpha: true })`) and lay the canvas over a picture, video or page. Interaction effects answer the pointer. Interactive shaders read `iPointer` and `iClicks`, so they work in any `ShaderRenderer` with no wiring, and play an idle demo when nobody is pointing (turn off "Demo when idle" to stop it). Vector micro-interactions carry a `trigger`: pass it to the player, `new SvgPlayer(host, renderVectorEffect(effect), { trigger: effect.trigger })`. A hover or press trigger plays to the end while hovered or held and back again after; a click trigger plays the next step on each click, so toggles turn on and off. Hosts can drive them too, with `player.setActive(on)` and `player.advance()` (from a keyboard handler, say).
|
|
136
|
+
|
|
137
|
+
To morph between any two SVG shapes, `morphPaths(from, to)` (from `@pixerate/flair/vector`) returns two paths with one structure, so `attrs: { d: [a, b] }` blends them point by point: curves and arcs are read, pieces are paired by position and size, and a piece with no partner grows from or shrinks to a point (draw them with `fill-rule="evenodd"`). `morphSequence` does the same for three or more shapes. `feature-morph` morphs two photos from five matching points, and `silhouette-morph` morphs any two silhouettes or logos (or words, through `textImage`).
|
|
138
|
+
|
|
139
|
+
`shader-text` fills letters from a text image: set its `uText` control to `textImage("Your title", { weight: 900 })`, a transparent SVG `data:` URL of any Unicode text.
|
|
135
140
|
|
|
136
141
|
A vector effect declares its controls in its picture, the way a shader declares its uniforms: the first `{{name: type …}}` declares a control (`float`, `int`, `bool`, `color` or `text`, with `@control`'s attributes; quote values with spaces in single quotes), and every `{{name}}` is filled with its value. Declarations can sit in an XML comment, which is dropped when the picture is filled in, and text is escaped, so any words are safe:
|
|
137
142
|
|
|
@@ -270,7 +275,9 @@ The exporters carry the camera too:
|
|
|
270
275
|
| image | ripple, glitch, duotone, halftone, pixel reveal, Ken Burns, ASCII art, shatter, melt, risograph, thermal, edge glow, tilt-shift, slit-scan, mosaic flip, chromatic lens, oil paint, CRT screen, film look |
|
|
271
276
|
| overlay | rain on glass, snowfall, lens flare, vignette & grain, scanline sweep, spotlight, embers, shine sweep, frost creep, viewfinder |
|
|
272
277
|
| text | shader text, drip text, typewriter, scramble text, kinetic stagger, neon sign, stroke draw text, split reveal, highlighter, word cycle, liquid fill, glitch text, extruded text |
|
|
273
|
-
|
|
|
278
|
+
| morph | feature morph, silhouette morph, shape morph, icon toggle, morph sequence, gooey morph, particle morph, digit morph |
|
|
279
|
+
| interaction | click ripple, click burst, cursor glow, hover liquid, X-ray reveal, magnifier, holo card, press charge, hover swap, like button, toggle switch, checkbox, menu toggle, bookmark, copy button, send button, download button, link hover, button hover fill, tooltip pop, press button |
|
|
280
|
+
| transition | liquid morph, displacement, luma fade, particle swap, ink bleed, wipe, iris, block dissolve, grid wipe, glass wipe, twister, light leak, cross zoom |
|
|
274
281
|
| loader / icon / data | spinner, bouncing dots, pulse ping, equalizer, progress ring, bar chart, line chart, stat counter, route, timeline track, success check, error cross, heartbeat, signature, confetti, flow network |
|
|
275
282
|
|
|
276
283
|
Every shader is self-contained and compiles on WebGL2. Open [`#check`](https://pixerate.github.io/flair/#check) on the demo to compile the catalog on your own GPU.
|
package/dist/catalog/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as ControlDef, C as ControlValue } from '../controls-Syr6drzO.js';
|
|
2
|
-
import { E as EffectDefinition, a as EffectCategory, S as ShaderEffect } from '../types-
|
|
3
|
-
export { b as EFFECT_CATEGORIES, c as EffectPreset, V as VECTOR_CONTROL_TYPES, d as VectorControl, e as VectorEffect, f as colorControl, n as numberControl, r as renderVectorEffect, v as vectorControlDef, g as vectorControlIssues, h as vectorControls, i as vectorEffectControls } from '../types-
|
|
4
|
-
import '../
|
|
2
|
+
import { E as EffectDefinition, a as EffectCategory, S as ShaderEffect } from '../types-D8uhzDyN.js';
|
|
3
|
+
export { b as EFFECT_CATEGORIES, c as EffectPreset, V as VECTOR_CONTROL_TYPES, d as VectorControl, e as VectorEffect, f as colorControl, n as numberControl, r as renderVectorEffect, v as vectorControlDef, g as vectorControlIssues, h as vectorControls, i as vectorEffectControls } from '../types-D8uhzDyN.js';
|
|
4
|
+
import '../svg-CpeanaE_.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Sample pictures for the catalog's image effects: small SVGs as `data:` URLs,
|
|
@@ -14,6 +14,12 @@ declare const SAMPLE_IMAGES: {
|
|
|
14
14
|
readonly landscape: string;
|
|
15
15
|
readonly city: string;
|
|
16
16
|
readonly portrait: string;
|
|
17
|
+
/** Another face, larger and to the right: morph it with `portrait`. */
|
|
18
|
+
readonly portrait2: string;
|
|
19
|
+
/** A ring-and-dot mark, indigo on transparent. */
|
|
20
|
+
readonly logo: string;
|
|
21
|
+
/** A heart, rose on transparent. */
|
|
22
|
+
readonly heart: string;
|
|
17
23
|
};
|
|
18
24
|
interface TextImageOptions {
|
|
19
25
|
/** CSS font family (default a heavy system sans-serif). */
|
package/dist/catalog/index.js
CHANGED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
// src/vector/morph.ts
|
|
2
|
+
var CURVE_STEPS = 24;
|
|
3
|
+
var TOKEN = /[MmLlHhVvCcSsQqTtAaZz]|-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?/gi;
|
|
4
|
+
var ARGS = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0 };
|
|
5
|
+
function flatten(d) {
|
|
6
|
+
const stray = d.replace(TOKEN, "").replace(/[\s,]+/g, "");
|
|
7
|
+
if (stray) throw new Error(`"${stray[0]}" is not a path command`);
|
|
8
|
+
const tokens = d.match(TOKEN) ?? [];
|
|
9
|
+
const rings = [];
|
|
10
|
+
let ring = null;
|
|
11
|
+
let x = 0;
|
|
12
|
+
let y = 0;
|
|
13
|
+
let startX = 0;
|
|
14
|
+
let startY = 0;
|
|
15
|
+
let cx = 0;
|
|
16
|
+
let cy = 0;
|
|
17
|
+
let prev = "";
|
|
18
|
+
let i = 0;
|
|
19
|
+
let command = "";
|
|
20
|
+
const add = (px, py) => ring.points.push([px, py]);
|
|
21
|
+
const begin = (px, py) => {
|
|
22
|
+
if (ring && ring.points.length) rings.push(ring);
|
|
23
|
+
ring = { points: [[px, py]], closed: false };
|
|
24
|
+
};
|
|
25
|
+
while (i < tokens.length) {
|
|
26
|
+
if (/[a-z]/i.test(tokens[i])) command = tokens[i++];
|
|
27
|
+
else if (!command) throw new Error(`"${tokens[i]}" needs a command (M, L, C, \u2026) before it`);
|
|
28
|
+
const lower = command.toLowerCase();
|
|
29
|
+
if (!(lower in ARGS)) throw new Error(`Unknown path command "${command}"`);
|
|
30
|
+
const rel = command !== command.toUpperCase();
|
|
31
|
+
const n = ARGS[lower];
|
|
32
|
+
const args = tokens.slice(i, i + n).map(Number);
|
|
33
|
+
if (args.length < n || args.some((v) => Number.isNaN(v))) break;
|
|
34
|
+
i += n;
|
|
35
|
+
const ox = rel ? x : 0;
|
|
36
|
+
const oy = rel ? y : 0;
|
|
37
|
+
if (lower === "z") {
|
|
38
|
+
if (ring) {
|
|
39
|
+
ring.closed = true;
|
|
40
|
+
rings.push(ring);
|
|
41
|
+
ring = null;
|
|
42
|
+
}
|
|
43
|
+
x = startX;
|
|
44
|
+
y = startY;
|
|
45
|
+
prev = "z";
|
|
46
|
+
command = "";
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (!ring) begin(x, y);
|
|
50
|
+
switch (lower) {
|
|
51
|
+
case "m":
|
|
52
|
+
x = ox + args[0];
|
|
53
|
+
y = oy + args[1];
|
|
54
|
+
startX = x;
|
|
55
|
+
startY = y;
|
|
56
|
+
begin(x, y);
|
|
57
|
+
command = rel ? "l" : "L";
|
|
58
|
+
break;
|
|
59
|
+
case "l":
|
|
60
|
+
x = ox + args[0];
|
|
61
|
+
y = oy + args[1];
|
|
62
|
+
add(x, y);
|
|
63
|
+
break;
|
|
64
|
+
case "h":
|
|
65
|
+
x = ox + args[0];
|
|
66
|
+
add(x, y);
|
|
67
|
+
break;
|
|
68
|
+
case "v":
|
|
69
|
+
y = (rel ? y : 0) + args[0];
|
|
70
|
+
add(x, y);
|
|
71
|
+
break;
|
|
72
|
+
case "c":
|
|
73
|
+
case "s": {
|
|
74
|
+
let x1;
|
|
75
|
+
let y1;
|
|
76
|
+
let rest;
|
|
77
|
+
if (lower === "c") {
|
|
78
|
+
x1 = ox + args[0];
|
|
79
|
+
y1 = oy + args[1];
|
|
80
|
+
rest = args.slice(2);
|
|
81
|
+
} else {
|
|
82
|
+
const smooth = prev === "c" || prev === "s";
|
|
83
|
+
x1 = smooth ? 2 * x - cx : x;
|
|
84
|
+
y1 = smooth ? 2 * y - cy : y;
|
|
85
|
+
rest = args;
|
|
86
|
+
}
|
|
87
|
+
const x2 = ox + rest[0];
|
|
88
|
+
const y2 = oy + rest[1];
|
|
89
|
+
const ex = ox + rest[2];
|
|
90
|
+
const ey = oy + rest[3];
|
|
91
|
+
for (let k = 1; k <= CURVE_STEPS; k++) {
|
|
92
|
+
const t = k / CURVE_STEPS;
|
|
93
|
+
const u = 1 - t;
|
|
94
|
+
add(
|
|
95
|
+
u * u * u * x + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * ex,
|
|
96
|
+
u * u * u * y + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * ey
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
cx = x2;
|
|
100
|
+
cy = y2;
|
|
101
|
+
x = ex;
|
|
102
|
+
y = ey;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case "q":
|
|
106
|
+
case "t": {
|
|
107
|
+
let x1;
|
|
108
|
+
let y1;
|
|
109
|
+
let ex;
|
|
110
|
+
let ey;
|
|
111
|
+
if (lower === "q") {
|
|
112
|
+
x1 = ox + args[0];
|
|
113
|
+
y1 = oy + args[1];
|
|
114
|
+
ex = ox + args[2];
|
|
115
|
+
ey = oy + args[3];
|
|
116
|
+
} else {
|
|
117
|
+
const smooth = prev === "q" || prev === "t";
|
|
118
|
+
x1 = smooth ? 2 * x - cx : x;
|
|
119
|
+
y1 = smooth ? 2 * y - cy : y;
|
|
120
|
+
ex = ox + args[0];
|
|
121
|
+
ey = oy + args[1];
|
|
122
|
+
}
|
|
123
|
+
for (let k = 1; k <= CURVE_STEPS; k++) {
|
|
124
|
+
const t = k / CURVE_STEPS;
|
|
125
|
+
const u = 1 - t;
|
|
126
|
+
add(u * u * x + 2 * u * t * x1 + t * t * ex, u * u * y + 2 * u * t * y1 + t * t * ey);
|
|
127
|
+
}
|
|
128
|
+
cx = x1;
|
|
129
|
+
cy = y1;
|
|
130
|
+
x = ex;
|
|
131
|
+
y = ey;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case "a": {
|
|
135
|
+
const ex = ox + args[5];
|
|
136
|
+
const ey = oy + args[6];
|
|
137
|
+
for (const p of arcPoints(x, y, args[0], args[1], args[2], args[3] !== 0, args[4] !== 0, ex, ey)) add(p[0], p[1]);
|
|
138
|
+
x = ex;
|
|
139
|
+
y = ey;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
prev = lower;
|
|
144
|
+
}
|
|
145
|
+
if (ring && ring.points.length) rings.push(ring);
|
|
146
|
+
return rings.map((r) => {
|
|
147
|
+
const [a, b] = [r.points[0], r.points[r.points.length - 1]];
|
|
148
|
+
const closes = r.points.length > 2 && Math.hypot(a[0] - b[0], a[1] - b[1]) < 1e-6;
|
|
149
|
+
return { points: closes ? r.points.slice(0, -1) : r.points, closed: r.closed || closes };
|
|
150
|
+
}).filter((r) => r.points.length > 1);
|
|
151
|
+
}
|
|
152
|
+
function arcPoints(x1, y1, rx, ry, angle, large, sweep, x2, y2) {
|
|
153
|
+
rx = Math.abs(rx);
|
|
154
|
+
ry = Math.abs(ry);
|
|
155
|
+
if (!rx || !ry || x1 === x2 && y1 === y2) return [[x2, y2]];
|
|
156
|
+
const phi = angle * Math.PI / 180;
|
|
157
|
+
const cos = Math.cos(phi);
|
|
158
|
+
const sin = Math.sin(phi);
|
|
159
|
+
const dx = (x1 - x2) / 2;
|
|
160
|
+
const dy = (y1 - y2) / 2;
|
|
161
|
+
const x1p = cos * dx + sin * dy;
|
|
162
|
+
const y1p = -sin * dx + cos * dy;
|
|
163
|
+
const lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
|
|
164
|
+
if (lambda > 1) {
|
|
165
|
+
rx *= Math.sqrt(lambda);
|
|
166
|
+
ry *= Math.sqrt(lambda);
|
|
167
|
+
}
|
|
168
|
+
const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
|
|
169
|
+
const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;
|
|
170
|
+
const k = (large === sweep ? -1 : 1) * Math.sqrt(Math.max(0, num / den));
|
|
171
|
+
const cxp = k * rx * y1p / ry;
|
|
172
|
+
const cyp = -k * ry * x1p / rx;
|
|
173
|
+
const cx = cos * cxp - sin * cyp + (x1 + x2) / 2;
|
|
174
|
+
const cy = sin * cxp + cos * cyp + (y1 + y2) / 2;
|
|
175
|
+
const theta = (ux, uy, vx, vy) => Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);
|
|
176
|
+
const start = theta(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
|
|
177
|
+
let delta = theta((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);
|
|
178
|
+
if (!sweep && delta > 0) delta -= 2 * Math.PI;
|
|
179
|
+
if (sweep && delta < 0) delta += 2 * Math.PI;
|
|
180
|
+
const steps = Math.max(2, Math.ceil(Math.abs(delta) / (Math.PI / 2) * (CURVE_STEPS / 2)));
|
|
181
|
+
const out = [];
|
|
182
|
+
for (let s = 1; s <= steps; s++) {
|
|
183
|
+
const t = start + delta * s / steps;
|
|
184
|
+
const px = rx * Math.cos(t);
|
|
185
|
+
const py = ry * Math.sin(t);
|
|
186
|
+
out.push([cos * px - sin * py + cx, sin * px + cos * py + cy]);
|
|
187
|
+
}
|
|
188
|
+
out[out.length - 1] = [x2, y2];
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
function resample(ring, n) {
|
|
192
|
+
const pts = ring.closed ? [...ring.points, ring.points[0]] : [...ring.points, ...ring.points.slice(0, -1).reverse()];
|
|
193
|
+
const lengths = [0];
|
|
194
|
+
for (let i = 1; i < pts.length; i++)
|
|
195
|
+
lengths.push(lengths[i - 1] + Math.hypot(pts[i][0] - pts[i - 1][0], pts[i][1] - pts[i - 1][1]));
|
|
196
|
+
const total = lengths[lengths.length - 1];
|
|
197
|
+
if (total === 0) return Array.from({ length: n }, () => [pts[0][0], pts[0][1]]);
|
|
198
|
+
const out = [];
|
|
199
|
+
let j = 1;
|
|
200
|
+
for (let k = 0; k < n; k++) {
|
|
201
|
+
const at = k / n * total;
|
|
202
|
+
while (j < lengths.length - 1 && lengths[j] < at) j++;
|
|
203
|
+
const seg = lengths[j] - lengths[j - 1];
|
|
204
|
+
const t = seg > 0 ? (at - lengths[j - 1]) / seg : 0;
|
|
205
|
+
const a = pts[j - 1];
|
|
206
|
+
const b = pts[j];
|
|
207
|
+
out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);
|
|
208
|
+
}
|
|
209
|
+
return out;
|
|
210
|
+
}
|
|
211
|
+
var signedArea = (pts) => {
|
|
212
|
+
let sum = 0;
|
|
213
|
+
for (let i = 0; i < pts.length; i++) {
|
|
214
|
+
const a = pts[i];
|
|
215
|
+
const b = pts[(i + 1) % pts.length];
|
|
216
|
+
sum += a[0] * b[1] - b[0] * a[1];
|
|
217
|
+
}
|
|
218
|
+
return sum / 2;
|
|
219
|
+
};
|
|
220
|
+
var centroid = (pts) => {
|
|
221
|
+
let x = 0;
|
|
222
|
+
let y = 0;
|
|
223
|
+
for (const p of pts) {
|
|
224
|
+
x += p[0];
|
|
225
|
+
y += p[1];
|
|
226
|
+
}
|
|
227
|
+
return [x / pts.length, y / pts.length];
|
|
228
|
+
};
|
|
229
|
+
function size(ring, pts) {
|
|
230
|
+
const area = Math.abs(signedArea(pts));
|
|
231
|
+
if (ring.closed && area > 0) return area;
|
|
232
|
+
let length = 0;
|
|
233
|
+
for (let i = 1; i < ring.points.length; i++)
|
|
234
|
+
length += Math.hypot(ring.points[i][0] - ring.points[i - 1][0], ring.points[i][1] - ring.points[i - 1][1]);
|
|
235
|
+
return length;
|
|
236
|
+
}
|
|
237
|
+
function assign(before, pieces, scale) {
|
|
238
|
+
const out = before.map(() => null);
|
|
239
|
+
const pairs = [];
|
|
240
|
+
before.forEach((slot, s) => {
|
|
241
|
+
if (!slot) return;
|
|
242
|
+
pieces.forEach((p, i) => {
|
|
243
|
+
const distance = Math.hypot(slot.centre[0] - p.centre[0], slot.centre[1] - p.centre[1]) / scale;
|
|
244
|
+
const likeness = Math.abs(Math.log((slot.size + 1e-9) / (p.size + 1e-9)));
|
|
245
|
+
pairs.push({ slot: s, piece: i, cost: distance + 0.5 * likeness });
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
pairs.sort((a, b) => a.cost - b.cost);
|
|
249
|
+
const used = /* @__PURE__ */ new Set();
|
|
250
|
+
for (const { slot, piece } of pairs) {
|
|
251
|
+
if (out[slot] || used.has(piece)) continue;
|
|
252
|
+
out[slot] = pieces[piece];
|
|
253
|
+
used.add(piece);
|
|
254
|
+
}
|
|
255
|
+
let free = 0;
|
|
256
|
+
pieces.forEach((p, i) => {
|
|
257
|
+
if (used.has(i)) return;
|
|
258
|
+
while (out[free] || before[free]) free++;
|
|
259
|
+
out[free] = p;
|
|
260
|
+
});
|
|
261
|
+
return out;
|
|
262
|
+
}
|
|
263
|
+
function align(ref, pts) {
|
|
264
|
+
const n = pts.length;
|
|
265
|
+
let best = pts;
|
|
266
|
+
let bestCost = Infinity;
|
|
267
|
+
for (const candidate of [pts, [...pts].reverse()]) {
|
|
268
|
+
for (let shift = 0; shift < n; shift++) {
|
|
269
|
+
let cost = 0;
|
|
270
|
+
for (let k = 0; k < n && cost < bestCost; k++) {
|
|
271
|
+
const a = ref[k];
|
|
272
|
+
const b = candidate[(k + shift) % n];
|
|
273
|
+
cost += (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;
|
|
274
|
+
}
|
|
275
|
+
if (cost < bestCost) {
|
|
276
|
+
bestCost = cost;
|
|
277
|
+
best = candidate.slice(shift).concat(candidate.slice(0, shift));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return best;
|
|
282
|
+
}
|
|
283
|
+
function morphSequence(paths, options = {}) {
|
|
284
|
+
const n = Math.max(8, Math.round(options.points ?? 72));
|
|
285
|
+
const decimals = options.decimals ?? 2;
|
|
286
|
+
const shapes = paths.map((d, i) => {
|
|
287
|
+
let rings;
|
|
288
|
+
try {
|
|
289
|
+
rings = flatten(d);
|
|
290
|
+
} catch (e) {
|
|
291
|
+
throw new Error(`Path ${i + 1} cannot be read: ${e.message}`);
|
|
292
|
+
}
|
|
293
|
+
if (!rings.length) throw new Error(`Path ${i + 1} draws nothing: give it at least two points`);
|
|
294
|
+
return rings.map((r) => {
|
|
295
|
+
const pts = resample(r, n);
|
|
296
|
+
return { pts, centre: centroid(pts), size: size(r, pts) };
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
if (!shapes.length) return [];
|
|
300
|
+
const slots = Math.max(...shapes.map((s) => s.length));
|
|
301
|
+
const xs = shapes.flat().flatMap((p) => p.pts.map((q) => q[0]));
|
|
302
|
+
const ys = shapes.flat().flatMap((p) => p.pts.map((q) => q[1]));
|
|
303
|
+
const scale = Math.max(1e-6, Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));
|
|
304
|
+
const first = [...shapes[0]].sort((a, b) => b.size - a.size);
|
|
305
|
+
const assigned = [[...first, ...Array(slots - first.length).fill(null)]];
|
|
306
|
+
for (let i = 1; i < shapes.length; i++) assigned.push(assign(assigned[i - 1], shapes[i], scale));
|
|
307
|
+
const resolved = assigned.map(
|
|
308
|
+
(shape, i) => shape.map((piece, s) => {
|
|
309
|
+
if (piece) return piece.pts;
|
|
310
|
+
for (let k = 1; k < shapes.length; k++) {
|
|
311
|
+
const near = assigned[(i + k) % shapes.length][s] ?? assigned[(i - k + shapes.length) % shapes.length][s];
|
|
312
|
+
if (near) return Array.from({ length: n }, () => [near.centre[0], near.centre[1]]);
|
|
313
|
+
}
|
|
314
|
+
return Array.from({ length: n }, () => [0, 0]);
|
|
315
|
+
})
|
|
316
|
+
);
|
|
317
|
+
for (let i = 1; i < resolved.length; i++)
|
|
318
|
+
resolved[i] = resolved[i].map((pts, s) => align(resolved[i - 1][s], pts));
|
|
319
|
+
const num = (v) => {
|
|
320
|
+
const r = Number(v.toFixed(decimals));
|
|
321
|
+
return String(Object.is(r, -0) ? 0 : r);
|
|
322
|
+
};
|
|
323
|
+
return resolved.map(
|
|
324
|
+
(shape) => shape.map((pts) => `M${pts.map((p) => `${num(p[0])} ${num(p[1])}`).join(" L")} Z`).join(" ")
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
function morphPaths(from, to, options = {}) {
|
|
328
|
+
const [a, b] = morphSequence([from, to], options);
|
|
329
|
+
return [a, b];
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export {
|
|
333
|
+
morphSequence,
|
|
334
|
+
morphPaths
|
|
335
|
+
};
|
|
336
|
+
//# sourceMappingURL=chunk-OHW7UG6D.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vector/morph.ts"],"sourcesContent":["/**\n * Shape morphing: any SVG paths turned into paths with the same structure, so\n * an `attrs` change on `d` (see `SvgAnimation`) blends one into the other\n * point by point. Pure functions of their arguments, with no DOM.\n */\n\ntype Point = [number, number];\n\n/** One piece of a path: its outline as points, and whether it closes. */\ninterface Ring {\n points: Point[];\n closed: boolean;\n}\n\nexport interface MorphOptions {\n /** Points per piece of the shape (default 72): more follows curves more closely. */\n points?: number;\n /** Decimals in the numbers written (default 2). */\n decimals?: number;\n}\n\n/** Segments a curve is split into before resampling. */\nconst CURVE_STEPS = 24;\n\nconst TOKEN = /[MmLlHhVvCcSsQqTtAaZz]|-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\n\n/** Arguments each command takes (repeated commands take them again). */\nconst ARGS: Record<string, number> = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0 };\n\n/**\n * The pieces of a path's `d` as outlines: lines kept, curves and arcs split\n * into short lines. Throws on a command it does not know.\n */\nfunction flatten(d: string): Ring[] {\n const stray = d.replace(TOKEN, \"\").replace(/[\\s,]+/g, \"\");\n if (stray) throw new Error(`\"${stray[0]}\" is not a path command`);\n const tokens = d.match(TOKEN) ?? [];\n const rings: Ring[] = [];\n // Typed by a cast: the helpers below assign it, which narrowing would miss.\n let ring = null as Ring | null;\n let x = 0;\n let y = 0;\n let startX = 0;\n let startY = 0;\n // The last control point, for S and T.\n let cx = 0;\n let cy = 0;\n let prev = \"\";\n let i = 0;\n let command = \"\";\n const add = (px: number, py: number) => ring!.points.push([px, py]);\n const begin = (px: number, py: number) => {\n if (ring && ring.points.length) rings.push(ring);\n ring = { points: [[px, py]], closed: false };\n };\n while (i < tokens.length) {\n if (/[a-z]/i.test(tokens[i]!)) command = tokens[i++]!;\n else if (!command) throw new Error(`\"${tokens[i]}\" needs a command (M, L, C, …) before it`);\n const lower = command.toLowerCase();\n if (!(lower in ARGS)) throw new Error(`Unknown path command \"${command}\"`);\n const rel = command !== command.toUpperCase();\n const n = ARGS[lower]!;\n const args = tokens.slice(i, i + n).map(Number);\n if (args.length < n || args.some((v) => Number.isNaN(v))) break;\n i += n;\n const ox = rel ? x : 0;\n const oy = rel ? y : 0;\n if (lower === \"z\") {\n if (ring) {\n ring.closed = true;\n rings.push(ring);\n ring = null;\n }\n x = startX;\n y = startY;\n prev = \"z\";\n // A Z takes no arguments: wait for the next command.\n command = \"\";\n continue;\n }\n if (!ring) begin(x, y);\n switch (lower) {\n case \"m\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n startX = x;\n startY = y;\n begin(x, y);\n // Pairs after a moveto are linetos.\n command = rel ? \"l\" : \"L\";\n break;\n case \"l\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n add(x, y);\n break;\n case \"h\":\n x = ox + args[0]!;\n add(x, y);\n break;\n case \"v\":\n y = (rel ? y : 0) + args[0]!;\n add(x, y);\n break;\n case \"c\":\n case \"s\": {\n let x1: number;\n let y1: number;\n let rest: number[];\n if (lower === \"c\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n rest = args.slice(2);\n } else {\n const smooth = prev === \"c\" || prev === \"s\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n rest = args;\n }\n const x2 = ox + rest[0]!;\n const y2 = oy + rest[1]!;\n const ex = ox + rest[2]!;\n const ey = oy + rest[3]!;\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(\n u * u * u * x + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * ex,\n u * u * u * y + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * ey,\n );\n }\n cx = x2;\n cy = y2;\n x = ex;\n y = ey;\n break;\n }\n case \"q\":\n case \"t\": {\n let x1: number;\n let y1: number;\n let ex: number;\n let ey: number;\n if (lower === \"q\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n ex = ox + args[2]!;\n ey = oy + args[3]!;\n } else {\n const smooth = prev === \"q\" || prev === \"t\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n ex = ox + args[0]!;\n ey = oy + args[1]!;\n }\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(u * u * x + 2 * u * t * x1 + t * t * ex, u * u * y + 2 * u * t * y1 + t * t * ey);\n }\n cx = x1;\n cy = y1;\n x = ex;\n y = ey;\n break;\n }\n case \"a\": {\n const ex = ox + args[5]!;\n const ey = oy + args[6]!;\n for (const p of arcPoints(x, y, args[0]!, args[1]!, args[2]!, args[3]! !== 0, args[4]! !== 0, ex, ey)) add(p[0], p[1]);\n x = ex;\n y = ey;\n break;\n }\n }\n prev = lower;\n }\n if (ring && ring.points.length) rings.push(ring);\n return rings\n .map((r) => {\n // A ring that ends where it starts is closed, Z or not.\n const [a, b] = [r.points[0]!, r.points[r.points.length - 1]!];\n const closes = r.points.length > 2 && Math.hypot(a[0] - b[0], a[1] - b[1]) < 1e-6;\n return { points: closes ? r.points.slice(0, -1) : r.points, closed: r.closed || closes };\n })\n .filter((r) => r.points.length > 1);\n}\n\n/** Points along an SVG arc (endpoint form), not including its start. */\nfunction arcPoints(\n x1: number,\n y1: number,\n rx: number,\n ry: number,\n angle: number,\n large: boolean,\n sweep: boolean,\n x2: number,\n y2: number,\n): Point[] {\n rx = Math.abs(rx);\n ry = Math.abs(ry);\n if (!rx || !ry || (x1 === x2 && y1 === y2)) return [[x2, y2]];\n const phi = (angle * Math.PI) / 180;\n const cos = Math.cos(phi);\n const sin = Math.sin(phi);\n const dx = (x1 - x2) / 2;\n const dy = (y1 - y2) / 2;\n const x1p = cos * dx + sin * dy;\n const y1p = -sin * dx + cos * dy;\n // Radii too small to reach are scaled up, as SVG says.\n const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);\n if (lambda > 1) {\n rx *= Math.sqrt(lambda);\n ry *= Math.sqrt(lambda);\n }\n const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;\n const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;\n const k = (large === sweep ? -1 : 1) * Math.sqrt(Math.max(0, num / den));\n const cxp = (k * rx * y1p) / ry;\n const cyp = (-k * ry * x1p) / rx;\n const cx = cos * cxp - sin * cyp + (x1 + x2) / 2;\n const cy = sin * cxp + cos * cyp + (y1 + y2) / 2;\n const theta = (ux: number, uy: number, vx: number, vy: number) =>\n Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);\n const start = theta(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);\n let delta = theta((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);\n if (!sweep && delta > 0) delta -= 2 * Math.PI;\n if (sweep && delta < 0) delta += 2 * Math.PI;\n const steps = Math.max(2, Math.ceil((Math.abs(delta) / (Math.PI / 2)) * (CURVE_STEPS / 2)));\n const out: Point[] = [];\n for (let s = 1; s <= steps; s++) {\n const t = start + (delta * s) / steps;\n const px = rx * Math.cos(t);\n const py = ry * Math.sin(t);\n out.push([cos * px - sin * py + cx, sin * px + cos * py + cy]);\n }\n out[out.length - 1] = [x2, y2];\n return out;\n}\n\n/**\n * `n` points evenly spaced along a ring. A closed ring goes round once; an\n * open one (a stroke) is resampled as closed by going there and back, so it\n * can turn into a closed shape.\n */\nfunction resample(ring: Ring, n: number): Point[] {\n const pts = ring.closed ? [...ring.points, ring.points[0]!] : [...ring.points, ...ring.points.slice(0, -1).reverse()];\n const lengths = [0];\n for (let i = 1; i < pts.length; i++)\n lengths.push(lengths[i - 1]! + Math.hypot(pts[i]![0] - pts[i - 1]![0], pts[i]![1] - pts[i - 1]![1]));\n const total = lengths[lengths.length - 1]!;\n if (total === 0) return Array.from({ length: n }, () => [pts[0]![0], pts[0]![1]] as Point);\n const out: Point[] = [];\n let j = 1;\n for (let k = 0; k < n; k++) {\n const at = (k / n) * total;\n while (j < lengths.length - 1 && lengths[j]! < at) j++;\n const seg = lengths[j]! - lengths[j - 1]!;\n const t = seg > 0 ? (at - lengths[j - 1]!) / seg : 0;\n const a = pts[j - 1]!;\n const b = pts[j]!;\n out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);\n }\n return out;\n}\n\nconst signedArea = (pts: Point[]) => {\n let sum = 0;\n for (let i = 0; i < pts.length; i++) {\n const a = pts[i]!;\n const b = pts[(i + 1) % pts.length]!;\n sum += a[0] * b[1] - b[0] * a[1];\n }\n return sum / 2;\n};\n\nconst centroid = (pts: Point[]): Point => {\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p[0];\n y += p[1];\n }\n return [x / pts.length, y / pts.length];\n};\n\n/** How big a piece is: its area, or for a stroke its length times a little. */\nfunction size(ring: Ring, pts: Point[]): number {\n const area = Math.abs(signedArea(pts));\n if (ring.closed && area > 0) return area;\n let length = 0;\n for (let i = 1; i < ring.points.length; i++)\n length += Math.hypot(ring.points[i]![0] - ring.points[i - 1]![0], ring.points[i]![1] - ring.points[i - 1]![1]);\n return length;\n}\n\ninterface Piece {\n pts: Point[];\n centre: Point;\n size: number;\n}\n\n/**\n * Pairs the pieces of one shape with the slots of the shape before it,\n * nearest and most alike first: a slot left over is empty (a piece that\n * shrinks away), and a piece left over takes an empty slot (it grows).\n */\nfunction assign(before: (Piece | null)[], pieces: Piece[], scale: number): (Piece | null)[] {\n const out: (Piece | null)[] = before.map(() => null);\n const pairs: { slot: number; piece: number; cost: number }[] = [];\n before.forEach((slot, s) => {\n if (!slot) return;\n pieces.forEach((p, i) => {\n const distance = Math.hypot(slot.centre[0] - p.centre[0], slot.centre[1] - p.centre[1]) / scale;\n const likeness = Math.abs(Math.log((slot.size + 1e-9) / (p.size + 1e-9)));\n pairs.push({ slot: s, piece: i, cost: distance + 0.5 * likeness });\n });\n });\n pairs.sort((a, b) => a.cost - b.cost);\n const used = new Set<number>();\n for (const { slot, piece } of pairs) {\n if (out[slot] || used.has(piece)) continue;\n out[slot] = pieces[piece]!;\n used.add(piece);\n }\n let free = 0;\n pieces.forEach((p, i) => {\n if (used.has(i)) return;\n while (out[free] || before[free]) free++;\n out[free] = p;\n });\n return out;\n}\n\n/** `pts` turned and started so it lines up with `ref` point by point (the shortest moves). */\nfunction align(ref: Point[], pts: Point[]): Point[] {\n const n = pts.length;\n let best = pts;\n let bestCost = Infinity;\n for (const candidate of [pts, [...pts].reverse()]) {\n for (let shift = 0; shift < n; shift++) {\n let cost = 0;\n for (let k = 0; k < n && cost < bestCost; k++) {\n const a = ref[k]!;\n const b = candidate[(k + shift) % n]!;\n cost += (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;\n }\n if (cost < bestCost) {\n bestCost = cost;\n best = candidate.slice(shift).concat(candidate.slice(0, shift));\n }\n }\n }\n return best;\n}\n\n/**\n * Paths with one structure for a sequence of shapes, so each blends into the\n * next (and the last into the first) with `attrs: { d: [a, b] }`. Any path\n * commands work, curves and arcs included, and shapes can have different\n * numbers of pieces (an icon's parts, a letter's holes): pieces are paired by\n * position and size, and one without a partner grows from or shrinks to a\n * point. Draw the results with `fill-rule=\"evenodd\"`, since a piece's\n * direction can change. Throws a sentence when a path cannot be read.\n */\nexport function morphSequence(paths: readonly string[], options: MorphOptions = {}): string[] {\n const n = Math.max(8, Math.round(options.points ?? 72));\n const decimals = options.decimals ?? 2;\n const shapes = paths.map((d, i) => {\n let rings: Ring[];\n try {\n rings = flatten(d);\n } catch (e) {\n throw new Error(`Path ${i + 1} cannot be read: ${(e as Error).message}`);\n }\n if (!rings.length) throw new Error(`Path ${i + 1} draws nothing: give it at least two points`);\n return rings.map((r): Piece => {\n const pts = resample(r, n);\n return { pts, centre: centroid(pts), size: size(r, pts) };\n });\n });\n if (!shapes.length) return [];\n const slots = Math.max(...shapes.map((s) => s.length));\n // How far apart counts as far, from the shapes' extent.\n const xs = shapes.flat().flatMap((p) => p.pts.map((q) => q[0]));\n const ys = shapes.flat().flatMap((p) => p.pts.map((q) => q[1]));\n const scale = Math.max(1e-6, Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));\n // Biggest pieces first, so the main outlines keep the first slots.\n const first = [...shapes[0]!].sort((a, b) => b.size - a.size);\n const assigned: (Piece | null)[][] = [[...first, ...Array<null>(slots - first.length).fill(null)]];\n for (let i = 1; i < shapes.length; i++) assigned.push(assign(assigned[i - 1]!, shapes[i]!, scale));\n // An empty slot is a point: where the piece in that slot is in the nearest shape that has one.\n const resolved = assigned.map((shape, i) =>\n shape.map((piece, s): Point[] => {\n if (piece) return piece.pts;\n for (let k = 1; k < shapes.length; k++) {\n const near = assigned[(i + k) % shapes.length]![s] ?? assigned[(i - k + shapes.length) % shapes.length]![s];\n if (near) return Array.from({ length: n }, () => [near.centre[0], near.centre[1]] as Point);\n }\n return Array.from({ length: n }, () => [0, 0] as Point);\n }),\n );\n for (let i = 1; i < resolved.length; i++)\n resolved[i] = resolved[i]!.map((pts, s) => align(resolved[i - 1]![s]!, pts));\n const num = (v: number) => {\n const r = Number(v.toFixed(decimals));\n return String(Object.is(r, -0) ? 0 : r);\n };\n return resolved.map((shape) =>\n shape.map((pts) => `M${pts.map((p) => `${num(p[0])} ${num(p[1])}`).join(\" L\")} Z`).join(\" \"),\n );\n}\n\n/**\n * Two paths turned into paths with one structure, so `attrs: { d: [from, to] }`\n * blends one into the other (see {@link morphSequence}).\n */\nexport function morphPaths(from: string, to: string, options: MorphOptions = {}): [string, string] {\n const [a, b] = morphSequence([from, to], options);\n return [a!, b!];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-P5TSANZY.js.map
|