morphico 0.4.0 → 0.5.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 +62 -45
- package/dist/esm/all.js +50 -0
- package/dist/esm/clip.js +283 -0
- package/dist/esm/engine.js +25 -0
- package/dist/esm/face.js +153 -0
- package/dist/esm/geometry.js +459 -0
- package/dist/esm/icon.js +41 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/morph.js +107 -0
- package/dist/esm/roundness.js +37 -0
- package/dist/esm/sets/battery.js +87 -0
- package/dist/esm/sets/bell.js +101 -0
- package/dist/esm/sets/characters.js +43 -0
- package/dist/esm/sets/check-mark.js +74 -0
- package/dist/esm/sets/checkbox.js +91 -0
- package/dist/esm/sets/chevron.js +70 -0
- package/dist/esm/sets/condensed.js +137 -0
- package/dist/esm/sets/copy.js +87 -0
- package/dist/esm/sets/eye.js +105 -0
- package/dist/esm/sets/faces.js +482 -0
- package/dist/esm/sets/folder.js +112 -0
- package/dist/esm/sets/handwritten.js +136 -0
- package/dist/esm/sets/lock.js +75 -0
- package/dist/esm/sets/lucide.js +66 -0
- package/dist/esm/sets/media.js +109 -0
- package/dist/esm/sets/menu.js +84 -0
- package/dist/esm/sets/mic.js +102 -0
- package/dist/esm/sets/radio.js +84 -0
- package/dist/esm/sets/round.js +244 -0
- package/dist/esm/sets/shapes.js +455 -0
- package/dist/esm/sets/slim.js +148 -0
- package/dist/esm/sets/square.js +149 -0
- package/dist/esm/sets/theme.js +107 -0
- package/dist/esm/sets/toggle.js +73 -0
- package/dist/esm/sets/volume.js +89 -0
- package/dist/esm/sets/weather.js +691 -0
- package/dist/esm/sets/wifi.js +68 -0
- package/dist/esm/svg.js +31 -0
- package/dist/esm/text.js +88 -0
- package/dist/esm/types.js +3 -0
- package/dist/morphico.js +3764 -3750
- package/dist/types/{iconSets.d.ts → all.d.ts} +0 -2
- package/dist/types/clip.d.ts +4 -11
- package/dist/types/face.d.ts +2 -6
- package/dist/types/icon.d.ts +4 -9
- package/dist/types/index.d.ts +1 -3
- package/dist/types/roundness.d.ts +8 -0
- package/dist/types/sets/battery.d.ts +1 -1
- package/dist/types/sets/bell.d.ts +1 -1
- package/dist/types/sets/checkbox.d.ts +1 -1
- package/dist/types/sets/chevron.d.ts +1 -1
- package/dist/types/sets/condensed.d.ts +1 -1
- package/dist/types/sets/copy.d.ts +1 -1
- package/dist/types/sets/eye.d.ts +1 -1
- package/dist/types/sets/folder.d.ts +1 -1
- package/dist/types/sets/handwritten.d.ts +1 -1
- package/dist/types/sets/lock.d.ts +1 -1
- package/dist/types/sets/media.d.ts +1 -1
- package/dist/types/sets/menu.d.ts +1 -1
- package/dist/types/sets/mic.d.ts +1 -1
- package/dist/types/sets/radio.d.ts +1 -1
- package/dist/types/sets/round.d.ts +1 -1
- package/dist/types/sets/slim.d.ts +1 -1
- package/dist/types/sets/square.d.ts +1 -1
- package/dist/types/sets/theme.d.ts +1 -1
- package/dist/types/sets/toggle.d.ts +1 -1
- package/dist/types/sets/volume.d.ts +1 -1
- package/dist/types/sets/weather.d.ts +1 -1
- package/dist/types/sets/wifi.d.ts +1 -1
- package/dist/types/text.d.ts +8 -13
- package/package.json +95 -3
- package/dist/morphico.mjs +0 -4642
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE) */
|
|
2
|
+
// Digit set "handwritten": hand-drawn marker digits, traced from the reference images in icons/handwritten/
|
|
3
|
+
// (the set format is described in ../types.ts).
|
|
4
|
+
//
|
|
5
|
+
// Free-form strokes, so the geometry is traced rather than constructed (scratch tools, see CLAUDE.md):
|
|
6
|
+
// thin decorative side lines removed (only ink of a thick stroke kept), the stroke thinned to its centre line,
|
|
7
|
+
// followed through hand-placed waypoints in writing order, smoothed and fitted with cubic Bézier curves
|
|
8
|
+
// (Schneider's algorithm). 7.375 image px = 1 grid unit, each digit centred on 12,12; stroke 1.04 (typical width along
|
|
9
|
+
// the centre line — the marker stroke varies a little, so the pixel match is ~8–17 %).
|
|
10
|
+
// - every digit is one stroke of 3–7 free cubic curves; round ends and corners
|
|
11
|
+
// - the 4 is drawn out and back over its crossbar end and right stem (one continuous stroke)
|
|
12
|
+
import { cubic } from '../geometry.js';
|
|
13
|
+
import { withTextCharacters } from './characters.js';
|
|
14
|
+
// '-' '/' '.' ',' ':' are added by withTextCharacters (characters.ts)
|
|
15
|
+
export const digitsHandwritten = withTextCharacters({
|
|
16
|
+
segmentCount: 16,
|
|
17
|
+
strokeWidth: 1.04,
|
|
18
|
+
lineCap: 'round',
|
|
19
|
+
lineJoin: 'round',
|
|
20
|
+
strokes: {
|
|
21
|
+
0: [
|
|
22
|
+
cubic(12.61, 4.07, 10.61, 3.51, 9.37, 5.81, 8.74, 7.36),
|
|
23
|
+
cubic(8.74, 7.36, 7.57, 10.27, 6.96, 17.17, 9.79, 19.34),
|
|
24
|
+
cubic(9.79, 19.34, 12.78, 21.64, 15.47, 18.25, 16, 15.5),
|
|
25
|
+
cubic(16, 15.5, 16.6, 12.38, 16.29, 8.49, 14.37, 5.83),
|
|
26
|
+
cubic(14.37, 5.83, 13.87, 5.13, 13.21, 4.66, 12.61, 4.07),
|
|
27
|
+
],
|
|
28
|
+
1: [
|
|
29
|
+
cubic(10.24, 7.53, 11.22, 6.54, 12.21, 5.24, 13.49, 4.68),
|
|
30
|
+
cubic(13.49, 4.68, 13.7, 4.79, 13.86, 4.5, 13.9, 4.89),
|
|
31
|
+
cubic(13.9, 4.89, 14.02, 6, 13.9, 7.27, 13.9, 8.42),
|
|
32
|
+
cubic(13.9, 8.42, 13.9, 12.28, 13.9, 16.14, 13.9, 20),
|
|
33
|
+
],
|
|
34
|
+
2: [
|
|
35
|
+
cubic(9.02, 7.66, 10.04, 4, 14.93, 1.86, 15.22, 7.15),
|
|
36
|
+
cubic(15.22, 7.15, 15.49, 11.89, 7.96, 15.48, 8.47, 19.86),
|
|
37
|
+
cubic(8.47, 19.86, 9.61, 20.58, 13.97, 20.14, 15.53, 20.14),
|
|
38
|
+
],
|
|
39
|
+
3: [
|
|
40
|
+
cubic(9.76, 5.15, 13.23, 2.8, 16.42, 4.68, 14.53, 7.59),
|
|
41
|
+
cubic(14.53, 7.59, 13.4, 9.34, 12.35, 9.39, 10.58, 9.9),
|
|
42
|
+
cubic(10.58, 9.9, 11.34, 9.75, 12.22, 9.41, 13.02, 9.59),
|
|
43
|
+
cubic(13.02, 9.59, 18.13, 10.7, 16.81, 19.23, 11.83, 19.98),
|
|
44
|
+
cubic(11.83, 19.98, 9.89, 20.28, 8.7, 19.11, 7.73, 17.63),
|
|
45
|
+
],
|
|
46
|
+
4: [
|
|
47
|
+
cubic(8.27, 4.14, 8.27, 6.1, 7.62, 12.38, 8.38, 13.74),
|
|
48
|
+
cubic(8.41, 13.76, 10.61, 14.38, 13.29, 14.03, 15.59, 14.03),
|
|
49
|
+
cubic(15.59, 14.03, 14.82, 14.03, 14.06, 14.03, 13.29, 14.03),
|
|
50
|
+
cubic(13.29, 14.03, 13.29, 10.73, 13.29, 7.44, 13.29, 4.14),
|
|
51
|
+
cubic(13.29, 4.14, 13.29, 9.33, 13.29, 14.53, 13.29, 19.73),
|
|
52
|
+
],
|
|
53
|
+
5: [
|
|
54
|
+
cubic(14.24, 3.86, 12.8, 3.86, 11.11, 3.74, 9.76, 4.14),
|
|
55
|
+
cubic(9.76, 4.14, 9.7, 4.15, 9.31, 4.09, 9.26, 4.23),
|
|
56
|
+
cubic(9.26, 4.23, 9.09, 4.74, 9.28, 8.83, 9.36, 9.58),
|
|
57
|
+
cubic(9.36, 9.58, 9.41, 10.07, 9.44, 9.66, 9.63, 9.83),
|
|
58
|
+
cubic(9.63, 9.83, 10.32, 9.54, 10.97, 9.13, 11.74, 9.04),
|
|
59
|
+
cubic(11.74, 9.04, 16.84, 8.46, 16.99, 16.29, 14.13, 18.87),
|
|
60
|
+
cubic(14.13, 18.87, 11.84, 20.92, 8.19, 19.68, 8, 16.47),
|
|
61
|
+
],
|
|
62
|
+
6: [
|
|
63
|
+
cubic(13.08, 3.93, 9.07, 6.47, 7.2, 12.92, 8.79, 17.24),
|
|
64
|
+
cubic(8.79, 17.24, 9.18, 18.28, 9.4, 19.11, 10.46, 19.67),
|
|
65
|
+
cubic(10.46, 19.67, 13.85, 21.46, 16.41, 16.37, 15.4, 13.64),
|
|
66
|
+
cubic(15.4, 13.64, 13.48, 8.42, 9.15, 16.35, 8.94, 16.42),
|
|
67
|
+
cubic(8.94, 16.42, 7.71, 16.83, 8.27, 12.36, 8.47, 11.8),
|
|
68
|
+
],
|
|
69
|
+
7: [
|
|
70
|
+
cubic(8.81, 3.86, 10.36, 3.86, 14.03, 3.47, 15.19, 4.08),
|
|
71
|
+
cubic(15.19, 4.14, 14.75, 5.71, 13.41, 7.25, 12.7, 8.8),
|
|
72
|
+
cubic(12.7, 8.8, 11.16, 12.19, 10.31, 16.13, 10.31, 19.86),
|
|
73
|
+
],
|
|
74
|
+
8: [
|
|
75
|
+
cubic(14.51, 5.56, 15.17, 3.17, 9.21, 3.46, 8.86, 6.51),
|
|
76
|
+
cubic(8.86, 6.51, 8.64, 8.41, 13.99, 11.13, 14.93, 13.6),
|
|
77
|
+
cubic(14.93, 13.6, 15.9, 16.15, 14.74, 20.7, 11.25, 19.94),
|
|
78
|
+
cubic(11.25, 19.94, 8.97, 19.44, 8.63, 17.22, 9.02, 15.26),
|
|
79
|
+
cubic(9.02, 15.26, 9.77, 11.45, 12.38, 8.68, 14.48, 5.59),
|
|
80
|
+
],
|
|
81
|
+
9: [
|
|
82
|
+
cubic(14.98, 6.98, 13.12, 0.31, 6.71, 5.82, 8.47, 10.23),
|
|
83
|
+
cubic(8.47, 10.23, 9.92, 13.9, 13.15, 10.88, 14.01, 8.61),
|
|
84
|
+
cubic(14.01, 8.61, 14.16, 8.23, 14.66, 6.7, 15.3, 7.44),
|
|
85
|
+
cubic(15.3, 7.44, 16.93, 9.31, 14.47, 18.24, 11.59, 19.86),
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
alternativeStrokes: {},
|
|
89
|
+
// optimizer fits (tools/check.ts) for the pairs the user rated bad / midd / not sure
|
|
90
|
+
pairLayouts: {
|
|
91
|
+
0: {
|
|
92
|
+
1: { startSegment: 5, reversed: true },
|
|
93
|
+
2: { startSegment: 5, reversed: true },
|
|
94
|
+
3: { startSegment: 4, reversed: true },
|
|
95
|
+
4: { breakpoints: [0, 0.7708, 1, 1.2083, 1.3958, 1.5208, 1.5208, 1.5208, 2, 3, 3.1458, 3.1458, 3.1458, 3.5833, 3.8542, 4, 5] },
|
|
96
|
+
5: { startSegment: 3, reversed: true },
|
|
97
|
+
7: { startSegment: 4, reversed: true },
|
|
98
|
+
9: { startSegment: 5, reversed: true },
|
|
99
|
+
},
|
|
100
|
+
1: {
|
|
101
|
+
0: { breakpoints: [0, 0, 0, 0, 0.3542, 1, 2, 3, 3.1667, 3.3958, 3.6042, 3.8125, 3.9167, 3.9167, 3.9167, 3.9167, 4] },
|
|
102
|
+
},
|
|
103
|
+
2: {
|
|
104
|
+
6: { breakpoints: [0, 0.4583, 1, 1.5833, 1.5833, 1.5833, 1.5833, 1.5833, 1.5833, 1.5833, 1.5833, 1.5833, 1.5833, 1.6458, 1.7083, 2, 3] },
|
|
105
|
+
0: { breakpoints: [0, 0, 0, 0, 0.25, 0.5417, 0.8958, 1, 1.2083, 1.3125, 1.4167, 1.5417, 1.75, 1.9792, 1.9792, 2, 3] },
|
|
106
|
+
},
|
|
107
|
+
3: {
|
|
108
|
+
8: { breakpoints: [0, 0.5833, 0.5833, 0.5833, 0.5833, 1, 2, 3, 3.1458, 3.3958, 3.5208, 3.6667, 3.8333, 4, 4.2917, 5, 5] },
|
|
109
|
+
0: { breakpoints: [0, 0, 0, 0, 0.2917, 1, 2, 3, 3.4167, 3.5208, 3.7083, 3.8542, 4, 4.4167, 5, 5, 5] },
|
|
110
|
+
},
|
|
111
|
+
4: {
|
|
112
|
+
8: { breakpoints: [0, 0.5833, 0.7708, 1, 1.4583, 2, 2.1458, 3, 3.2917, 3.3125, 3.875, 3.8958, 3.8958, 3.8958, 3.8958, 4, 5] },
|
|
113
|
+
0: { breakpoints: [0, 0.0833, 0.3542, 0.5208, 0.7708, 1, 1.1042, 1.25, 1.5, 1.7292, 1.9583, 2, 3, 3.3958, 3.5625, 4, 5] },
|
|
114
|
+
},
|
|
115
|
+
5: {
|
|
116
|
+
0: { breakpoints: [0, 1, 2, 3, 4, 5, 5.3958, 5.5208, 5.6875, 5.875, 6, 6.2917, 6.5625, 6.8958, 7, 7, 7] },
|
|
117
|
+
},
|
|
118
|
+
6: {
|
|
119
|
+
2: { breakpoints: [0, 0.0625, 0.0625, 1, 2, 3, 3.6458, 3.6458, 3.6458, 3.6458, 3.6458, 3.6458, 3.6458, 3.7292, 3.875, 4, 5] },
|
|
120
|
+
},
|
|
121
|
+
7: {
|
|
122
|
+
8: { breakpoints: [0, 0.7292, 0.7292, 0.7292, 0.7292, 0.7292, 1, 2, 2.1458, 2.1458, 2.1458, 2.1458, 2.4583, 2.75, 2.75, 2.75, 3] },
|
|
123
|
+
0: { breakpoints: [0, 0, 0, 0.2083, 0.5417, 1, 1.6667, 2, 2.2708, 2.5208, 2.7708, 2.8542, 2.8542, 2.8542, 2.8542, 2.8542, 3] },
|
|
124
|
+
},
|
|
125
|
+
8: {
|
|
126
|
+
7: { breakpoints: [0, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 0.3125, 1, 1.5625, 1.5625, 1.6042, 1.625, 2, 3, 3.6042, 4, 5] },
|
|
127
|
+
4: { breakpoints: [0, 0, 0, 0, 0, 0.25, 1, 1.625, 1.6875, 2, 2.0417, 2.0417, 3, 4, 4.3125, 4.5208, 5], reversed: true },
|
|
128
|
+
3: { breakpoints: [0, 0.125, 0.125, 0.125, 0.125, 1, 1.5208, 1.5625, 1.7708, 2, 2.1667, 2.3958, 2.6458, 3, 3.0417, 4, 5] },
|
|
129
|
+
},
|
|
130
|
+
9: {
|
|
131
|
+
0: { breakpoints: [0, 0.9792, 0.9792, 1, 2, 2.7917, 2.7917, 3, 3.3125, 3.4375, 3.5833, 3.7083, 3.8333, 4, 4, 4, 4] },
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
spins: {},
|
|
135
|
+
textLayout: { cellWidth: 9, spacing: 4, baselineY: 20.2, colonDotsY: [8, 16] },
|
|
136
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | code: MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE)
|
|
2
|
+
* Icons based on Lucide (https://lucide.dev), some of them from Feather (https://feathericons.com):
|
|
3
|
+
*
|
|
4
|
+
* ISC License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Lucide Icons and Contributors
|
|
7
|
+
*
|
|
8
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
10
|
+
* copyright notice and this permission notice appear in all copies.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
13
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
14
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
15
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
16
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
17
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
18
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
19
|
+
*
|
|
20
|
+
* The MIT License (MIT) (for the Lucide icons derived from Feather, listed in LICENSE-lucide)
|
|
21
|
+
*
|
|
22
|
+
* Copyright (c) 2013-present Cole Bemis
|
|
23
|
+
*
|
|
24
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
26
|
+
* in the Software without restriction, including without limitation the rights
|
|
27
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
28
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
29
|
+
* furnished to do so, subject to the following conditions:
|
|
30
|
+
*
|
|
31
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
32
|
+
* copies or substantial portions of the Software.
|
|
33
|
+
*
|
|
34
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
38
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
39
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
40
|
+
* SOFTWARE.
|
|
41
|
+
*/
|
|
42
|
+
import { LUCIDE_STROKE_WIDTH, lucideArc, lucideLine } from './lucide.js';
|
|
43
|
+
const BODY = [
|
|
44
|
+
lucideLine(5, 11, 19, 11),
|
|
45
|
+
lucideArc(19, 13, 2, -90, 0),
|
|
46
|
+
lucideLine(21, 13, 21, 20),
|
|
47
|
+
lucideArc(19, 20, 2, 0, 90),
|
|
48
|
+
lucideLine(19, 22, 5, 22),
|
|
49
|
+
lucideArc(5, 20, 2, 90, 180),
|
|
50
|
+
lucideLine(3, 20, 3, 13),
|
|
51
|
+
lucideArc(5, 13, 2, 180, 270),
|
|
52
|
+
];
|
|
53
|
+
const LEFT_LEG = lucideLine(7, 11, 7, 7);
|
|
54
|
+
const body = { strokes: { locked: BODY, unlocked: BODY }, alternativeStrokes: {}, pairLayouts: {} };
|
|
55
|
+
// left leg 2 segments, arch 6, right leg 4 — unlocked has no right leg: 4 zero-length segments at the arch's end
|
|
56
|
+
const shackle = {
|
|
57
|
+
strokes: {
|
|
58
|
+
locked: [LEFT_LEG, lucideArc(12, 7, 5, 180, 360), lucideLine(17, 7, 17, 11)],
|
|
59
|
+
unlocked: [LEFT_LEG, lucideArc(12, 6.995, 5, 179.9424, 348.5218)],
|
|
60
|
+
},
|
|
61
|
+
alternativeStrokes: {},
|
|
62
|
+
pairLayouts: {
|
|
63
|
+
locked: { unlocked: { breakpoints: [0, 0.5, 1, 1.1667, 1.3333, 1.5, 1.6667, 1.8333, 2, 2.25, 2.5, 2.75, 3] } },
|
|
64
|
+
unlocked: { locked: { breakpoints: [0, 0.5, 1, 1.1667, 1.3333, 1.5, 1.6667, 1.8333, 2, 2, 2, 2, 2] } },
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
export const iconsLock = {
|
|
68
|
+
segmentCount: 12,
|
|
69
|
+
strokeWidth: LUCIDE_STROKE_WIDTH,
|
|
70
|
+
lineCap: 'round',
|
|
71
|
+
lineJoin: 'round',
|
|
72
|
+
...body,
|
|
73
|
+
morePieces: [shackle],
|
|
74
|
+
spins: {},
|
|
75
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | code: MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE)
|
|
2
|
+
* Icons based on Lucide (https://lucide.dev), some of them from Feather (https://feathericons.com):
|
|
3
|
+
*
|
|
4
|
+
* ISC License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Lucide Icons and Contributors
|
|
7
|
+
*
|
|
8
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
10
|
+
* copyright notice and this permission notice appear in all copies.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
13
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
14
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
15
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
16
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
17
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
18
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
19
|
+
*
|
|
20
|
+
* The MIT License (MIT) (for the Lucide icons derived from Feather, listed in LICENSE-lucide)
|
|
21
|
+
*
|
|
22
|
+
* Copyright (c) 2013-present Cole Bemis
|
|
23
|
+
*
|
|
24
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
26
|
+
* in the Software without restriction, including without limitation the rights
|
|
27
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
28
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
29
|
+
* furnished to do so, subject to the following conditions:
|
|
30
|
+
*
|
|
31
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
32
|
+
* copies or substantial portions of the Software.
|
|
33
|
+
*
|
|
34
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
38
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
39
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
40
|
+
* SOFTWARE.
|
|
41
|
+
*/
|
|
42
|
+
// Shared by every Lucide-based icon set: Lucide draws in y 3…21 (18 units) with a 2-unit line; our icons get the
|
|
43
|
+
// same room as the digits (16 units, y 4…20; user's choice 2026-10-26), so every icon is scaled around the centre
|
|
44
|
+
// 12,12 — line width included, so each icon looks exactly like Lucide's, only with more margin in its box.
|
|
45
|
+
import { arc, cubic, line } from '../geometry.js';
|
|
46
|
+
export const LUCIDE_SCALE = 16 / 18;
|
|
47
|
+
/** Lucide's 2-unit line, scaled with the icon. */
|
|
48
|
+
export const LUCIDE_STROKE_WIDTH = 2 * LUCIDE_SCALE;
|
|
49
|
+
/** A point (or corner) of a Lucide icon moved into our icon box. */
|
|
50
|
+
export const fromLucide = ([x, y]) => [12 + (x - 12) * LUCIDE_SCALE, 12 + (y - 12) * LUCIDE_SCALE];
|
|
51
|
+
/** A length of a Lucide icon (e.g. a corner radius) in our icon box. */
|
|
52
|
+
export const lucideLength = (length) => length * LUCIDE_SCALE;
|
|
53
|
+
// Strokes written in Lucide coordinates (for the icon sets added from 2026-10-28 on).
|
|
54
|
+
/** A straight line between two Lucide points. */
|
|
55
|
+
export const lucideLine = (fromX, fromY, toX, toY) => line(...fromLucide([fromX, fromY]), ...fromLucide([toX, toY]));
|
|
56
|
+
/** A circular arc in Lucide coordinates (angles in degrees, `endAngle > startAngle` = clockwise on screen). */
|
|
57
|
+
export const lucideArc = (centerX, centerY, radius, startAngle, endAngle) => arc(...fromLucide([centerX, centerY]), lucideLength(radius), startAngle, endAngle);
|
|
58
|
+
/** A cubic Bézier curve in Lucide coordinates. */
|
|
59
|
+
export const lucideCubic = (...coordinates) => {
|
|
60
|
+
const [startX, startY, control1X, control1Y, control2X, control2Y, endX, endY] = coordinates;
|
|
61
|
+
return cubic(...fromLucide([startX, startY]), ...fromLucide([control1X, control1Y]), ...fromLucide([control2X, control2Y]), ...fromLucide([endX, endY]));
|
|
62
|
+
};
|
|
63
|
+
/** A missing piece at rest: a single point, never drawn (see toPathData). */
|
|
64
|
+
export const lucidePoint = (x, y) => [lucideLine(x, y, x, y)];
|
|
65
|
+
/** The diagonal slash of Lucide's "-off" icons, from the top left. */
|
|
66
|
+
export const LUCIDE_SLASH = [lucideLine(2, 2, 22, 22)];
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | code: MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE)
|
|
2
|
+
* Icons based on Lucide (https://lucide.dev), some of them from Feather (https://feathericons.com):
|
|
3
|
+
*
|
|
4
|
+
* ISC License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Lucide Icons and Contributors
|
|
7
|
+
*
|
|
8
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
10
|
+
* copyright notice and this permission notice appear in all copies.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
13
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
14
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
15
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
16
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
17
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
18
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
19
|
+
*
|
|
20
|
+
* The MIT License (MIT) (for the Lucide icons derived from Feather, listed in LICENSE-lucide)
|
|
21
|
+
*
|
|
22
|
+
* Copyright (c) 2013-present Cole Bemis
|
|
23
|
+
*
|
|
24
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
26
|
+
* in the Software without restriction, including without limitation the rights
|
|
27
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
28
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
29
|
+
* furnished to do so, subject to the following conditions:
|
|
30
|
+
*
|
|
31
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
32
|
+
* copies or substantial portions of the Software.
|
|
33
|
+
*
|
|
34
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
38
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
39
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
40
|
+
* SOFTWARE.
|
|
41
|
+
*/
|
|
42
|
+
// Icon set "media": play, pause, stop — Lucide 1.61.0 icons (ISC, see LICENSE-lucide).
|
|
43
|
+
// First imported with `node tools/import-lucide.ts play pause square`, then rewritten as rounded polygons so the
|
|
44
|
+
// corners can be made sharper (`withRoundness`); with Lucide's radii (play 2, pause 1, stop 2) the shapes match
|
|
45
|
+
// the import within 0.005 units (Lucide's own rounding).
|
|
46
|
+
// Two pieces: pause has two bars; play and stop draw their single shape in both pieces (the second copy lies
|
|
47
|
+
// exactly on the first, so it doesn't show — during a morph to pause the two copies separate into the bars).
|
|
48
|
+
// Every shape runs clockwise from its top left, like Lucide's. Coordinates below are Lucide's; fromLucide /
|
|
49
|
+
// lucideLength scale them into our icon box (more margin, like the digits — see lucide.ts).
|
|
50
|
+
import { reversedStroke, roundedPolygon } from '../geometry.js';
|
|
51
|
+
import { fromLucide, LUCIDE_STROKE_WIDTH, lucideLength } from './lucide.js';
|
|
52
|
+
/** Lucide's play: a triangle (left side x 5, tip at the right) with rounded corners, starting with the top left arc. */
|
|
53
|
+
const PLAY_CORNERS = [[5, 1.5174], [22.9706, 11.9998], [5, 22.4827]].map(fromLucide);
|
|
54
|
+
const RIGHT_BAR_CORNERS = [[14, 3], [19, 3], [19, 21], [14, 21]].map(fromLucide);
|
|
55
|
+
const LEFT_BAR_CORNERS = [[5, 3], [10, 3], [10, 21], [5, 21]].map(fromLucide);
|
|
56
|
+
const SQUARE_CORNERS = [[3, 3], [21, 3], [21, 21], [3, 21]].map(fromLucide);
|
|
57
|
+
const LUCIDE_RADII = { play: lucideLength(2), pause: lucideLength(1), stop: lucideLength(2) };
|
|
58
|
+
// play ↔ stop (both pieces, the user's sketch): corner to corner, edge to edge, and the tip opens up and down
|
|
59
|
+
// into the square's right side. Play (top left corner, top, tip, bottom, bottom left corner, left):
|
|
60
|
+
// 2 + 1 + 4 + 1 + 2 + 2 segments. Stop is laid out from its top edge and then started at its top left corner,
|
|
61
|
+
// so its segments line up: top left 2, top 1, top right 1, right side 2, bottom right 1, bottom 1, bottom left 2, left 2.
|
|
62
|
+
const PLAY_FOR_STOP = { breakpoints: [0, 0.5, 1, 2, 2.25, 2.5, 2.75, 3, 4, 4.5, 5, 5.5, 6] };
|
|
63
|
+
const STOP_FOR_PLAY = { breakpoints: [0, 1, 2, 2.5, 3, 4, 5, 5.5, 6, 6.5, 7, 7.5, 8], startSegment: 10 };
|
|
64
|
+
const buildMediaIcons = (radii) => {
|
|
65
|
+
const play = roundedPolygon(PLAY_CORNERS, radii.play, true);
|
|
66
|
+
const stop = roundedPolygon(SQUARE_CORNERS, radii.stop);
|
|
67
|
+
return {
|
|
68
|
+
segmentCount: 12,
|
|
69
|
+
strokeWidth: LUCIDE_STROKE_WIDTH,
|
|
70
|
+
lineCap: 'round',
|
|
71
|
+
lineJoin: 'round',
|
|
72
|
+
strokes: { play, pause: roundedPolygon(RIGHT_BAR_CORNERS, radii.pause), stop },
|
|
73
|
+
alternativeStrokes: {},
|
|
74
|
+
// play ↔ stop: the user's sketch (above); play ↔ pause, pause ↔ stop: tools/check.ts
|
|
75
|
+
pairLayouts: {
|
|
76
|
+
play: { pause: { breakpoints: [0, 0.7292, 1, 1.6458, 2, 2.25, 3, 3.3125, 3.3125, 4, 4.2708, 5, 6] }, stop: PLAY_FOR_STOP },
|
|
77
|
+
pause: { play: { startSegment: 10 }, stop: { startSegment: 11 } },
|
|
78
|
+
stop: { pause: { breakpoints: [0, 0.8333, 1, 2, 2.2917, 2.7083, 3, 4, 4.1667, 5, 6, 7, 8] }, play: STOP_FOR_PLAY },
|
|
79
|
+
},
|
|
80
|
+
morePieces: [
|
|
81
|
+
{
|
|
82
|
+
strokes: { play, pause: roundedPolygon(LEFT_BAR_CORNERS, radii.pause), stop },
|
|
83
|
+
// only the triangle's left side, traced down and back up like the left bar's loop (top left corner out
|
|
84
|
+
// and back, left edge down, bottom left corner out and back, left edge up): the left bar inflates from
|
|
85
|
+
// that edge, while the first piece (the whole triangle) opens into the right bar
|
|
86
|
+
alternativeStrokes: {
|
|
87
|
+
'play-left-side': [
|
|
88
|
+
play[0], reversedStroke(play[0]), reversedStroke(play[5]), reversedStroke(play[4]), play[4], play[5],
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
pairLayouts: {
|
|
92
|
+
play: {
|
|
93
|
+
pause: { tracing: 'play-left-side', breakpoints: [0, 0.7292, 1, 1.7292, 2, 3, 3.7292, 4, 4.7292, 5, 5.7708, 6, 6] },
|
|
94
|
+
stop: PLAY_FOR_STOP,
|
|
95
|
+
},
|
|
96
|
+
pause: {
|
|
97
|
+
stop: { breakpoints: [0, 1, 2, 2.0208, 2.9792, 3, 4, 5, 6, 6.3333, 6.6667, 7, 8] },
|
|
98
|
+
},
|
|
99
|
+
stop: { pause: { breakpoints: [0, 0.1667, 1, 2, 3, 4, 4.8333, 5, 6, 6.2917, 6.7083, 7, 8] }, play: STOP_FOR_PLAY },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
spins: {},
|
|
104
|
+
withRoundness: (roundness) => buildMediaIcons({
|
|
105
|
+
play: LUCIDE_RADII.play * roundness, pause: LUCIDE_RADII.pause * roundness, stop: LUCIDE_RADII.stop * roundness,
|
|
106
|
+
}),
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
export const iconsMedia = buildMediaIcons(LUCIDE_RADII);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | code: MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE)
|
|
2
|
+
* Icons based on Lucide (https://lucide.dev), some of them from Feather (https://feathericons.com):
|
|
3
|
+
*
|
|
4
|
+
* ISC License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Lucide Icons and Contributors
|
|
7
|
+
*
|
|
8
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
10
|
+
* copyright notice and this permission notice appear in all copies.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
13
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
14
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
15
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
16
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
17
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
18
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
19
|
+
*
|
|
20
|
+
* The MIT License (MIT) (for the Lucide icons derived from Feather, listed in LICENSE-lucide)
|
|
21
|
+
*
|
|
22
|
+
* Copyright (c) 2013-present Cole Bemis
|
|
23
|
+
*
|
|
24
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
26
|
+
* in the Software without restriction, including without limitation the rights
|
|
27
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
28
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
29
|
+
* furnished to do so, subject to the following conditions:
|
|
30
|
+
*
|
|
31
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
32
|
+
* copies or substantial portions of the Software.
|
|
33
|
+
*
|
|
34
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
38
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
39
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
40
|
+
* SOFTWARE.
|
|
41
|
+
*/
|
|
42
|
+
// Icon set "menu": menu (☰), close (✕), back (←) — Lucide 1.61.0 icons "menu", "x", "arrow-left" (ISC, see
|
|
43
|
+
// LICENSE-lucide), imported with `node tools/import-lucide.ts menu x arrow-left`. Coordinates below are Lucide's;
|
|
44
|
+
// fromLucide scales them into our icon box (more margin, like the digits — see lucide.ts).
|
|
45
|
+
// Three pieces, each one straight line, lined up so the lines of every state correspond:
|
|
46
|
+
// piece 1: top line | "\" of the ✕ | upper half of the arrowhead
|
|
47
|
+
// piece 2: middle line | hidden on the ✕'s centre | the arrow's shaft
|
|
48
|
+
// piece 3: bottom line | "/" of the ✕ | lower half of the arrowhead
|
|
49
|
+
// Lucide draws the arrowhead as one bent line; two lines meeting with round ends look the same.
|
|
50
|
+
// Every line runs from left to right, so lines move without turning over.
|
|
51
|
+
import { line } from '../geometry.js';
|
|
52
|
+
import { fromLucide, LUCIDE_STROKE_WIDTH } from './lucide.js';
|
|
53
|
+
/** A straight line between two Lucide points, moved into our icon box. */
|
|
54
|
+
const lucideLine = (from, to) => [line(...fromLucide(from), ...fromLucide(to))];
|
|
55
|
+
const piece = (strokes, extras = { alternativeStrokes: {}, pairLayouts: {} }) => ({ strokes, ...extras });
|
|
56
|
+
// close ↔ back: the ✕ drawn with its lines swapped ("/" in piece 1, "\" in piece 3), so each line only shortens
|
|
57
|
+
// and tilts into its half of the arrowhead instead of turning over
|
|
58
|
+
const BACKSLASH = lucideLine([6, 6], [18, 18]);
|
|
59
|
+
const SLASH = lucideLine([6, 18], [18, 6]);
|
|
60
|
+
export const iconsMenu = {
|
|
61
|
+
segmentCount: 1,
|
|
62
|
+
strokeWidth: LUCIDE_STROKE_WIDTH,
|
|
63
|
+
lineCap: 'round',
|
|
64
|
+
lineJoin: 'round',
|
|
65
|
+
...piece({
|
|
66
|
+
menu: lucideLine([4, 5], [20, 5]),
|
|
67
|
+
close: BACKSLASH,
|
|
68
|
+
back: lucideLine([5, 12], [12, 5]),
|
|
69
|
+
}, { alternativeStrokes: { 'close-swapped': SLASH }, pairLayouts: { close: { back: { tracing: 'close-swapped', breakpoints: [0, 1] } } } }),
|
|
70
|
+
morePieces: [
|
|
71
|
+
piece({
|
|
72
|
+
menu: lucideLine([4, 12], [20, 12]),
|
|
73
|
+
// a tiny line on the centre of the ✕'s "\": hidden under it
|
|
74
|
+
close: lucideLine([11.5, 11.5], [12.5, 12.5]),
|
|
75
|
+
back: lucideLine([5, 12], [19, 12]),
|
|
76
|
+
}),
|
|
77
|
+
piece({
|
|
78
|
+
menu: lucideLine([4, 19], [20, 19]),
|
|
79
|
+
close: SLASH,
|
|
80
|
+
back: lucideLine([5, 12], [12, 19]),
|
|
81
|
+
}, { alternativeStrokes: { 'close-swapped': BACKSLASH }, pairLayouts: { close: { back: { tracing: 'close-swapped', breakpoints: [0, 1] } } } }),
|
|
82
|
+
],
|
|
83
|
+
spins: {},
|
|
84
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | code: MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE)
|
|
2
|
+
* Icons based on Lucide (https://lucide.dev), some of them from Feather (https://feathericons.com):
|
|
3
|
+
*
|
|
4
|
+
* ISC License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Lucide Icons and Contributors
|
|
7
|
+
*
|
|
8
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
10
|
+
* copyright notice and this permission notice appear in all copies.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
13
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
14
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
15
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
16
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
17
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
18
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
19
|
+
*
|
|
20
|
+
* The MIT License (MIT) (for the Lucide icons derived from Feather, listed in LICENSE-lucide)
|
|
21
|
+
*
|
|
22
|
+
* Copyright (c) 2013-present Cole Bemis
|
|
23
|
+
*
|
|
24
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
26
|
+
* in the Software without restriction, including without limitation the rights
|
|
27
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
28
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
29
|
+
* furnished to do so, subject to the following conditions:
|
|
30
|
+
*
|
|
31
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
32
|
+
* copies or substantial portions of the Software.
|
|
33
|
+
*
|
|
34
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
38
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
39
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
40
|
+
* SOFTWARE.
|
|
41
|
+
*/
|
|
42
|
+
import { LUCIDE_SLASH, LUCIDE_STROKE_WIDTH, lucideArc, lucideLine, lucidePoint } from './lucide.js';
|
|
43
|
+
const STAND = [lucideLine(12, 19, 12, 22)];
|
|
44
|
+
/** Where the mic's capsule is split: the middles of mic-off's gaps (right side y 11.85, left side y 6.3). */
|
|
45
|
+
const RIGHT_SPLIT_Y = 11.85;
|
|
46
|
+
const LEFT_SPLIT_Y = 6.3;
|
|
47
|
+
/** Where the holder is split: the middle of its gap (10.17° … 45°). */
|
|
48
|
+
const HOLDER_GAP_MIDDLE = (10.1709 + 44.9971) / 2;
|
|
49
|
+
const stand = { strokes: { on: STAND, off: STAND }, alternativeStrokes: {}, pairLayouts: {} };
|
|
50
|
+
// line, arc, line — 3 + 6 + 3 segments; off has no last line: 3 zero-length segments at its end
|
|
51
|
+
const SPLIT_LAYOUT = { breakpoints: [0, 0.3333, 0.6667, 1, 1.1667, 1.3333, 1.5, 1.6667, 1.8333, 2, 2.3333, 2.6667, 3] };
|
|
52
|
+
const CUT_LAYOUT = { breakpoints: [0, 0.3333, 0.6667, 1, 1.1667, 1.3333, 1.5, 1.6667, 1.8333, 2, 2, 2, 2] };
|
|
53
|
+
const capsuleTop = {
|
|
54
|
+
strokes: {
|
|
55
|
+
// up the right side, over the top (counterclockwise), down the left side to the split
|
|
56
|
+
on: [lucideLine(15, RIGHT_SPLIT_Y, 15, 5), lucideArc(12, 5, 3, 0, -180), lucideLine(9, 5, 9, LEFT_SPLIT_Y)],
|
|
57
|
+
off: [lucideLine(15, 9.34, 15, 5), lucideArc(12.0001, 5.0181, 3, -0.3452, -153.2975)],
|
|
58
|
+
},
|
|
59
|
+
alternativeStrokes: {},
|
|
60
|
+
pairLayouts: { on: { off: SPLIT_LAYOUT }, off: { on: CUT_LAYOUT } },
|
|
61
|
+
};
|
|
62
|
+
const capsuleBottom = {
|
|
63
|
+
strokes: {
|
|
64
|
+
// down the left side, around the bottom (counterclockwise), up the right side to the split
|
|
65
|
+
on: [lucideLine(9, LEFT_SPLIT_Y, 9, 12), lucideArc(12, 12, 3, 180, 0), lucideLine(15, 12, 15, RIGHT_SPLIT_Y)],
|
|
66
|
+
off: [lucideLine(9, 9, 9, 12), lucideArc(12, 11.9974, 3, 179.9496, 45.0356)],
|
|
67
|
+
},
|
|
68
|
+
alternativeStrokes: {},
|
|
69
|
+
pairLayouts: { on: { off: SPLIT_LAYOUT }, off: { on: CUT_LAYOUT } },
|
|
70
|
+
};
|
|
71
|
+
// arc then line, 6 + 6 segments in both states (the arc only shortens)
|
|
72
|
+
const HOLDER_LAYOUT = { breakpoints: [0, 0.1667, 0.3333, 0.5, 0.6667, 0.8333, 1, 1.1667, 1.3333, 1.5, 1.6667, 1.8333, 2] };
|
|
73
|
+
const holderLeft = {
|
|
74
|
+
strokes: {
|
|
75
|
+
on: [lucideArc(12, 12, 7, HOLDER_GAP_MIDDLE, 180), lucideLine(5, 12, 5, 10)],
|
|
76
|
+
off: [lucideArc(12, 12.0005, 7, 44.9971, 180.0041), lucideLine(5, 12, 5, 10)],
|
|
77
|
+
},
|
|
78
|
+
alternativeStrokes: {},
|
|
79
|
+
pairLayouts: { on: { off: HOLDER_LAYOUT }, off: { on: HOLDER_LAYOUT } },
|
|
80
|
+
};
|
|
81
|
+
const holderRight = {
|
|
82
|
+
strokes: {
|
|
83
|
+
on: [lucideArc(12, 12, 7, HOLDER_GAP_MIDDLE, 0), lucideLine(19, 12, 19, 10)],
|
|
84
|
+
off: [lucideArc(12, 11.9939, 7, 10.1709, 0.0499), lucideLine(19, 12, 19, 10)],
|
|
85
|
+
},
|
|
86
|
+
alternativeStrokes: {},
|
|
87
|
+
pairLayouts: { on: { off: HOLDER_LAYOUT }, off: { on: HOLDER_LAYOUT } },
|
|
88
|
+
};
|
|
89
|
+
const slash = {
|
|
90
|
+
strokes: { on: lucidePoint(2, 2), off: LUCIDE_SLASH },
|
|
91
|
+
alternativeStrokes: {},
|
|
92
|
+
pairLayouts: { on: { off: { draw: true } } },
|
|
93
|
+
};
|
|
94
|
+
export const iconsMic = {
|
|
95
|
+
segmentCount: 12,
|
|
96
|
+
strokeWidth: LUCIDE_STROKE_WIDTH,
|
|
97
|
+
lineCap: 'round',
|
|
98
|
+
lineJoin: 'round',
|
|
99
|
+
...stand,
|
|
100
|
+
morePieces: [capsuleTop, capsuleBottom, holderLeft, holderRight, slash],
|
|
101
|
+
spins: {},
|
|
102
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | code: MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE)
|
|
2
|
+
* Icons based on Lucide (https://lucide.dev), some of them from Feather (https://feathericons.com):
|
|
3
|
+
*
|
|
4
|
+
* ISC License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Lucide Icons and Contributors
|
|
7
|
+
*
|
|
8
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
10
|
+
* copyright notice and this permission notice appear in all copies.
|
|
11
|
+
*
|
|
12
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
13
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
14
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
15
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
16
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
17
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
18
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
19
|
+
*
|
|
20
|
+
* The MIT License (MIT) (for the Lucide icons derived from Feather, listed in LICENSE-lucide)
|
|
21
|
+
*
|
|
22
|
+
* Copyright (c) 2013-present Cole Bemis
|
|
23
|
+
*
|
|
24
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
25
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
26
|
+
* in the Software without restriction, including without limitation the rights
|
|
27
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
28
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
29
|
+
* furnished to do so, subject to the following conditions:
|
|
30
|
+
*
|
|
31
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
32
|
+
* copies or substantial portions of the Software.
|
|
33
|
+
*
|
|
34
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
35
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
36
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
37
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
38
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
39
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
40
|
+
* SOFTWARE.
|
|
41
|
+
*/
|
|
42
|
+
// Icon set "radio": unchecked, checked, checked-big — Lucide 1.61.0 icons "circle", "circle-check",
|
|
43
|
+
// "circle-check-big" (ISC, see LICENSE-lucide). Coordinates below are Lucide's; fromLucide / lucideLength scale them
|
|
44
|
+
// into our icon box (more margin, like the digits — see lucide.ts). Works like "checkbox", with a circle for the box.
|
|
45
|
+
// Two pieces:
|
|
46
|
+
// piece 1, the circle (radius 10 around 12,12): the same full circle in unchecked and checked (it doesn't move);
|
|
47
|
+
// checked-big opens a gap at the top right (from 17,3.335 clockwise round to 21.801,10 is the open arc) where
|
|
48
|
+
// the big check leaves the circle — both ends of the gap pull back to the gap's edges.
|
|
49
|
+
// piece 2, the check (check-mark.ts, shared with "checkbox"): drawn in like a pen from unchecked.
|
|
50
|
+
import { arc } from '../geometry.js';
|
|
51
|
+
import { checkMarkPiece } from './check-mark.js';
|
|
52
|
+
import { fromLucide, LUCIDE_STROKE_WIDTH, lucideLength } from './lucide.js';
|
|
53
|
+
const [CENTER_X, CENTER_Y] = fromLucide([12, 12]);
|
|
54
|
+
const RADIUS = lucideLength(10);
|
|
55
|
+
/** The open arc of circle-check-big runs clockwise from 21.801,10 to 17,3.335 (the gap is the rest). */
|
|
56
|
+
const OPEN_START_ANGLE = (Math.atan2(10 - 12, 21.801 - 12) * 180) / Math.PI;
|
|
57
|
+
const OPEN_END_ANGLE = (Math.atan2(3.335 - 12, 17 - 12) * 180) / Math.PI + 360;
|
|
58
|
+
/** The share of the full circle that stays in checked-big. */
|
|
59
|
+
const OPEN_SHARE = (OPEN_END_ANGLE - OPEN_START_ANGLE) / 360;
|
|
60
|
+
/** The full circle starts where the open arc starts, so the gap is its last part. */
|
|
61
|
+
const CIRCLE = [arc(CENTER_X, CENTER_Y, RADIUS, OPEN_START_ANGLE, OPEN_START_ANGLE + 360)];
|
|
62
|
+
const OPEN_CIRCLE = [arc(CENTER_X, CENTER_Y, RADIUS, OPEN_START_ANGLE, OPEN_END_ANGLE)];
|
|
63
|
+
// circle, unchecked/checked ↔ checked-big: the open part 10 segments, the gap 2 (one per half), started at the gap's
|
|
64
|
+
// second half — so it lines up with the open arc, which gets a zero-length segment at each end of the gap where
|
|
65
|
+
// the vanishing halves pull back to.
|
|
66
|
+
const openPart = Array.from({ length: 11 }, (_, index) => +((index / 10) * OPEN_SHARE).toFixed(4));
|
|
67
|
+
const CIRCLE_FOR_OPEN_CIRCLE = { breakpoints: [...openPart, +((1 + OPEN_SHARE) / 2).toFixed(4), 1], startSegment: 11 };
|
|
68
|
+
const OPEN_CIRCLE_FOR_CIRCLE = { breakpoints: [0, ...Array.from({ length: 11 }, (_, index) => index / 10), 1] };
|
|
69
|
+
export const iconsRadio = {
|
|
70
|
+
segmentCount: 12,
|
|
71
|
+
strokeWidth: LUCIDE_STROKE_WIDTH,
|
|
72
|
+
lineCap: 'round',
|
|
73
|
+
lineJoin: 'round',
|
|
74
|
+
strokes: { unchecked: CIRCLE, checked: CIRCLE, 'checked-big': OPEN_CIRCLE },
|
|
75
|
+
alternativeStrokes: {},
|
|
76
|
+
pairLayouts: {
|
|
77
|
+
unchecked: { 'checked-big': CIRCLE_FOR_OPEN_CIRCLE },
|
|
78
|
+
checked: { 'checked-big': CIRCLE_FOR_OPEN_CIRCLE },
|
|
79
|
+
'checked-big': { unchecked: OPEN_CIRCLE_FOR_CIRCLE, checked: OPEN_CIRCLE_FOR_CIRCLE },
|
|
80
|
+
},
|
|
81
|
+
// the check rests (hidden) on the circle's left edge
|
|
82
|
+
morePieces: [checkMarkPiece([2, 12])],
|
|
83
|
+
spins: {},
|
|
84
|
+
};
|