+sub dispdomino {
+ my $code = shift;
+ my ($prefix, @dots) = $code =~ m/\A(-?)(\d)(\d)/ or return $code;
+ # unicode glyph alternative as DOMINO TILE HORIZONTAL-0a-0b
+ return $prefix . chr(0x1F031 + ($dots[0] * 7) + $dots[1]);
+}
+
+sub dispdash {
+ my $code = shift;
+ my ($prefix, @dots) = $code =~ m/\A(-?)(\d)(\d)/ or return $code;
+ my ($w, $h) = (12, 9);
+ my @w = map { $w / ($_ || 1) } @dots;
+ return sprintf(
+ '<svg height="20" viewBox="-.5 -.5 %s %s">'
+ . '<path d="%s" /></svg>',
+ $w + 1, $h + 1, join(' ',
+ "m0,$h l+$w[0],-$h" x $dots[0], # slashes
+ "m0,$h l-$w[1],-$h" x $dots[1], # backslashes
+ )
+ );
+}
+
+sub dispblock {
+ my $code = shift;
+ my ($prefix, $shape, $rotate) = $code =~ m/\A(-?)(\w)(\d?)/
+ or return $code;
+ my %path = (
+ S => 'm0,1h1v-1h1',
+ Z => 'm0,0h1v1h1',
+ L => 'm0,0v2h1',
+ v => 'm0,0v1h1',
+ J => 'm1,0v2h-1',
+ T => 'm0,0h2.5h-1.5v1',
+ O => 'm0,0h1v1h-1',
+ I => 'm0,1h3',
+ i => 'm0,1h2',
+ o => 'm0,1h1',
+ );
+ my %col = qw(
+ S 120 Z 0 J 240 L 30 T 300 O 60 I 180
+ v 45,50% i 165,50% o 165,0%
+ );
+ s/\z(?<!%)/,100%/ for values %col;
+ my @gaps = (grep $_,
+ $code =~ /[Ii]$|T[23]|L3?$|S1|Z$|J1|v3?$/ ? 'gapl1' : (),
+ $code =~ /T$|L2|Z$/ ? 'gapr1' : (),
+ );
+ return sprintf(
+ '<svg height="24" viewBox="-.5 -.5 %s 4"%s>'
+ . '<path d="%s" stroke="%s" fill="none"%s /></svg>',
+ $code eq 'I' ? 4 : $code =~ /T3|[LJO]$|[Iio]1/ ? 2 : 3,
+ @gaps ? qq( class="@gaps") : '',
+ $path{$shape}, "hsl($col{$shape},50%)", join('',
+ $rotate && sprintf(' transform="rotate(%s 1 1)"', $rotate * 90),
+ $prefix && ' style="opacity:.5"',
+ ),
+ );
+}
+