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,244 @@
|
|
|
1
|
+
/*! morphico v0.5.0 | MIT License, Copyright (c) 2026 Raycho Ivanov (see LICENSE) */
|
|
2
|
+
// Digit set "round": geometric sans digits, drafted from the reference images in icons/round/
|
|
3
|
+
// (the set format is described in ../types.ts).
|
|
4
|
+
//
|
|
5
|
+
// Measured from the images and tidied up so shared parts are exactly shared:
|
|
6
|
+
// - round digits span y 4…20, bars sit at y 4.2 / 19.8
|
|
7
|
+
// - round line ends: every open end stops half a stroke (END_INSET) before the edge measured in the images
|
|
8
|
+
// (the images have flat ends), so the round cap ends exactly there — bottoms of 1, 4, 7, 9 line up with the base
|
|
9
|
+
// - one big circle radius (2, 3, 6, 8, 9) and one small one (top of 3 and 8); 5 has its own, larger bowl
|
|
10
|
+
// - 3 is drawn on exactly the two circles of 8 (they touch at 12, 11.2)
|
|
11
|
+
// - 9 is exactly 6 turned 180° around 12,12 → 6 ↔ 9 morphs as a pure spin
|
|
12
|
+
import { arc, ellipse, line, pointOnCircle } from '../geometry.js';
|
|
13
|
+
import { withTextCharacters } from './characters.js';
|
|
14
|
+
const STROKE_WIDTH = 1.2; // the reference images use 1.6; thinner by the user's choice
|
|
15
|
+
/** A round line end reaches this far beyond its end point. */
|
|
16
|
+
const END_INSET = STROKE_WIDTH / 2;
|
|
17
|
+
/** Angle that shortens an arc's end by END_INSET along the circle. */
|
|
18
|
+
const arcInset = (radius) => (END_INSET / radius) * (180 / Math.PI);
|
|
19
|
+
/** The point on the line through `from` and `to` at height `y`. */
|
|
20
|
+
const pointAtY = ([fromX, fromY], [toX, toY], y) => [fromX + ((toX - fromX) * (y - fromY)) / (toY - fromY), y];
|
|
21
|
+
const BIG_RADIUS = 4.4;
|
|
22
|
+
const SMALL_RADIUS = 3.6;
|
|
23
|
+
const TOP_BAR_Y = 4.2;
|
|
24
|
+
const BASE_Y = 19.8;
|
|
25
|
+
/** Where the 6's tail touches its circle (tangent); 9 uses the same angle turned by 180°. */
|
|
26
|
+
const SIX_TAIL_ANGLE = -147.1085;
|
|
27
|
+
const SIX_TAIL_JOIN = pointOnCircle(12, 15.6, BIG_RADIUS, SIX_TAIL_ANGLE);
|
|
28
|
+
/** Top end of the 6's tail: on the measured tail line (from 14.65, 3.4), pulled in so the round end tops at 3.4. */
|
|
29
|
+
const SIX_TAIL_TOP = pointAtY([14.65, 3.4], SIX_TAIL_JOIN, TOP_BAR_Y);
|
|
30
|
+
/** Bottom end of the 9's tail: the 6's tail top turned 180° around 12,12. */
|
|
31
|
+
const NINE_TAIL_END = [24 - SIX_TAIL_TOP[0], 24 - SIX_TAIL_TOP[1]];
|
|
32
|
+
/** Where the 2's diagonal leaves its bowl (tangent towards the corner at 8.3, 19.8). */
|
|
33
|
+
const TWO_DIAGONAL_ANGLE = 39.5191;
|
|
34
|
+
/** Where the 5's short down-stroke meets its bowl. */
|
|
35
|
+
const FIVE_JOIN_ANGLE = 237.2;
|
|
36
|
+
/** The 7's foot: on the measured diagonal (16, 4.2 → 7.45, 20.6), pulled in to the base line. */
|
|
37
|
+
const SEVEN_FOOT = pointAtY([16, TOP_BAR_Y], [7.45, 20.6], BASE_Y);
|
|
38
|
+
// '-' '/' '.' ',' ':' are added by withTextCharacters (characters.ts)
|
|
39
|
+
export const digitsRound = withTextCharacters({
|
|
40
|
+
segmentCount: 12,
|
|
41
|
+
strokeWidth: STROKE_WIDTH,
|
|
42
|
+
lineCap: 'round',
|
|
43
|
+
lineJoin: 'round',
|
|
44
|
+
strokes: {
|
|
45
|
+
0: ellipse(12, 12, 5.05, 8),
|
|
46
|
+
1: [line(10 + END_INSET, TOP_BAR_Y, 13.1, TOP_BAR_Y), line(13.1, TOP_BAR_Y, 13.1, BASE_Y)],
|
|
47
|
+
2: [
|
|
48
|
+
arc(12, 8.4, BIG_RADIUS, 158.7 + arcInset(BIG_RADIUS), TWO_DIAGONAL_ANGLE + 360),
|
|
49
|
+
line(...pointOnCircle(12, 8.4, BIG_RADIUS, TWO_DIAGONAL_ANGLE), 8.3, BASE_Y),
|
|
50
|
+
line(8.3, BASE_Y, 17.5 - END_INSET, BASE_Y),
|
|
51
|
+
],
|
|
52
|
+
3: [
|
|
53
|
+
arc(12, 7.6, SMALL_RADIUS, 180 + arcInset(SMALL_RADIUS), 439.2),
|
|
54
|
+
// the two arcs meet slightly right of the point where the circles touch
|
|
55
|
+
line(...pointOnCircle(12, 7.6, SMALL_RADIUS, 79.2), ...pointOnCircle(12, 15.6, BIG_RADIUS, 278.7)),
|
|
56
|
+
arc(12, 15.6, BIG_RADIUS, 278.7, 536.7 - arcInset(BIG_RADIUS)),
|
|
57
|
+
],
|
|
58
|
+
// one stroke: crossbar right → left, diagonal up to the top, stem down
|
|
59
|
+
4: [
|
|
60
|
+
line(17.6 - END_INSET, 14.95, 8, 14.95),
|
|
61
|
+
line(8, 14.95, 14.75, TOP_BAR_Y),
|
|
62
|
+
line(14.75, TOP_BAR_Y, 14.75, BASE_Y),
|
|
63
|
+
],
|
|
64
|
+
5: [
|
|
65
|
+
line(17.1 - END_INSET, TOP_BAR_Y, 10.5, TOP_BAR_Y),
|
|
66
|
+
line(10.5, TOP_BAR_Y, ...pointOnCircle(11.9, 15, 4.8, FIVE_JOIN_ANGLE)),
|
|
67
|
+
arc(11.9, 15, 4.8, FIVE_JOIN_ANGLE, 523.3 - arcInset(4.8)),
|
|
68
|
+
],
|
|
69
|
+
6: [
|
|
70
|
+
line(...SIX_TAIL_TOP, ...SIX_TAIL_JOIN),
|
|
71
|
+
arc(12, 15.6, BIG_RADIUS, SIX_TAIL_ANGLE, SIX_TAIL_ANGLE - 360),
|
|
72
|
+
],
|
|
73
|
+
7: [line(6.7 + END_INSET, TOP_BAR_Y, 16, TOP_BAR_Y), line(16, TOP_BAR_Y, ...SEVEN_FOOT)],
|
|
74
|
+
// closed figure-eight: top circle clockwise, bottom circle counter-clockwise, meeting where they touch
|
|
75
|
+
8: [arc(12, 7.6, SMALL_RADIUS, 90, 450), arc(12, 15.6, BIG_RADIUS, 270, -90)],
|
|
76
|
+
9: [
|
|
77
|
+
arc(12, 8.4, BIG_RADIUS, SIX_TAIL_ANGLE + 180 - 360, SIX_TAIL_ANGLE + 180),
|
|
78
|
+
line(...pointOnCircle(12, 8.4, BIG_RADIUS, SIX_TAIL_ANGLE + 180), ...NINE_TAIL_END),
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
alternativeStrokes: {
|
|
82
|
+
// the 8 traced like the 0 (from the top, counter-clockwise): left half of the top circle down to the waist,
|
|
83
|
+
// once around the bottom circle, right half of the top circle back up
|
|
84
|
+
'8-like-0': [
|
|
85
|
+
arc(12, 7.6, SMALL_RADIUS, 270, 90),
|
|
86
|
+
arc(12, 15.6, BIG_RADIUS, 270, -90),
|
|
87
|
+
arc(12, 7.6, SMALL_RADIUS, 90, -90),
|
|
88
|
+
],
|
|
89
|
+
// the 8 as two clockwise loops, both starting at the waist (like the 3: top arc, then bottom arc)
|
|
90
|
+
'8-two-loops': [arc(12, 7.6, SMALL_RADIUS, 90, 450), arc(12, 15.6, BIG_RADIUS, 270, 630)],
|
|
91
|
+
// the 6 with its circle drawn clockwise (the same way round as the 5's bowl)
|
|
92
|
+
'6-clockwise': [
|
|
93
|
+
line(...SIX_TAIL_TOP, ...SIX_TAIL_JOIN),
|
|
94
|
+
arc(12, 15.6, BIG_RADIUS, SIX_TAIL_ANGLE, SIX_TAIL_ANGLE + 360),
|
|
95
|
+
],
|
|
96
|
+
// mirrored figure-eight from the waist: top circle counter-clockwise, bottom circle clockwise (like the 5)
|
|
97
|
+
'8-mirrored': [arc(12, 7.6, SMALL_RADIUS, 90, -270), arc(12, 15.6, BIG_RADIUS, 270, 630)],
|
|
98
|
+
// the usual figure-eight, but starting on the right side of the bottom circle (where the 4's crossbar starts)
|
|
99
|
+
'8-from-right': [
|
|
100
|
+
arc(12, 15.6, BIG_RADIUS, 0, -90),
|
|
101
|
+
arc(12, 7.6, SMALL_RADIUS, 90, 450),
|
|
102
|
+
arc(12, 15.6, BIG_RADIUS, 270, 0),
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
pairLayouts: {
|
|
106
|
+
0: {
|
|
107
|
+
// cut the 0 open at the upper left: the part going up over the top becomes the flag, the rest the stem
|
|
108
|
+
1: { startSegment: 2, reversed: true },
|
|
109
|
+
// start at the leftmost point and go up, like the 2's bowl
|
|
110
|
+
2: { startSegment: 3, reversed: true },
|
|
111
|
+
3: { startSegment: 3, reversed: true },
|
|
112
|
+
// start at the lower right and go left: bottom → crossbar, left side → diagonal, right side → stem
|
|
113
|
+
4: { startSegment: 7, reversed: true },
|
|
114
|
+
// optimizer: start at the upper left and go clockwise, the same way round as the 5's bowl
|
|
115
|
+
5: { startSegment: 2, reversed: true },
|
|
116
|
+
// start at the leftmost point and go up: the top becomes the bar, the right side the diagonal
|
|
117
|
+
7: { startSegment: 3, reversed: true },
|
|
118
|
+
// start at the bottom and go clockwise, the same way round as the 9's circle
|
|
119
|
+
9: { startSegment: 6, reversed: true },
|
|
120
|
+
},
|
|
121
|
+
1: {
|
|
122
|
+
4: { breakpoints: [0, 1, 1.0625, 1.125, 1.1875, 1.2708, 1.2708, 1.6875, 1.6875, 1.6875, 1.6875, 1.6875, 2] },
|
|
123
|
+
// flag curls into the top loop, stem rounds into the bottom loop (optimizer fit)
|
|
124
|
+
8: { breakpoints: [0, 0, 0, 1, 1.3125, 1.4583, 1.5208, 1.8333, 1.8333, 1.8333, 1.8333, 1.8333, 2] },
|
|
125
|
+
// fewer segments for the 9's circle, more for its tail; the circle unrolls into flag + stem top (optimizer fit)
|
|
126
|
+
9: { breakpoints: [0, 0, 0, 1, 1.1042, 1.4167, 1.4792, 1.5625, 1.625, 1.6875, 1.7708, 1.8125, 2] },
|
|
127
|
+
},
|
|
128
|
+
2: {
|
|
129
|
+
// the 4's crossbar shrinks into the 2's starting tip, the diagonal and stem bend into the bowl (optimizer fit)
|
|
130
|
+
4: { breakpoints: [0, 0, 0.3542, 0.6875, 0.7708, 1, 1.2083, 1.2292, 2, 2.7292, 2.7292, 2.7292, 3] },
|
|
131
|
+
// bowl → the 5's bar and down-stroke, diagonal + base → its bowl (optimizer fit)
|
|
132
|
+
5: { breakpoints: [0, 0.375, 0.375, 0.375, 0.625, 1, 1.0833, 1.0833, 1.1458, 1.4375, 1.7083, 2, 3] },
|
|
133
|
+
// the bowl closes into the 9's circle (same circle), the base pulls back into the tail (optimizer fit)
|
|
134
|
+
9: { breakpoints: [0, 0, 0, 0, 0.2083, 0.3958, 0.5833, 0.7708, 1, 1.2083, 1.3542, 2, 3] },
|
|
135
|
+
// 2 → 6 spins (see spins): in the turning frame it is 2 → 9 — the 2's bowl is exactly the 9's circle
|
|
136
|
+
6: { breakpoints: [0, 0, 0, 0, 0.2292, 0.4167, 0.6042, 0.7708, 1, 1.2083, 1.4167, 2, 3] },
|
|
137
|
+
},
|
|
138
|
+
3: {
|
|
139
|
+
// the 4's crossbar shrinks into the 3's starting tip, the diagonal becomes the top arc (optimizer fit)
|
|
140
|
+
4: { breakpoints: [0, 0, 0.3333, 0.6042, 0.7917, 1, 2, 2.1458, 2.3333, 2.5208, 2.5208, 2.6667, 3] },
|
|
141
|
+
// the small top arc grows into the 9's circle, the lower bowl straightens into the tail (optimizer fit)
|
|
142
|
+
9: { breakpoints: [0, 0, 0, 0, 0.0208, 0.2708, 0.4792, 0.6458, 1, 2, 2.3542, 2.6667, 3] },
|
|
143
|
+
},
|
|
144
|
+
4: {
|
|
145
|
+
// drawn from the stem's bottom: the 1's stem stays a stem, its flag folds out into diagonal + crossbar
|
|
146
|
+
1: { breakpoints: [0, 0.4375, 0.4375, 0.4375, 0.4375, 1, 1.6042, 1.6042, 1.7292, 1.8333, 1.8958, 2, 3], reversed: true },
|
|
147
|
+
2: { breakpoints: [0, 1, 2, 2, 2.1458, 2.3958, 2.5208, 2.6667, 2.8125, 2.9375, 2.9375, 2.9375, 3] },
|
|
148
|
+
3: { breakpoints: [0, 1, 2, 2.0208, 2.2708, 2.3958, 2.3958, 2.4792, 2.6875, 2.9167, 2.9167, 2.9167, 3] },
|
|
149
|
+
// crossbar → top bar (moves up), diagonal → down-stroke, stem → bowl (optimizer fit)
|
|
150
|
+
5: { breakpoints: [0, 1, 1.3958, 1.3958, 1.3958, 1.4792, 1.4792, 2, 2.3958, 2.3958, 2.5833, 2.9583, 3] },
|
|
151
|
+
// drawn from the stem's bottom: stem top → the 6's tail top, diagonal + crossbar → circle (optimizer fit)
|
|
152
|
+
6: { breakpoints: [0, 0.3542, 0.3542, 0.3542, 0.3542, 0.4375, 0.875, 1, 1.1042, 1.3958, 1.6042, 2, 3], reversed: true },
|
|
153
|
+
// drawn from the stem's bottom: stem tips over into the 7's bar, diagonal + crossbar → its diagonal (optimizer fit)
|
|
154
|
+
7: { breakpoints: [0, 1, 1, 1.1667, 1.3542, 1.5625, 1.7292, 1.9792, 2, 2, 2, 2, 3], reversed: true },
|
|
155
|
+
// drawn backwards (stem bottom first), so the stem's end meets the crossbar's start on the 8's right side
|
|
156
|
+
8: { reversed: true },
|
|
157
|
+
},
|
|
158
|
+
5: {
|
|
159
|
+
0: { breakpoints: [0, 1, 1, 2, 2.2708, 2.3125, 2.4792, 2.625, 2.75, 2.8542, 3, 3, 3] },
|
|
160
|
+
2: { breakpoints: [0, 1, 1, 1, 2, 2.2917, 2.2917, 2.2917, 2.2917, 2.5417, 2.8542, 2.8542, 3] },
|
|
161
|
+
4: { breakpoints: [0, 1, 2, 2, 2, 2.0833, 2.1458, 2.1667, 2.1875, 2.25, 2.3958, 2.6875, 3] },
|
|
162
|
+
// bar stays the bar, down-stroke + bowl straighten into the 7's diagonal (optimizer fit)
|
|
163
|
+
7: { breakpoints: [0, 0.5625, 0.5625, 0.5625, 0.5625, 0.5625, 1, 2, 2.2083, 2.5208, 2.8333, 2.9167, 3] },
|
|
164
|
+
// start of the 5 (bar end) moves down to the 9's start; segments re-spread on both (optimizer fit)
|
|
165
|
+
9: { breakpoints: [0, 1, 2, 2, 2.0208, 2.1042, 2.1667, 2.2292, 2.2708, 2.3125, 2.5625, 2.75, 3] },
|
|
166
|
+
},
|
|
167
|
+
6: {
|
|
168
|
+
// the 1's flag shrinks into the top of the tail, its stem tilts into the tail and curls into the circle
|
|
169
|
+
// (optimizer fit, like 7 → 6)
|
|
170
|
+
1: {
|
|
171
|
+
tracing: '6-clockwise',
|
|
172
|
+
breakpoints: [0, 0.1042, 0.1042, 0.1667, 0.3125, 0.3125, 1, 1.25, 1.25, 1.3542, 1.5, 1.75, 2],
|
|
173
|
+
},
|
|
174
|
+
// turned by 180° this is the 9 laid out for the 2 (optimizer fit for 2 ↔ 9, mirrored onto the 6)
|
|
175
|
+
2: { breakpoints: [0, 0.1042, 0.5417, 0.75, 1, 1.125, 1.25, 1.375, 1.5, 1.6458, 1.6458, 1.75, 2], reversed: true },
|
|
176
|
+
4: { breakpoints: [0, 0.3958, 0.4792, 0.75, 1, 1.0625, 1.1458, 1.3958, 1.625, 1.625, 1.625, 1.75, 2] },
|
|
177
|
+
// the 3's lower bowl lies on the 6's circle and closes up; its top arc straightens into the tail (optimizer fit)
|
|
178
|
+
3: {
|
|
179
|
+
tracing: '6-clockwise',
|
|
180
|
+
breakpoints: [0, 0.2292, 0.2292, 0.2292, 0.3125, 1, 1.2083, 1.2917, 1.4167, 1.5417, 1.6667, 1.7708, 2],
|
|
181
|
+
},
|
|
182
|
+
// the 5's bowl end closes up to where the bowl starts; bar + down-stroke become the tail (optimizer fit)
|
|
183
|
+
5: {
|
|
184
|
+
tracing: '6-clockwise',
|
|
185
|
+
breakpoints: [0, 0.0833, 0.25, 0.4375, 0.5625, 1, 1.1875, 1.2708, 1.3958, 1.5, 1.6458, 1.75, 2],
|
|
186
|
+
},
|
|
187
|
+
// the 7's bar shrinks into the top of the tail, its diagonal becomes the tail and curls into the circle
|
|
188
|
+
// (optimizer fit)
|
|
189
|
+
7: {
|
|
190
|
+
tracing: '6-clockwise',
|
|
191
|
+
breakpoints: [0, 0.1667, 0.1667, 0.1667, 0.1667, 0.1667, 0.3125, 1, 1.25, 1.5, 1.75, 1.75, 2],
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
7: {
|
|
195
|
+
5: { breakpoints: [0, 0.6875, 0.6875, 0.6875, 0.6875, 0.6875, 1, 1.4375, 1.4375, 1.6042, 1.9167, 1.9167, 2] },
|
|
196
|
+
4: { breakpoints: [0, 1, 1.0833, 1.0833, 1.0833, 1.1042, 1.25, 1.3542, 1.5, 1.625, 1.6667, 1.6667, 2] },
|
|
197
|
+
},
|
|
198
|
+
8: {
|
|
199
|
+
1: { breakpoints: [0, 0.25, 0.4792, 0.5625, 0.8125, 1, 1.0625, 1.3125, 1.5625, 1.6042, 1.6042, 1.75, 2] },
|
|
200
|
+
// 0's leftmost and rightmost points (after 3 and 9 segments) both land on the waist
|
|
201
|
+
0: {
|
|
202
|
+
tracing: '8-like-0',
|
|
203
|
+
breakpoints: [0, 1 / 3, 2 / 3, 1, 1 + 1 / 6, 1 + 2 / 6, 1 + 3 / 6, 1 + 4 / 6, 1 + 5 / 6, 2, 2 + 1 / 3, 2 + 2 / 3, 3],
|
|
204
|
+
},
|
|
205
|
+
// both ends of the 3 slide along their circles into the waist: 5 segments on the top loop like the 3's
|
|
206
|
+
// top arc, a zero-length one at the waist for the 3's middle link, 6 on the bottom loop
|
|
207
|
+
3: {
|
|
208
|
+
tracing: '8-two-loops',
|
|
209
|
+
breakpoints: [0, 0.2, 0.4, 0.6, 0.8, 1, 1, 1 + 1 / 6, 1 + 2 / 6, 1 + 3 / 6, 1 + 4 / 6, 1 + 5 / 6, 2],
|
|
210
|
+
},
|
|
211
|
+
// the 4's two ends meet on the right side of the bottom circle (optimizer fit)
|
|
212
|
+
4: {
|
|
213
|
+
tracing: '8-from-right',
|
|
214
|
+
breakpoints: [0, 0, 0.125, 1, 1.25, 1.5, 1.75, 2, 2.1458, 2.2917, 2.625, 2.9583, 3],
|
|
215
|
+
},
|
|
216
|
+
// both ends of the 5 meet at the waist: bar + down-stroke → top loop, bowl → bottom loop (optimizer fit)
|
|
217
|
+
5: {
|
|
218
|
+
tracing: '8-mirrored',
|
|
219
|
+
breakpoints: [0, 0.25, 0.5, 0.6875, 0.8125, 0.8958, 1, 1.125, 1.2292, 1.3542, 1.5, 1.75, 2],
|
|
220
|
+
},
|
|
221
|
+
// 8 → 9 spins (see spins): in the turning frame it is 8 → 6, the 8's big circle stays the 6's circle
|
|
222
|
+
9: { startSegment: 1 },
|
|
223
|
+
},
|
|
224
|
+
9: {
|
|
225
|
+
1: { breakpoints: [0, 0.25, 0.5, 0.75, 0.8125, 1, 1.1042, 1.2292, 1.3542, 1.4583, 1.6042, 1.6875, 2] },
|
|
226
|
+
2: { breakpoints: [0, 0.25, 0.375, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 1.2708, 1.4375, 2, 2] },
|
|
227
|
+
3: { breakpoints: [0, 0.25, 0.4792, 0.4792, 0.4792, 0.625, 0.75, 0.875, 1, 1.1667, 1.3125, 1.9583, 2] },
|
|
228
|
+
5: { breakpoints: [0, 0, 0.25, 0.2917, 0.3125, 0.5625, 0.8125, 1, 1.0833, 1.0833, 1.5, 1.8542, 2] },
|
|
229
|
+
// turned back by 180° this is exactly the 6 (same segment split, same direction) → a pure spin
|
|
230
|
+
6: { breakpoints: [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 1.25, 1.5, 1.75, 2], reversed: true },
|
|
231
|
+
// turned back by 180° this is the 6 laid out for the 8 (optimizer fit for 6 ↔ 8, mirrored onto the 9)
|
|
232
|
+
8: { breakpoints: [0, 0.1667, 0.2917, 0.4375, 0.5833, 0.7292, 0.875, 1, 1.3125, 1.7083, 1.75, 1.75, 2], reversed: true },
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
// 9 is exactly 6 turned 180°, the 6's circle is the 8's bottom circle and the 2's bowl is the 9's circle:
|
|
236
|
+
// 6 ↔ 9, 8 ↔ 9 and 2 ↔ 6 morph while turning
|
|
237
|
+
spins: {
|
|
238
|
+
2: { 6: 180 },
|
|
239
|
+
6: { 9: 180, 2: -180 },
|
|
240
|
+
8: { 9: 180 },
|
|
241
|
+
9: { 6: -180, 8: -180 },
|
|
242
|
+
},
|
|
243
|
+
textLayout: { cellWidth: 10, spacing: 4, baselineY: 19.8, colonDotsY: [7.6, 15.6] },
|
|
244
|
+
});
|