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