common: wrap some long code lines to 78 columns
[sheet.git] / writing-latn.inc.pl
1 use 5.014;
2 use utf8;
3 use warnings;
4 use List::Util qw( pairs pairmap sum );
5
6 my %C = (
7         red    => '#EC1C24',
8         blue   => '#3953A3',
9         yellow => '#F9EC31',
10         black  => '#231F20',
11 );
12 my $U = 0;  # optional unicode alternatives
13
14 my @wrapstyle = (
15         'td { white-space: normal; word-spacing: 10em }',
16                 # force line break between words
17         '.sample { word-spacing: 0 }',
18         '.sample span { margin-right: 1ex; white-space: nowrap; display: inline-block }',
19                 # larger space between letters
20 );
21 my $spacestyle = '.sample span { margin-right: 0.5ex }';  # separate letters
22 my @tapstyle = (
23         @wrapstyle,
24         '{ line-height: 1ex }',
25         'td:not(.sample) { vertical-align: top }',
26         '.sample { font-size: 80% }',
27 );
28
29 my @hueorder = (
30         2,11,20,19,18,21,24,15,6,7,8,5,13, # red .. magenta, grey
31         1,10,9,12,3,4,0, 14,23,22,25,16,17,26, # dark, light hues
32 );
33
34 # Order to put similar sounds close to each other:
35 #         ┌ R Y G C B M X
36 #        ┌┼──────────────
37 #        W│ o e y h s f -
38 #         │muaixqgkdtbp l
39 #        K│ w n j c z v r
40
41 my @hueletters = ((26) x 27);
42 @hueletters[map { ord($_) - ord('a') } qw(
43         u a i x q g k d t b p m l   w n j c z v r   o e y h s f
44 )] = @hueorder;
45
46 sub disptap {
47         my $code = shift;
48         my ($prefix, @dots) = $code =~ m/\A(-?)(\d)(\d)/ or return $code;
49         if ($U) {
50                 # unicode glyph alternative as DOMINO TILE HORIZONTAL-0a-0b
51                 return $prefix . chr(0x1F031 + ($dots[0] * 7) + $dots[1]);
52         }
53         return $prefix . join(' ', map { '·' x $_ } @dots);
54 }
55
56 sub dispbar {
57         my $code = shift or return '';
58
59         return join '', pairmap {
60                 ($a =~ tr/123/❘❙❚/r) . ($b =~ tr/321/  /dr)
61         } split //, $code if $U;
62
63         my @cols = split //, $code;  # bar and space widths
64         my $width = sum(@cols);
65         return sprintf(
66                 '<svg width="%d" height="%d" viewBox="-.5 0 %d %d"><path d="%s"/></svg>',
67                 $width * 2, 14, $width, 7, join(' ',
68                         'M0,0',
69                         map {
70                                 join('m1,-7', ('v7') x $_->[0]),  # line per bar width
71                                 (map { sprintf 'm%d,-7', $_ + 1 } $_->[1] || ()),  # space forward
72                         }
73                         pairs @cols
74                 )
75         );
76 }
77
78 sub disphues {
79         my ($index, $hues, $opaque) = @_;
80         $index >= 0 or $index = 26;
81         my @lum = ($index % 3, $index / 3 % 3, $index / 9);  # hue opacities (0..2)x3
82         my @lumf = $opaque ? ('hsl(%s,100%%,50%%)', 'hsl(%s,100%%,25%%)') :
83                 ('hsl(%s,100%%,50%%)', 'hsla(%s,100%%,50%%,.5)');
84         return sprintf(
85                 '<svg width="16" height="16" viewBox="0 0 12 12">%s</svg>',
86                 join '', map {
87                         my $colf = $lumf[ $lum[$_] ];
88                         !$colf ? () : sprintf('<circle cx="%d" cy="%d" r="%d" fill="%s"/>',
89                                 5 + $_, $_ == 1 ? 7 : 5, 5, sprintf($colf, $hues->[$_])
90                         );
91                 } 0 .. 2
92         );
93 }
94
95 (
96 uppercase => {
97         list => [qw{ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z }],
98 },
99 lowercase => {
100         list => [qw{ a b c d e f g h i j k l m n o p q r s t u v w x y z }],
101 },
102 suetterlin => {
103         title => 'Sütterlin',
104         style => [
105                 '@font-face {
106                         font-family: Suetterlin; /* R. G. Arens */
107                         src: url("/suetterlin.ttf");
108                 }',
109                 'td { font-family: Suetterlin }',
110         ],
111         list => [qw{ a b c d e f g h i j k l m n o p q r ſ s t u v w x y z }],
112 },
113 roman => {
114         title => 'Old Roman Cursive',
115         style => [
116                 'svg path { stroke-linecap: round; stroke-linejoin: round }',
117                 '.sample span { margin-right: -10px }',
118         ],
119         list => [
120                 map {
121                         s{\A-?\K(\w.+)}
122                          {<svg width="20" height="20" viewBox="0 0 12 20"><path d="$1"/></svg>}r
123                 }
124                 "m2,4 c1,2 8,9 8,9 M2,15 6,9",
125                 "m2,4 c0,0 3,-2 4,1 1,2 0,9 3,9 1,-0 2,-1 2,-1 m-6,-2 c-5,4 -0,6 1,3",
126                 "m4,7 4,-2 m-4,4 c0,0 -2,7 3,6",
127                 "m3,2 c0,0 7,10 7,12 m-2,-4 c-5,2 -4,9 1,3",
128                 "m3,10 4,0 m2,-7 c0,0 -7,1 -5,16",
129                 "m4,11 5,-2 m-3,-4 7,-4 M0,18 c0,0 4,3 5,-3 2,-6 2,-10 2,-10",
130                 "m3,6 7,-2 m-7,4 c-2,5 4,9 6,6 l1,3",
131                 "m7,9 4,-0 m-8,0 c4,0 6,-1 5,6 M1,3 c2,-0 2,12 2,12",
132                 '>', # i = j
133                 "m6,8 -0,7",
134                 "-m9,5 -5,4 4,4 m-4,-10 -1,13",
135                 "m3,2 c0,0 -1,9 1,10 5,2 6,2 6,2",
136                 "m0,16 3,-10 4,6 2,-5 5,4",
137                 "m2,16 1,-9 5,8 2,-9",
138                 "m5,8 c-2,0 -2,6 1,5 4,-2 1,-5 1,-5",
139                 "m5,8 c0,0 -1,8 2,6 m-3,-7 5,3",
140                 "m3,6 9,12 m-9,-11 c-4,1 -3,4 -3,4 0,0 2,2 6,-1",
141                 "m0,6 c3,-1 3,-1 6,0 2,1 3,3 6,1 m-7,-1 -2,11",
142                 "m13,3 c0,0 -5,2 -8,4 -2,3 -1,5 -2,9 -1,1 -4,2 -4,2",
143                 "m2,7 8,0 m-4,1 c0,0 -1,8 3,5",
144                 '>', # u = v
145                 "m2,5 c0,0 3,5 6,3 3,-2 2,-3 2,-3",
146                 '-',
147                 "m3,19 c-1,-6 6,-17 6,-17 M1,8 c0,0 10,1 10,1",
148                 "-m0,7 c2,-3 5,-2 5,1 l0,11 c0,0 -0,-4 -0,-10 -0,-4 4,-4 6,-3",
149                 "-m3,6 c4,-1 3,3 3,3 -1,3 -2,5 -1,5 1,1 3,0 3,0",
150         ],
151 },
152 sutton => {
153         title => 'Sutton <abbr title="American Sign Lanugage">ASL</abbr>',
154         style => $spacestyle,
155         list => [
156                 # American manual alphabet in Sutton (U+1D800+) notation
157                 map { !!$_ && pack 'W*', map { hex "1D$_" } unpack '(A3)*', $_ } qw{
158                 8F7a9c    847a9c    86Da9c    801a9c    84Aa9c
159                 8CEa9c    8F0       815aa2    892a9c    892a9c9A2aac
160                 840a9c    8DCa9c    88Da9c
161                 819a9c    876a9c    840a9caA1 8F0a9caA1 81Aa9c
162                 903a9c    8FBa9c    815a9c    80Ea9c    887a9c
163                 806a9c    89Aa9c    800a9c945aaa
164                 0         965aa6
165         }],
166 },
167 unistrokes => {
168         title => 'Unistrokes',
169         url   => 'https://www.google.com/patents/US5596656', # by Xerox
170         style => 'svg path { stroke-linecap: round; stroke-linejoin: round }',
171         list => [
172                 map { '<svg width="14" height="16" viewBox="-1 -1 8 10">'.$_.'</svg>' }
173                 map {
174                         sprintf('<circle cx="%s" cy="%s" r="1"/>', m/\AM(\d+),(\d+)(.?)/) . # start point
175                         (!!$3 && qq(<path d="$_"/>))
176                 }
177                 'M3,8 V0',
178                 'M0,0 6,4 0,8',
179                 'M6,0 0,4 6,8',
180                 'M6,0 0,4 6,8',
181                 'M6,4 H0',
182                 'M6,0 0,0 0,8',
183                 'M0,8 6,8 6,0',
184                 'M0,0 6,0 6,8',
185                 'M3,0 V8',
186                 'M6,0 6,8 0,8',
187                 'M0,8 6,0',
188                 'M0,0 0,8 6,8',
189                 'M6,8 3,0 0,8',
190                 'M0,8 3,0 6,8',
191                 'M6,0 Q0,6 3,8 6,6 0,0',
192                 'M0,0 Q4,8 6,4 4,0 0,8',
193                 'M6,0 Q2,8 0,4 2,0 6,8',
194                 'M0,0 6,8',
195                 'M6,0 0,0 6,8 0,8',
196                 'M0,4 H6',
197                 'M6,0 3,8 0,0',
198                 'M0,0 3,8 6,0',
199                 'M0,0 0,8 6,0 6,8',
200                 'M0,0 Q6,6 3,8 0,6 6,0',
201                 'M6,0 0,8',
202                 'M0,0 6,0 0,8 6,8',
203                 'M3,4',
204         ],
205 },
206 edgewrite => {
207         title => 'EdgeWrite',
208         url   => 'http://depts.washington.edu/ewrite/', # patented US7729542
209         style => 'svg path { stroke-linecap: round; stroke-linejoin: round }',
210         list => [
211                 map { '<svg width="14" height="14" viewBox="-1 -1 10 10">'.$_.'</svg>' }
212                 map {
213                         my @route = split //;
214                         my @coords = map { $_ % 2 << 3, $_ >> 1 << 3 } @route; # x,y,
215                         sprintf('<circle cx="%s" cy="%s" r="1"/><path d="M%s"/>',
216                                 @coords[0, 1],  # start point
217                                 join(' ', map {
218                                         my $pos = join(',', @coords[$_*2, $_*2 + 1]);
219                                         $_ > 1 && $route[$_] == $route[$_ - 2] # curve back
220                                                 ? 'Q4,4 '.$pos.'L' : $pos
221                                 } 0 .. $#route),
222                         )
223                 }
224                 # corners (0..3) clockwise from top-left in order
225                 qw(
226                         213 0232 1023 1323 103 102 10132 0213 02 132 02123 023 20313 2031
227                         10231 0102 10131 201 1032 013 0231 021 02131 0312 0313 0123  01
228                 )
229         ],
230 },
231 #graffiti => {
232 #       title => 'Palm Graffiti',
233 #},
234 ita2 => {
235         title => '<abbr title="International Telegraph Alphabet">ITA</abbr>2',
236         style => [@wrapstyle, 'td { font-size: 50% }'],
237         list => [map { tr/01/○●/r =~ s/..\K/ /r } qw(
238                 11000 10011 01110 10010 10000 10110 01011 00101 01100 11010 11110 01001 00111
239                 00110 00011 01101 11101 01010 10100 00001 11100 01111 11001 10111 10101 10001
240                 00100
241         )],
242 },
243 braille => {
244         list => [qw{ ⠁ ⠃ ⠉ ⠙ ⠑ ⠋ ⠛ ⠓ ⠊ ⠚ ⠅ ⠇ ⠍ ⠝ ⠕ ⠏ ⠟ ⠗ ⠎ ⠞ ⠥ ⠧ ⠺ ⠭ ⠽ ⠵ }],
245 },
246 tactile => {
247         title => '5-point Tactile',
248         list => [
249                 map { '<svg width="9" height="12" viewBox="0 0 18 24">'.$_.'</svg>' }
250                 map {
251                         join '', map { sprintf '<circle cx="%d" cy="%d" r="4"/>',
252                                 !$_ ?  9 : $_ & 1 ? 4 : 14,
253                                 !$_ ? 12 : $_ < 3 ? 4 : 20,
254                         } split //
255                 }
256                 qw{
257                         4 234 012 14 0 014 023 12
258                         02 024 0134 23 013 03 01 123
259                         0124 13 04 1 34 0123 134 0234
260                         034 124
261                 }
262         ],
263 },
264 morse => {
265         style => $spacestyle,
266         list => [map {tr/.-/‧‑/r} qw{
267                 .- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. --
268                 -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..
269         }],
270 },
271 tap => {
272         title => 'Tap code',
273         style => \@tapstyle,
274         list => [map { disptap($_) } qw{
275                 11 12 13 14 15 21 22 23  > 24 25 31 32
276                 33 34 35 41 42 43 44 45 51 52 53 54 55
277         }],
278 },
279 shorttap => {
280         title => 'Short Tap',
281         style => \@tapstyle,
282         list => [map { disptap($_) } qw{
283                 11 12 13 14 21 22 23 20 > 31 -13 32 33
284                 30 41 42 -13 43 40 10 51 52 53 50 -31 -40
285         }],
286 },
287 cards => {
288         style => 'td { font-family: Symbola, "DejaVu Sans", serif, sans }',
289         list => [(
290                 map { chr(0x1F0A0 + $_), sprintf('<b>%s</b>', chr(0x1F0B0 + $_)) }  # spades, hearts
291                 1 .. 11, 13, 14  # A 2-10 J Q K
292         ), '', chr(0x1F0CF), chr(0x1F0DF) ],
293 },
294 maritime => {
295         title => 'Maritime flags',
296         style => $spacestyle,
297         list => [
298                 # International Code of Signals, SVG fills
299                 map { !!$_ && '<svg width="20" height="20" viewBox="0 0 30 30">'.s/\n?\t+//gr.'</svg>' }
300                 split /\n\n/, qq{
301                         <path fill="$C{blue}" d="M0,0 h30 l-7.5,15 7.5,15 h-30 z"/>
302                         <path fill="white" d="M0,0 h15 v30 h-15"/>
303
304                         <path fill="$C{red}" d="M0,0 h30 l-7.5,15 7.5,15 h-30 z"/>
305
306                         <path fill="$C{blue}" d="M0,0 h30v30 h-30z"/>
307                         <path fill="white" d="M0,6  h30 v18 h-30" />
308                         <path fill="$C{red}" d="M0,12 h30 v6  h-30" />
309
310                         <path fill="$C{yellow}" d="M0,0 h30v30 h-30z"/>
311                         <path fill="$C{blue}" d="M0,6 h30 v18 h-30"/>
312
313                         <path fill="$C{red}" d="M0,0 h30v30 h-30z"/>
314                         <path fill="$C{blue}" d="M0,0 h30 v15 h-30"/>
315
316                         <path fill="white" d="M0,0 h30v30 h-30z"/>
317                         <path fill="$C{red}" d="M15,0 l15,15 -15,15 -15,-15"/>
318
319                         <path fill="$C{blue}" d="M0,0 h30v30 h-30z"/>
320                         <path fill="$C{yellow}" d="M 0,0 h5 v30 h-5"/>
321                         <path fill="$C{yellow}" d="M10,0 h5 v30 h-5"/>
322                         <path fill="$C{yellow}" d="M20,0 h5 v30 h-5"/>
323
324                         <path fill="$C{red}" d="M0,0 h30v30 h-30z"/>
325                         <path fill="white" d="M0,0 h15 v30 h-15"/>
326
327                         <path fill="$C{yellow}" d="M0,0 h30v30 h-30z"/>
328                         <circle fill="$C{black}" r="7.5" cx="15" cy="15"/>
329
330                         <path fill="$C{blue}" d="M0,0 h30v30 h-30z"/>
331                         <path fill="white" d="M0,10 h30 v10 h-30"/>
332
333                         <path fill="$C{blue}" d="M0,0 h30v30 h-30z"/>
334                         <path fill="$C{yellow}" d="M0,0 h15 v30 h-15"/>
335
336                         <path fill="$C{black}" d="M0,0 h30v30 h-30z"/>
337                         <path fill="$C{yellow}" d="M0,0 h15 v15 h-15 M15,15 h15 v15 h-15"/>
338
339                         <path fill="white" d="M0,0 h30v30 h-30z"/>
340                         <path fill="$C{blue}" d="M4,0h22l-11,11 M4,30h22l-11,-11
341                                 M0,4v22l11,-11 M30,4v22l-11,-11"/>
342
343                         <path fill="white" d="M0,0 h30v30 h-30z"/>
344                         <path fill="$C{blue}" d="
345                                 M0,0     h7.5v7.5h-7.5 m0,7.5h7.5v7.5h-7.5
346                                 m7.5,-15 h7.5v7.5h-7.5 m0,7.5h7.5v7.5h-7.5
347                                 m7.5,-30 h7.5v7.5h-7.5 m0,7.5h7.5v7.5h-7.5
348                                 m7.5,-15 h7.5v7.5h-7.5 m0,7.5h7.5v7.5h-7.5
349                         "/>
350
351                         <path fill="$C{yellow}" d="M0,0 h30v30 h-30z"/>
352                         <path fill="$C{red}" d="M0,0 h30 v30"/>
353
354                         <path fill="$C{blue}" d="M0,0 h30v30 h-30z"/>
355                         <path fill="white" d="M10,10 h10 v10 h-10"/>
356
357                         <path fill="$C{yellow}" d="M0,0 h30v30 h-30z"/>
358
359                         <path fill="$C{red}" d="M0,0 h30v30 h-30z"/>
360                         <path fill="$C{yellow}" d="M12.5,0 v30 h5 v-30"/>
361                         <path fill="$C{yellow}" d="M0,12.5 h30 v5 h-30"/>
362
363                         <path fill="white" d="M0,0 h30v30 h-30z"/>
364                         <path fill="$C{blue}" d="M10,10 h10 v10 h-10"/>
365
366                         <path fill="white" d="M0,0 h30v30 h-30z"/>
367                         <path fill="$C{red}" d="M0,0 h10 v30 h-10"/>
368                         <path fill="$C{blue}" d="M20,0 h10 v30 h-10"/>
369
370                         <path fill="white" d="M0,0 h30v30 h-30z"/>
371                         <path fill="$C{red}" d="M0,0 h15 v15 h-15 M15,15 h15 v15 h-15"/>
372
373                         <path fill="$C{red}" d="M0,0 h30v30 h-30z"/>
374                         <path fill="white" d="M4,0h22l-11,11 M4,30h22l-11,-11
375                                 M0,4v22l11,-11 M30,4v22l-11,-11"/>
376
377                         <path fill="$C{blue}" d="M0,0 h30v30 h-30z"/>
378                         <path fill="white" d="M5,5 h20 v20 h-20"/>
379                         <path fill="$C{red}" d="M10,10 h10 v10 h-10"/>
380
381                         <path fill="white" d="M0,0 h30v30 h-30z"/>
382                         <path fill="$C{blue}" d="M12.5,0 v30 h5 v-30"/>
383                         <path fill="$C{blue}" d="M0,12.5 h30 v5 h-30"/>
384
385                         <path fill="$C{red}" d="M0,0 h30v30 h-30z"/>
386                         <path fill="$C{yellow}" d="M0,0h6l-6,6 M12,0h6l-18,18v-6
387                                 M24,0h6l-30,30v-6 M30,6v6l-18,18h-6 M30,18v6l-6,6h-6"/>
388
389                         <path fill="$C{black}" d="M0,0 h30v30 h-30z"/>
390                         <path fill="$C{blue}" d="M30,0 v31 l-15,-15"/>
391                         <path fill="$C{yellow}" d="M0,0  h31 l-15,15"/>
392                         <path fill="$C{red}" d="M0,30 h31 l-15,-15"/>
393
394
395
396                         <path fill="$C{blue}" d="M0,5 30,15 0,25"/>
397                         <path fill="$C{yellow}" d="M0,9 20,15 0,21"/>
398
399                         <path fill="$C{blue}" d="M0,5 30,15 0,25"/>
400                         <path fill="white" d="M15,10 30,15 15,20"/>
401                 },
402         ],
403 },
404 flag => {
405         title => 'Flag semaphore',
406         list => [
407                 map {
408                         local $_ = $_;
409                         s/[1-4]\K(?=[4-9])/ /; # prevent unwanted vertical crossing
410                         tr/1-9/↙←↖↑↗→↘↓/;
411                         s{(\S)(?=.)}{<span style="position:absolute">$1</span>};
412                         $_
413                 }
414                 qw(
415                         1 2 3 4 5  6 7 21 31 46  14 51 16 17 23
416                         24 25 26 27 34  35 47 56 57 36  67
417                 )
418         ],
419 },
420 chappe => {
421         title => 'Chappe semaphore',
422         list => [
423                 map {
424                         my ($r, $pr, $pl) = split //, $_;
425                         /^\D$/ ? $_ : sprintf(
426                                 join('',
427                                         '<svg width="16" height="20" viewBox="0 0 10 15">',
428                                         '<path d="M5,6 v7"/>',
429                                         '<path d="M0,%s h10 %s" transform="rotate(%d 5 6)"/>',
430                                         '</svg>',
431                                 ),
432                                 ['6', '3v3', '9v-3']->[$pl],
433                                 [ '',  'v3',  'v-3']->[$pr],
434                                 $r * 45,
435                         );
436                 }
437                 # 360° rotation (0-7) and position state (0-2) of left and right bars
438                 qw(
439                   021 121 221 321 421 521 621 721
440                   > 022 122 222 322 011 111 211 311
441                   001 101 201 301 401 501 601 701 020
442                 )
443         ],
444 },
445 prussian => {
446         title => 'Prussian semaphore',
447         list => [
448                 map { /^\D+$/ ? $_ : sprintf
449                         join('',
450                                 '<svg width="10" height="20" viewBox="0 0 8 18">',
451                                 '<path d="M4,1 v18"/>',
452                                 (map {(
453                                         qq(<path d="M0 $_ h4" transform="rotate(%d 4 $_)"/>),
454                                         qq(<path d="M4 $_ h4" transform="rotate(-%d 4 $_)"/>),
455                                 )} 3, 7, 14),
456                                 '</svg>',
457                         ),
458                         map { ($_ - 2) * 45 % 360 } split //, $_
459                 }
460                 # rotation state (0-3) for left and right bar of 3 rows
461                 qw(
462                         003000 000200 203300 000030 033030 000130 000330 032330 > 031330
463                         022020 130120 001320 233010 030210 022310 203001 233001
464                         131001 231301 000202 023302 230003 032003 201003 101003
465                 )
466         ],
467 },
468 code39 => {
469         title => 'Code 39',
470         list => [map { dispbar($_) } qw(
471                 2111121121 1121121121 2121121111 1111221121 2111221111 1121221111
472                 1111122121 2111122111 1121122111 1111222111 2111111221 1121111221
473                 2121111211 1111211221 2111211211 1121211211 1111112221 2111112211
474                 1121112211 1111212211 2211111121 1221111121 2221111111 1211211121
475                 2211211111 1221211111            1221112111 0 1211212111
476         )], # ISO/IEC 16388
477 },
478 code93 => {
479         title => 'Code 93',
480         list => [map { dispbar($_) } qw(
481                 211113 211212 211311 221112 221211 231111 112113 112212 112311 122112
482                 132111 111123 111222 111321 121122 131121 212112 212211 211122 211221
483                 221121 222111 112122 112221 122121 123111        311211 0 111141
484         )],
485 },
486 code128 => {
487         title => 'Code 128',
488         list => [map { dispbar($_) } qw(
489                 111323 131123 131321 112313 132113 132311 211313 231113 231311 112133
490                 112331 132131 113123 113321 133121 313121 211331 231131 213113 213311
491                 213131 311123 311321 331121 312113 312311      212222 0 211412 23311120
492         )],
493 },
494 rm4scc => {
495         title => '<abbr title="Royal Mail 4-State Customer Code">RM4SCC</abbr>',
496         list => [
497                 map {
498                         my $len = length $_;
499                         !$len ? '' : sprintf(
500                                 '<svg width="%d" height="20" viewBox="0 0 %d 6">'
501                                 . '<path d="M1%s"/></svg>',
502                                 $len * 5, $len * 2,
503                                 join ' m2',
504                                 map { sprintf ',%dv%dm0,-%d',
505                                         ($_ & 1 ? 0 : 2),  2 + ($_ & 2) + ($_ & 1) * 2,
506                                         ($_ & 1 ? 0 : 2) + 2 + ($_ & 2) + ($_ & 1) * 2,
507                                 }
508                                 split //
509                         );
510                 }
511                 qw(
512                                                                 2121 2301
513                         0132 0312 0330 2112 2130 2310
514                         1023 1203 1221 3003 3021 3201
515                         1032 1212 1230 3012 3030 3210
516                         1122 1302 1320 3102 3120 3300
517                         0033
518                 ), # 0 for space
519                 '', 1, 3  # start/end
520         ],
521 },
522 rgbmap => {
523         title => 'RGBmap',
524         style => [
525                 'svg { isolation: isolate }',
526                 'svg circle { mix-blend-mode: screen }',
527                 '.sample { background: black }',
528         ],
529         list => [
530                 map { disphues($_, [0, 240, 120], 1) } # Red, Blue, Green
531                 @hueorder[23..25,20..22, 12, 6..11,0..5, 16..18, 13..15, 19, 26],
532         ],
533 },
534 cmymap => {
535         title => 'CMYmap',
536         style => [
537                 'svg { isolation: isolate }',  # mix on white
538                 'svg circle { mix-blend-mode: multiply }',
539                 '.sample { background: white }',
540         ],
541         list => [
542                 map { disphues($_, [180, 60, 300]) } # Cyan, Yellow, Magenta
543 #               @hueorder[13..18, 19, 0..11, 20..25, 12, 26],
544                 @hueletters
545         ],
546 },
547 dni => {
548         title => "D'ni",
549         style => [
550                 'svg { border: 1px solid currentColor }',
551                 '.sample span + span svg { border-left: 0 }',
552         ],
553         list => [
554                 map {
555                         state $v = [
556                                 '',
557                                 'M0,4 8,4',
558                                 'M0,8 Q4,4 8,8',
559                                 'M0,4 4,8 8,4',
560                                 'M2,0 2,4 8,4',
561                                 'M0,0 8,8 M0,8 8,0', # cross
562                                 'M3.5,4 h1', # dot
563                         ];
564                         state $h = [
565                                 '',
566                                 'M4,0 4,8',
567                                 'M0,0 Q4,4 0,8',
568                                 'M4,-.5 0,4 4,8.5',
569                                 'M4,8 4,2 8,2',
570                         ];
571                         sprintf(
572                                 '<svg width="16" height="16" viewBox="0 0 8 8"><path d="%s"/></svg>',
573                                 $h->[$_ % 5] . $v->[$_ / 5] || $v->[6],
574                         );
575                 } 0 .. 5*5
576         ],
577 },
578 pigpen => {
579         style => [
580                 'svg path { stroke-linecap: square }',
581                 '.sample svg { margin-right: 0.1em }',
582         ],
583         list => [
584                 map {
585                         qq(<svg width="12" height="12" viewBox="-.5 -.5 7 7">$_</svg>)
586                 }
587                 map {
588                         local $_ = $_;
589                         s/^H/mX,0/ or s/^V/m0,X/ or s/^/m0,0/;
590                         s/[hv]\K|X/6/g;
591                         s/(?:v|,[^0]).*?v\K/-/;
592                         s/(?:h|m[^0]).*?h\K/-/;
593                         m/h/ or s/v/l3,/g;
594                         m/v/ or s/h([^h]*)/l$1,3/g;
595                         my $dot = s/\.// && qq(<circle cx="3" cy="3" r="1"/>);
596                         qq(<path d="$_"/>$dot)
597                 }
598                 qw(
599                         Hvh  vhv  vh  hvh  vhvh  Hhvh  hv  Vvhv  Hhv
600                         Hvh. vhv. vh. hvh. vhvh. Hhvh. hv. Vvhv. Hhv.
601                         vv  hh  Hhh  Vvv
602                         vv. hh. Hhh. Vvv.
603                 ),
604         ],
605 },
606 nyctographs => {
607         style => [
608                 'svg path { stroke-linecap: round; stroke-linejoin: round }',
609                 '.sample svg {
610                         background: rgba(0,0,0, .1);
611                         padding: 0.1em;
612                         margin-right: 0.2em;
613                 }',
614         ],
615         list => [
616                 map { s/M[\d,\hM]+(?=[M"])//gr }  # clean up superfluous moves
617                 map { sprintf
618                         '<svg width="14" height="14" viewBox="-.5 -.5 5 5">'
619                         . '<path d="M0,0%s %s4,0 %s4,4 %s0,4 %s0,0"/></svg>',
620                         'h.5v.5h-.5v-.5',  # start anchor
621                         map { ['M', 'h0M', 'L']->[$_] }
622                         split //
623                 }
624                 # draw style (0=empty, 1=dot, 2=line connect) to right, down, left, up
625                 qw(
626                         0010 0112 2022 2220 2000 2012 0122 0202 0020 0220 0012 0022 2202
627                         0222 2222 0102 0200 2201 2002 2200 0100 0110 0120 2001 2010 2020
628                         0000
629                 ),
630         ],
631 },
632 chromacons => {
633 #       style => '.sample { word-break: break-all }',
634         list => [
635                 # Colour Alphabet by Paul Green-Armytage (2010)
636                 map {
637                         sprintf('<span%s>%s</span>',
638                                 !!$_ && sprintf(' style="background:#%s" title="%s"', split /:/),
639                                 chr(8195) . (!$_ && chr(8203)) # em space (plus zwsp for spaces)
640                         );
641                 }
642                 qw{
643                         F0A3FF:Amethyst 0075DC:Blue     993F00:Caramel  4C005C:Damson
644                         191919:Ebony    005C31:Forest   2BCE48:Green    FFCC99:Honeydew
645                         808080:Iron     94FFB5:Jade     8F7C00:Khaki    9DCC00:Lime
646                         C20088:Mallow   003380:Navy     FFA405:Orpiment FFA8BB:Pink
647                         426600:Quagmire FF0010:Red      5EF1F2:Sky      00998F:Turquoise
648                         E0FF66:Uranium  740AFF:Violet   990000:Wine     FFFF80:Xanthin
649                         FFFF00:Yellow   FF5005:Zinnia   0
650                 }
651         ],
652 },
653 );