├── CHANGELOG
├── MANIFEST
├── Makefile
├── Makefile.PL
├── README.md
├── README.pod
├── Term-Graille-0.10.tar.gz
├── examples
├── animations
│ ├── cheetah
│ │ ├── cheetah1.png
│ │ ├── cheetah2.png
│ │ ├── cheetah3.png
│ │ ├── cheetah4.png
│ │ ├── cheetah5.png
│ │ ├── cheetah6.png
│ │ ├── cheetah7.png
│ │ └── cheetah8.png
│ ├── chimp
│ │ ├── chimp1.png
│ │ ├── chimp10.png
│ │ ├── chimp2.png
│ │ ├── chimp3.png
│ │ ├── chimp4.png
│ │ ├── chimp5.png
│ │ ├── chimp6.png
│ │ ├── chimp7.png
│ │ ├── chimp8.png
│ │ └── chimp9.png
│ └── dragon.png
├── breakout.pl
├── convert2grl.pl
├── demo.pl
├── editor.pl
├── fontDemo.pl
├── fonts
│ ├── Anvil Alternate.grf
│ ├── Area51 Overwide.grf
│ ├── Area51 Serif Bold.grf
│ ├── Area51.grf
│ ├── Cinema Bold.grf
│ ├── Computer.grf
│ ├── Coolant.grf
│ ├── Everest Bold.grf
│ ├── Everest Condensed SemiBold.grf
│ ├── Everest Condensed.grf
│ ├── Everest.grf
│ ├── Mutual.grf
│ ├── Reflections Dark.grf
│ ├── Reflections.grf
│ ├── Tentacle Bold.grf
│ ├── Tentacle.grf
│ ├── ZX Times.grf
│ ├── ZX Venice.grf
│ ├── asm2grf.pl
│ └── font2grf.pl
├── graillepiano.pl
├── image2grl.pl
├── invaders.pl
├── lineDemo.pl
├── perl2.grl
├── perl2.jpg
├── pulseaudio.pl
├── save.grl
├── spritemaker.pl
├── sprites
│ ├── File.spr
│ ├── Hash.spr
│ ├── Launcher.spr
│ ├── bar.spr
│ ├── boat.spr
│ ├── cow.spr
│ ├── crwoned.spr
│ ├── default.spb
│ ├── die.spr
│ ├── dummy.spb
│ ├── empty.spr
│ ├── forbidden.spr
│ ├── game1.spb
│ ├── help.spr
│ ├── info.spr
│ ├── m.spr
│ ├── man1.spr
│ ├── manhatwalk1.spr
│ ├── manhatwalk2.spr
│ ├── manhatwalk3.spr
│ ├── manhatwalk4.spr
│ ├── mm.spr
│ ├── oyster.spr
│ ├── perly.spr
│ ├── photos.spr
│ ├── rocket.spr
│ ├── spiral.spr
│ ├── testmessage.spb
│ ├── warn.spr
│ └── warn2.spr
├── surmaphoto.png
├── testanimate.pl
├── turtle.pl
└── visualiser.pl
├── lib
├── Algorithm
│ └── Line
│ │ └── Bresenham.pm
└── Term
│ ├── Graille.pm
│ └── Graille
│ ├── Audio.pm
│ ├── Chart.pm
│ ├── Dialog.pm
│ ├── Font.pm
│ ├── Interact.pm
│ ├── Menu.pm
│ ├── Selector.pm
│ ├── Sprite.pm
│ └── Textarea.pm
├── old_files
└── Readme.md
└── t
└── 1.t
/CHANGELOG:
--------------------------------------------------------------------------------
1 | CHANGELOG
2 | Term::Graille - Graphical Display in the terminal using UTF8 Braille characters
3 |
4 | 0.10
5 | -Term::Graille Multicharacter scrolling of canvas
6 | -Term::Graille::Interact user interaction module added
7 | -Term::Graille::Menu now used Interact; Term::Graille::IO deprecated to be removed in 0.11
8 | -Term::Graille::Dialog added
9 | -Term::Graille::Selector with limited file selecting capability,
10 | -Term::Graille::Textarea with scrolling editable text
11 | -Term::Graille::Audio added
12 | - examples/editor.pl a terminal editor with a hierachical menu
13 | - examples/piano.pl testing Audio Module
14 |
15 |
16 |
17 | 0.09
18 | -starting Charting module
19 | -Term::Graille::IO user interaction module
20 | -Term::Graille::Menu A modal drop down menu for user interaction
21 | -prototype sprite editor started
22 |
23 | 0.08
24 | - minor bug fixes
25 | - Variable thickness lines added (requires Algorithm::Line::Bresenham 0.151)
26 |
27 | 0.07
28 | - Adds textAt () function allowing heterogenous content on the canvas
29 | - Adds colour to pixel and text and turtle graphics on the $canvas
30 | - Adds a Graille::Font module that imports converts and loads and saves fonts
31 | - loadGrf() moved to the new separate Graille::Font module
32 |
33 | 0.06
34 | - Added print colour("reset") as suggested by https://github.com/jwrightecs
35 | - Added block2braille (convert 2d binary data to 2d braille)
36 | - Added blockBlit (blit 2d blocks of characters)
37 | - Added loadGrf (load blocks e.g. fonts)
38 | - Added importCanvas and exportCanvas (load/save canvas from/to file)
39 | - Added font2grf to examples folder (convert fonts from https://damieng.com/typography/zx-origins to grf)
40 | - Added image2grl (convert image to file loadable by Term::Graille *Needs Image::Magick)
41 | - Added testanimate (convert a folder containingg frames into Graille Animation *Needs Image::Magick)
42 |
43 | 0.05
44 | Failing CpanTesters
45 | - Error in 1.t corected
46 | - Added Import and export images
47 | - Created an image converter (Depends on Image::Magick)
48 |
49 | 0.04
50 | Corrected error hightlighted by https://old.reddit.com/user/tarje
51 | - Perl Version set at v5.10.0
52 | - License file removed
53 |
54 | 0.03 June 2022
55 | First version unploaded to CPAN
56 |
57 | 0.02 June 2022
58 | First version converted form Drawille
59 |
--------------------------------------------------------------------------------
/MANIFEST:
--------------------------------------------------------------------------------
1 | CHANGELOG
2 | examples/animations/cheetah/cheetah1.png
3 | examples/animations/cheetah/cheetah2.png
4 | examples/animations/cheetah/cheetah3.png
5 | examples/animations/cheetah/cheetah4.png
6 | examples/animations/cheetah/cheetah5.png
7 | examples/animations/cheetah/cheetah6.png
8 | examples/animations/cheetah/cheetah7.png
9 | examples/animations/cheetah/cheetah8.png
10 | examples/animations/dragon.png
11 | examples/demo.pl
12 | examples/editor.pl
13 | examples/fontDemo.pl
14 | 'examples/fonts/Anvil Alternate.grf'
15 | 'examples/fonts/Area51 Overwide.grf'
16 | 'examples/fonts/Area51 Serif Bold.grf'
17 | examples/fonts/Area51.grf
18 | examples/fonts/asm2grf.pl
19 | 'examples/fonts/Cinema Bold.grf'
20 | examples/fonts/Computer.grf
21 | examples/fonts/Coolant.grf
22 | 'examples/fonts/Everest Bold.grf'
23 | 'examples/fonts/Everest Condensed SemiBold.grf'
24 | 'examples/fonts/Everest Condensed.grf'
25 | examples/fonts/Everest.grf
26 | examples/fonts/Mutual.grf
27 | 'examples/fonts/Reflections Dark.grf'
28 | examples/fonts/Reflections.grf
29 | 'examples/fonts/Tentacle Bold.grf'
30 | examples/fonts/Tentacle.grf
31 | 'examples/fonts/ZX Times.grf'
32 | 'examples/fonts/ZX Venice.grf'
33 | examples/graillepiano.pl
34 | examples/image2grl.pl
35 | examples/lineDemo.pl
36 | examples/perl2.grl
37 | examples/perl2.jpg
38 | examples/pulseaudio.pl
39 | examples/spriteEditor.pl
40 | examples/sprites/bar.spr
41 | examples/sprites/boat.spr
42 | examples/sprites/cow.spr
43 | examples/sprites/crwoned.spr
44 | examples/sprites/default.spb
45 | examples/sprites/die.spr
46 | examples/sprites/dummy.spb
47 | examples/sprites/empty.spr
48 | examples/sprites/File.spr
49 | examples/sprites/forbidden.spr
50 | examples/sprites/game1.spb
51 | examples/sprites/Hash.spr
52 | examples/sprites/help.spr
53 | examples/sprites/info.spr
54 | examples/sprites/Launcher.spr
55 | examples/sprites/m.spr
56 | examples/sprites/man1.spr
57 | examples/sprites/manhatwalk1.spr
58 | examples/sprites/manhatwalk2.spr
59 | examples/sprites/manhatwalk3.spr
60 | examples/sprites/manhatwalk4.spr
61 | examples/sprites/mm.spr
62 | examples/sprites/oyster.spr
63 | examples/sprites/perly.spr
64 | examples/sprites/photos.spr
65 | examples/sprites/rocket.spr
66 | examples/sprites/spiral.spr
67 | examples/sprites/testmessage.spb
68 | examples/sprites/warn.spr
69 | examples/sprites/warn2.spr
70 | examples/testanimate.pl
71 | examples/testBeep1.pl
72 | examples/visualiser.pl
73 | lib/Term/Graille.pm
74 | lib/Term/Graille/Audio.pm
75 | lib/Term/Graille/Chart.pm
76 | lib/Term/Graille/Dialog.pm
77 | lib/Term/Graille/Font.pm
78 | lib/Term/Graille/Interact.pm
79 | lib/Term/Graille/Menu.pm
80 | lib/Term/Graille/Selector.pm
81 | lib/Term/Graille/Textarea.pm
82 | Makefile.PL
83 | MANIFEST This list of files
84 | t/1.t
85 |
--------------------------------------------------------------------------------
/Makefile.PL:
--------------------------------------------------------------------------------
1 | use 5.008004;
2 | use ExtUtils::MakeMaker;
3 |
4 | WriteMakefile(
5 | NAME => 'Term::Graille',
6 | VERSION_FROM => 'lib/Term/Graille.pm',
7 | ABSTRACT_FROM => 'lib/Term/Graille.pm',
8 | AUTHOR => 'Saif Ahmed',
9 | LICENSE => 'Artistic',
10 | MIN_PERL_VERSION => 'v5.10.0',
11 | PREREQ_PM => {
12 | 'strict' => 0,
13 | 'warnings' => 0,
14 | 'Algorithm::Line::Bresenham' =>'0.151',
15 | 'Time::HiRes' => 0,
16 | 'Storable' =>0,
17 | 'Term::ReadKey'=>0,
18 | 'Data::Dumper' =>0,
19 | },
20 | (eval { ExtUtils::MakeMaker->VERSION(6.46) } ? (META_MERGE => {
21 | 'meta-spec' => { version => 2 },
22 | resources => {
23 | repository => {
24 | type => 'git',
25 | url => 'https://github.com/saiftynet/Term-Graille.git',
26 | web => 'https://github.com/saiftynet/Term-Graille',
27 | },
28 | }})
29 | : ()
30 | ),
31 | );
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Term-Graille
2 | Braille Characters for Terminal Graphical Applications
3 |
4 | 
5 |
6 |
7 | Drawille is a method of using Braille characters as a mechanism for graphical display in a terminal. Ports of the original by [asciimoo](https://github.com/asciimoo/drawille) exist inmultiple other languages including [Perl](https://metacpan.org/dist/Term-Drawille), [Java](https://github.com/null93/drawille), [Rust](https://crates.io/crates/drawille), [NodeJS](https://www.npmjs.com/package/drawille), and others. The [Perl version](https://github.com/hoelzro/term-drawille) was initially produced by [@hoelzro](https://hoelz.ro/), but not much changed since about 8 years ago.
8 |
9 | This is another Perl version, targeting ANSI compatible consoles. It delivers significantly higher performance and extends Term::Drawille by including features like:-
10 |
11 | * Integrated Turtle-like drawing
12 | * Built-in drawing primitives including line and curve, circle, ellipse, polyline more on the way
13 | * Scrolling with or without wrapping
14 | * Some frame border manipulation
15 | * Text overlays
16 |
17 | Tools in other languages have been used in publications, system monitoring tools and for games. Term::Graille allows Perl programmers access to a expanding set of features for developing simple general purpose graphics, graphing applications, games etc from the console.
18 |
19 | Associated with Term::Graille is Algorithm::Line::Bresenham. The plotting primitives in the latter are used in Graille
20 |
21 | Features to be included are colors, sprites, maps, and more on user request. For more information see the [wiki](https://github.com/saiftynet/Term-Graille/wiki)
22 |
23 | Version 0.06
24 |
25 | ## Importing images
26 |
27 | Graille does not have the resolution for fancy graphics. Having said that, images converted into mono with appropriate dithering can be surpisingly recognisable at the low resolution oferred. The `image2grl.pl` script in the examples folder uses Image Magick to perform the transromation down to a Graille canvas's resolutions, and plotted on to the canvas pixel by pixel. Graille offers the option to import or export `.grl` files.
28 |
29 | 
30 |
31 | ## Animation Demo
32 |
33 | The animation demo uses Image::Magick to convert a folder of frames into monochrome images, which are then converted to bitmap plots on a canvas. These bitmap plots are displayed sequentially creating an animation.
34 |
35 | This is an animation derived from a sprite sheet at [Adobe stock photos](https://stock.adobe.com/uk/images/cheetah-run-cycle-animation-sprite-sheet-silhouette-animation-frames-running-chasing/183196184) which do a 30 day free trial.
36 |
37 | 
38 |
39 | ## Fonts
40 |
41 | In the initial demo above a Turtle script was used to produce a drawing of text. This is rather combersome. Fortunately bitmap fonts exist, and can be easily converted to Braille. [DamienG](https://damieng.com/typography/zx-origins/) has produced a series of 8X8 fonts which can translated into 4X2 braille characters. The fonts are consistently coded, so `font2grf.pl` in the example folders converts the Z80 assembly data into `.grf` files for importing into Graille. Fonts are not the only thing that can be transformed, and one imagines potential for sprites or tilemaps to be similarly encoded.
42 |
43 | 
44 |
45 | ## Variable thickness Lines
46 |
47 |
48 | [Herbert Breuning](https://github.com/lichtkind) had made this suggestion. There are many examples of thick line algorithms on the net. [Alan Murphy](http://homepages.enterprise.net/murphy/thickline/index.html) gives the classic version, which has been [improved](http://kt8216.unixcab.org/murphy/index.html) and it is this code that has been ported to Perl and used in Algorth::Line::Bresenham v0.151. INtegrating these into Graille was in v0.08.
49 |
50 | 
51 |
52 | ## Drop down menu
53 |
54 | In developing a sprite editor on the console, mulitiple user interactions were required. Interactive graphical menus are not easy in the console. Tickit and Term::Menus are powerful modules. Term::Graille::Menu goes for simplicity rather than power. This comes in v 0.09. The sprite editor itself is not complete yet, but would be very cumbersome without something to aid visual development with multiple options and features.Term::Graille::Menu makes it very simple to create menus for ANSI terminals.
55 |
56 | The menu in this image is created using:
57 | ```
58 | my $menu=new Term::Graille::Menu(
59 | menu=>[["File","New Sprite Bank","Save Sprite Bank","Load Sprite Bank","Quit"],
60 | ["Sprites","New Sprite","Delete Sprite","Import Sprite","Export Sprite"],
61 | ["Edit","Clear","MirrorX","MirrorY","Rotate+","Rotate-",
62 | ["Reformat","2x4","4x4"],
63 | ["Scroll","left","right","up","down"]],
64 | "About"],
65 | redraw=>\&main::refreshScreen,
66 | callback=>\&main::menuActions,
67 | );
68 |
69 | ```
70 |
71 |
72 | 
73 |
74 | ## Audio
75 |
76 | A component of interaction often neglected in terminal aplications is sound. Sound also adds an extra dimension to games. Term::Graille::Audio attempts to add sound with the least possible dependencies. It curently depends on pulseaudio in Linux to create a /dev/dsp (and Win32::Sound on Windows although this is as yet untested). At its simplest Audio can play a sound from its built-in sound sample set which it can autogenerate, although this is customisable and may include a speech synthesizer module based on [SP0256 allophones](https://github.com/saiftynet/SP0256).
77 |
78 | ```
79 | use Term::Graille::Audio;
80 |
81 | my $beep=Term::Graille::Audio->new(); # TERM::Graille's Audio module
82 | $beep->playSound(undef, "A#1");
83 | ```
84 |
85 |
86 | [piano.webm](https://user-images.githubusercontent.com/34284663/205505757-3207fa25-c1be-492c-b353-73cb365349f2.webm)
87 |
88 |
89 | ## Games
90 |
91 | One of objective of combining in interactivity with graphics and sound is the cfreation of Games for the [PerlaySation Games Console](https://github.com/saiftynet/PerlayStation)
92 |
93 | 
94 |
95 | [breakout.webm](https://user-images.githubusercontent.com/34284663/211404936-fb79f676-a505-413e-bad0-d1ac28c7f7d3.webm)
96 |
97 |
--------------------------------------------------------------------------------
/README.pod:
--------------------------------------------------------------------------------
1 | =head1 NAME
2 |
3 | Term::Graille - Graphical Display in the terminal using UTF8 Braille characters
4 |
5 | =head1 SYNOPSIS
6 |
7 | my $canvas = Term::Graille->new(
8 | width => 72, # pixel width
9 | height => 64, # pixel height
10 | top=>3, # row position in terminal (optional,defaults to 1)
11 | left=>10, # column position (optional,defaults to 1)
12 | borderStyle => "double", #
13 | );
14 |
15 | =head1 DESCRIPTION
16 |
17 | Inspired by Drawille by asciimoo, which has many variants (including
18 | a perl variant Term::Drawille by RHOELZ), this is a clone with a few
19 | extras. The goal is to achieve performance and features. with built-in
20 | turtle-like graphics, line and curve drawing (Algorithm::Line::Bresenham),
21 | scrolling, border setting, and more in development.
22 |
23 | =begin html
24 |
25 |
26 |
27 | =end html
28 |
29 |
30 | =head1 FUNCTIONS
31 |
32 |
33 | =cut
34 |
35 | =head3 Cnew(%params)>
36 |
37 | Creates a new canavas; params are
38 | C The pixel width, required C the pixel height, required,
39 | C terminal row (optional,default 1) C terminal column (
40 | optional,default 1) C border type (optional,one of 'simple',
41 | 'double', 'thin', 'thick' or 'shadow') C border colour (
42 | optional), C Title text for top border,(optional) C
43 | Title colour (optional)
44 |
45 |
46 | =cut
47 |
48 | =head3 C<$canvas-Edraw()> , C<$canvas-Edraw($row, $column)>
49 |
50 | Draws the canvas to the terminal window. Optional row and column
51 | parameters may be passed to position the displayed canvas. If
52 | borderStyle is specified, the border is drawn, If title is specified
53 | this is added to the top border
54 |
55 |
56 | =cut
57 |
58 | =head3 C<$canvas-Eas_string()>
59 |
60 | Returns the string containing the canvas of utf8 braille symbols, rows
61 | being separated by newline.
62 |
63 |
64 | =cut
65 |
66 | =head3 C<$canvas-Eset($x,$y,$pixelValue)>
67 |
68 | Sets a particular pixel on (default if C<$pixelValue> not sent) or off.
69 |
70 |
71 | =cut
72 |
73 | =head3 C<$canvas-Eunset($x,$y)>
74 |
75 | Sets the pixel value at C<$x,$y> to blank
76 |
77 |
78 | =cut
79 |
80 | =head3 C<$canvas-Epixel($x,$y)>
81 |
82 | Gets the pixel value at C<$x,$y>
83 |
84 |
85 | =cut
86 |
87 | =head3 C<$canvas-Eclear()>
88 |
89 | Re-initialises the canvas with blank braille characters
90 |
91 |
92 | =cut
93 |
94 | =head3 C<$canvas-Eline($x1,$y1,$x2,$y2,$value)>
95 |
96 | Uses Algorithm::Line::Bresenham to draw a line from C<$x1,$y1> to C<$x2,$y2>.
97 | The optional value C<$value> sets or unsets the pixels. If C<$value> is a
98 | valid colour (see below) the line will be drawn with that colour.
99 |
100 |
101 | =cut
102 |
103 | =head3 C<$canvas-Ecircle($x1,$y1,$radius,$value)>
104 |
105 | Uses Algorithm::Line::Bresenham to draw a circle centered at C<$x1,$y1>
106 | with radius C<$radius> to C<$x2,$y2>.
107 | The optional value C<$value> sets or unsets the pixels. If C<$value> is a
108 | valid colour (see below) the line will be drawn with that colour.
109 |
110 |
111 | =cut
112 |
113 | =head3 C<$canvas-Eellipse_rect($x1,$y1,$x2,$y2,$value)>
114 |
115 | Uses Algorithm::Line::Bresenham to draw a rectangular ellipse, (an
116 | ellipse bounded by a rectangle defined by C<$x1,$y1,$x2,$y2>).
117 | The optional value C<$value> sets or unsets the pixels. If C<$value> is a
118 | valid colour (see below) the line will be drawn with that colour.
119 |
120 |
121 | =cut
122 |
123 | =head3 C<$canvas-Equad_bezier($x1,$y1,$x2,$y2,$x3,$y3,$value)>
124 |
125 | Uses Algorithm::Line::Bresenham to draw a quadratic bezier, defined by
126 | end points C<$x1,$y1,$x3,$y3>) and control point C<$x2,$y2>.
127 | The optional value C<$value> sets or unsets the pixels. If C<$value> is a
128 | valid colour (see below) the line will be drawn with that colour.
129 |
130 |
131 | =cut
132 |
133 | =head3 C<$canvas-Epolyline($x1,$y1,....,$xn,$yn,$value)>
134 |
135 | Uses Algorithm::Line::Bresenham to draw a poly line, form a
136 | sequences of points.
137 | The optional value C<$value> sets or unsets the pixels. If C<$value> is a
138 | valid colour (see below) the line will be drawn with that colour.
139 |
140 |
141 | =cut
142 |
143 | =head2 Character Level Functions;
144 |
145 | =head3 C<$canvas-Escroll($direction,$wrap)>
146 |
147 | Scrolls in C<$direction>. $direction may be
148 | "l", "left", "r","right", "u","up","d", "down".
149 | Beacuse of the use of Braille characters, up/down scrolling is 4 pixels
150 | at a time, whereas left right scrolling is 2 pixels at a time. If
151 | C<$wrap> is a true value, the screen wraps around.
152 |
153 |
154 | =cut
155 |
156 | =head3 C<$canvas-EblockBlit($block,$gridX, $gridY)>
157 |
158 | Allows blitting a 2d arrays to a grid location in the canvas. Useful for
159 | printing using a Graille font.
160 |
161 |
162 | =cut
163 |
164 | =head3 C<$canvas-EexportCanvas($filename)> , C<$canvas-EimportCanvas($filename,[$toBuffer])>
165 |
166 | This allows the loading and unloading of a canvas from a file. There is
167 | no checking of the dimension of the canvas being imported at the moment.
168 | Import can be direct to the canvas, the function return the loaded data
169 | as an ArrayRef, the optional c<$toBuffer> parameter, if true prevents
170 | loading the data onto the canvas.
171 |
172 |
173 | =cut
174 |
175 | =head3 C<$canvas-EtextAt($x,$y,$text,$fmt)>
176 |
177 | Printing text on the C<$canvas>. This is different fromthe exported
178 | C function. the characters are printed on the C<$canvas>
179 | and may be scrolled with the canvas and will overwrite or be over written
180 | othe $canvas drawing actions. The optional C<$fmt> allows the setting of colour;
181 |
182 |
183 | =cut
184 |
185 | =head2 Enhancements
186 |
187 | =head3 C<$canvas-Elogo($script)>
188 |
189 | Interface to Graille's built in Turtle interpreter.
190 | A string is taken and split by senicolons or newlines into instructions.
191 | The instructions are trimmed, and split by the first space character into
192 | command and parameters. Very simple in other words. No syntax checking
193 | is done
194 |
195 | C<"fd distance"> pen moves forward a certain distance.
196 | C<"lt angle">, C<"rt angle"> turns left or right.
197 | C<"bk distance"> pen moves back a certain distance.
198 | C<"pu">, C<"pd"> Pen is up or down, up means no drawing takes place,
199 | and down means the turtle draws as it moves.
200 | C<"dir"> set the direction at a specific angle in dgrees,
201 | with 0 being directly left.
202 | C<"mv">moves pen to specific coordinates without drawing.
203 | C<"ce"> centers the turtle in the middle of a canvas
204 | C<"sp"> allows animated drawing by specifiying the the number
205 | of centiseconds between instructions
206 |
207 |
208 | =cut
209 |
210 | =head3 Exported Routines
211 |
212 | Graille exports some functions for additional console graphical manipulation
213 | This includes drawing of borders, printing characters at specific locations
214 | in the terminal window, and colouring the characters, clearing the screen, etc.
215 |
216 | printAt($row,$column,@textRows);
217 |
218 | Prints text sent as a scalar, a list of scalars or a reference to list
219 | of scalars, at a specific location on the screen. Lists are printed
220 | from the same column but increasing row positions.
221 |
222 | border($top,$left,$bottom,$right,$style,$colour);
223 |
224 | Draws a border box.
225 |
226 | paint($txt,$fmt)
227 |
228 | Paints text the colour and background specified, $text may be a string, or ref
229 | to a list of strings. This is combined with C abouve
230 |
231 | clearScreen()
232 |
233 | Guess what? clears the enire screen. This is different from C<$canvas-Eclear()>
234 | which clears the Graille canvas.
235 |
236 |
237 | block2braille($block)
238 |
239 | Given a block of binary data (a 2D Array ref of 8-bit data), return a
240 | corresponding 2d Array ref of braille blocks. This is handy to convert,
241 | say, binary font data tinto Braille blocks for blittting into the canvas;
242 |
243 | pixelAt($block,$px,$py)
244 |
245 | Given a binary block of data e.g. a font or a sprite offered as a 2D Array ref
246 | find the pixel value at a certain coordinate in that block.
247 |
248 |
249 |
250 | =cut
251 |
252 | =head1 AUTHOR
253 |
254 | Saif Ahmed
255 |
256 | =head1 LICENSE
257 |
258 | Artistic
259 |
260 | =head1 INSTALLATION
261 |
262 |
263 |
264 | Manual install:
265 |
266 | $ perl Makefile.PL
267 | $ make
268 | $ make install
269 |
270 |
271 | =cut
272 |
273 |
--------------------------------------------------------------------------------
/Term-Graille-0.10.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/Term-Graille-0.10.tar.gz
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah1.png
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah2.png
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah3.png
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah4.png
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah5.png
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah6.png
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah7.png
--------------------------------------------------------------------------------
/examples/animations/cheetah/cheetah8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/cheetah/cheetah8.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp1.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp10.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp2.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp3.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp4.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp5.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp6.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp7.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp8.png
--------------------------------------------------------------------------------
/examples/animations/chimp/chimp9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/chimp/chimp9.png
--------------------------------------------------------------------------------
/examples/animations/dragon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/animations/dragon.png
--------------------------------------------------------------------------------
/examples/breakout.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use utf8;
4 | use lib "../lib";
5 | use open ":std", ":encoding(UTF-8)";
6 | use Term::Graille qw/colour paint printAt cursorAt clearScreen border blockBlit block2braille pixelAt/;
7 | use Term::Graille::Interact ;
8 | use Term::Graille::Sprite;
9 | use Term::Graille::Audio;
10 | use Term::Graille::Font qw/loadGrf fontWrite/;
11 | use Time::HiRes qw/sleep/;
12 |
13 | my $beep=Term::Graille::Audio->new(); # TERM::Graille's Audio module
14 | my $grf=loadGrf("./fonts/ZX Times.grf");
15 | my $stopUpdates=0;
16 | my $canvas = Term::Graille->new(
17 | width => 148,
18 | height => 60,
19 | top=>3,
20 | left=>4,
21 | borderStyle => "double",
22 | title=>"Breakout",
23 | );
24 | my $lives=3;
25 | my $score=0;
26 | my $level=1;
27 | my $spriteBank=Term::Graille::SpriteBank->new();
28 | my $dir="./sprites/";
29 | foreach my $colour(qw/red yellow green magenta cyan white blue/){
30 | $spriteBank->addShape($colour."brick",[[colour($colour)."█","█","█","▌".colour("reset")]]);
31 | }
32 |
33 | my $bat=new Term::Graille::Sprite(data=>[[("█") x 6]],pos=>[20,0],bounds=>[1,14,60,0]);
34 | my $ball=new Term::Graille::Sprite(pos=>[20,3],vel=>[1,1],bounds=>[1,14,70,-1],skip=>6);
35 | $spriteBank->addSprite("player",$bat);
36 | $spriteBank->addSprite("ball",$ball);
37 |
38 | my $help={};
39 |
40 | newWall();
41 | $spriteBank->drawAll($canvas);
42 | sleep 5;
43 | my $io=Term::Graille::Interact->new();
44 | $io->{debugCursor}=[22,45];
45 |
46 | $io->addAction(undef,"[D",{note=>"Move Left ",proc=>sub{
47 | $bat->blank($canvas);
48 | $bat->move([-1,0]) unless $bat->{pos}->[0] <= 2 }} );
49 | $io->addAction(undef,"[C",{note=>"Move Right ",proc=>sub{
50 | $bat->blank($canvas);
51 | $bat->move([1,0]) unless $bat->{pos}->[0] >= 68 }} );
52 | $io->addAction(undef,"p",{note=>"PaUSE ", proc=>sub{
53 | $stopUpdates=$stopUpdates?0:1;}} );
54 |
55 | $io->updateAction(\&update);
56 | $io->run();
57 |
58 | sub update{
59 | missed() unless @{$spriteBank->{groups}->{ball}};
60 | foreach my $bll (@{$spriteBank->{groups}->{ball}}){
61 | my ($edge,$dir)=$bll->edge();
62 |
63 | if ($bll->collide($bat)){
64 | $bll->{vel}->[1]=abs ($bll->{vel}->[1]);
65 | my $batside=4*($bll->{pos}->[0]-$bat->{pos}->[0]+1)/($bat->{geometry}->[0]+2);
66 | $bll->{vel}->[0]=(-2,-1,1,2)[$batside];
67 | $beep->playSound(undef,"B1") if ($bll->{skipped}==$bll->{skip});
68 | # printAt(20,25,($bll->{pos}->[0]-$bat->{pos}->[0]+1)." " );
69 | }
70 | elsif ($edge ne ""){
71 | if ($edge =~ "Bot"){
72 | $bll->{destroyed}=1;
73 | }
74 | $bll->{vel}->[1]=abs($bll->{vel}->[1])*$dir->[1] if ($dir->[1]);
75 | $bll->{vel}->[0]=abs($bll->{vel}->[0])*$dir->[0] if ($dir->[0]);;
76 | # printAt(20,15,$edge." ".$bll->{vel}->[1]);
77 | }
78 | else{
79 | nextLevel() unless @{$spriteBank->{groups}->{wall}};
80 | foreach my $brk (@{$spriteBank->{groups}->{wall}}){
81 | if ($bll->collide($brk)){
82 | $beep->playSound(undef,"A#1");
83 | $score+=$brk->{etc}->{points};
84 | special($brk,$bll);
85 | if ($bll->{pos}->[1] ==$brk->{pos}->[1]){ # if hitting side of brick
86 | $bll->{vel}->[0]=($bll->{pos}->[0] <=$brk->{pos}->[0])?-abs ($bll->{vel}->[0]):abs ($bll->{vel}->[0]);
87 | }
88 | else {
89 | $bll->{vel}->[1]=($bll->{pos}->[1] >$brk->{pos}->[1])?abs ($bll->{vel}->[1]):-abs ($bll->{vel}->[1]);
90 | }
91 | $bll->move();
92 | $bll->blankPrev($canvas);
93 | }
94 | }
95 | }
96 | }
97 | $spriteBank->update($canvas);
98 | $canvas->draw();
99 | #printAt(20,10,$ball->{pos}->[0]." ".$ball->{pos}->[1]);
100 | printAt(2,40,"Score: $score Level: $level, Lives ".colour("red")."♥ "x$lives.colour("reset") );
101 | }
102 |
103 | sub newWall{
104 | for my $row (0..5){
105 | for my $col (0..16){
106 | my $colour=(qw/red yellow green magenta cyan white blue/)[rand()*7];
107 | $spriteBank->addSprite("wall", new Term::Graille::Sprite (shape=>$colour."brick",pos=>[2+4*$col+2*($row%2),14-$row], etc=>{points=>5,type=>$colour}));
108 | }
109 | }
110 | }
111 |
112 | sub missed{
113 | $lives--;
114 | $beep->playMusic(undef,["D1","C1","B1","A1"]);
115 | if ($lives){
116 | fontWrite($canvas,$grf,19,4,"Missed !");
117 | $canvas->draw();
118 | sleep 5;
119 | fontWrite($canvas,$grf,17,4," ");
120 | $ball=new Term::Graille::Sprite(pos=>[$bat->{pos}->[0],3],vel=>[1,1],bounds=>[1,14,70,-1],skip=>6);
121 | $spriteBank->addSprite("ball",$ball);
122 | }
123 | else{
124 | fontWrite($canvas,$grf,9,8,"The Wall Wins");
125 |
126 | $canvas->draw();
127 | $io->stop();
128 | exit;
129 | }
130 | }
131 |
132 | sub nextLevel{
133 | $beep->playMusic(undef,["A2","B2","C2","D2"]);
134 | fontWrite($canvas,$grf,2,4,"Wall ".$level++." Destroyed !");
135 | $canvas->draw();
136 | sleep 2;
137 | $canvas->clear();
138 | newWall();
139 | $spriteBank->drawAll($canvas);
140 | }
141 |
142 | sub special{
143 | my ($brick,$ball)=@_;
144 | $brick->{destroyed}=1;
145 | my $type=$brick->{etc}->{type};
146 | my $message=" $type brick hit ";
147 | if ($type eq "blue"){
148 | $message.="10pts Ball moves faster ";
149 | $score+=10;
150 | $ball->{skip}=4;
151 | }
152 | elsif($type eq "red"){
153 | $message.="100pts Ball moves slower ";
154 | $score+=100;
155 | $ball->{skip}=8;
156 | }
157 | elsif($type eq "magenta"){
158 | $message.="1000pts Destroys nearby bricks ";
159 | $score+=1000;
160 | foreach my $brk (@{$spriteBank->{groups}->{wall}}){
161 | if ((($brk->{pos}->[0]-$ball->{pos}->[0])**2 + ($brk->{pos}->[1]-$ball->{pos}->[1])**2)<30){
162 | $brk->{destroyed}=1;
163 | }
164 | }
165 | }
166 | elsif($type eq "yellow"){
167 | $message.="500pts Destroys entire row ";
168 | $score+=1000;
169 | foreach my $brk (@{$spriteBank->{groups}->{wall}}){
170 | unless ($brk->{pos}->[1]-$brick->{pos}->[1]){
171 | $brk->{destroyed}=1;
172 | }
173 | }
174 | }
175 | elsif($type eq "green"){
176 | $message.="1000pts all green bricks disappear ";
177 | $score+=1000;
178 | foreach my $brk (@{$spriteBank->{groups}->{wall}}){
179 | if ($brk->{etc}->{type} eq "green"){
180 | $brk->{destroyed}=1;
181 | }
182 | }
183 | }
184 | elsif($type eq "white"){
185 | $message.="100pts multiple balls";
186 | $score+=100;
187 | $spriteBank->addSprite("ball",new Term::Graille::Sprite(pos=>[@{$bat->{pos}}],vel=>[int(rand()*3)-1,1],bounds=>[1,14,70,-1],skip=>6));
188 |
189 | }
190 |
191 | unless (exists $help->{$type} && $help->{type}++>2){
192 | $help->{$type}//=1;
193 | $canvas->textAt(17,15,$message);
194 | $canvas->draw();
195 | sleep 1;
196 | $canvas->textAt(17,15," "x length $message,);
197 | $canvas->draw();
198 | }
199 |
200 | }
201 |
202 |
--------------------------------------------------------------------------------
/examples/convert2grl.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use lib "../lib/";
4 | use Term::Graille qw/colour paint printAt clearScreen border/;
5 | use Image::Magick;
6 |
7 | # convert2grl--converts an image to .grl format.
8 |
9 | my $imgFile=$ARGV[0];
10 |
11 | my $canvas = Term::Graille->new(
12 | width => 72,
13 | height => 60,
14 | top=>4,
15 | left=>10,
16 | borderStyle => "double",
17 | );
18 | clearScreen();
19 | loadImage($imgFile||"perl2.jpg");
20 | $canvas->exportCanvas("save.grl");
21 |
22 | #$canvas->importCanvas("save.grl");
23 |
24 | sub loadImage{
25 | my $imgfile=shift;
26 | my $image = Image::Magick->new();
27 | my $wh = $image->Read($imgfile);
28 | $image->Resize(geometry => "$canvas->{width}x$canvas->{height}");
29 | warn $wh if $wh;
30 | $image->set('monochrome'=>'True');
31 | for (my $x =0;$x<$canvas->{width};$x++){
32 | for (my $y=0;$y<$canvas->{height};$y++){
33 | $canvas->set($x,$y) if $image->GetPixel("x"=>$x,"y",$canvas->{height}-$y);
34 | }
35 | }
36 | }
37 |
38 | $canvas->draw();
39 | print "\n";
40 | print $imgFile//"no File input";;
41 |
--------------------------------------------------------------------------------
/examples/demo.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use lib "../lib/";
4 | use Term::Graille qw/colour paint printAt clearScreen border/;
5 | use Term::Graille::Font qw/loadGrf fontWrite/;
6 | use Time::HiRes "sleep";
7 | my $canvas = Term::Graille->new(
8 | width => 72,
9 | height => 64,
10 | top=>3,
11 | left=>10,
12 | borderStyle => "double",
13 | );
14 | clearScreen();
15 |
16 | my $grf=loadGrf("./fonts/ZX Times.grf");
17 | logo();
18 | turtle();
19 | cube();
20 | lines();
21 | waves();
22 |
23 | printAt(20,50," ");
24 |
25 | sub logo{
26 | $canvas->clear();
27 | $canvas->{borderColour}="cyan";
28 | $canvas->{title}="Term::Graille";
29 | $canvas->logo("pu;rt 90; fd 25; rt 90;fd 31;lt 180;pd;");
30 | printAt(5,50, paint("Introducing Term::Graille", "white on_black"));
31 | printAt(7,50, paint(["Inspired by Drawille by",
32 | "asciimoo, which has many",
33 | "variants (including a ",
34 | "Perl variant Term::Drawille",
35 | "by RHOELZ), this is a clone",
36 | "with a few extras. The goal",
37 | "is to deliver better",
38 | "performance and features. "],"yellow"));
39 |
40 |
41 |
42 | fontWrite($canvas,$grf,4,5,"GRAILLE");
43 | $canvas->textAt(18,14,"Testing version $Term::Graille::VERSION","green italic");
44 | $canvas->textAt(18,10,"with Bresenham $Algorithm::Line::Bresenham::VERSION","green italic");
45 | $canvas->ellipse_rect(20,63, 52,55,"red");
46 | $canvas->quad_bezier(20,59,22,40,35,40);
47 | $canvas->quad_bezier(37,40,50,40,52,59);
48 | $canvas->polyline(35,40,35,35,20,35,20,33,55,33,55,35,37,35,37,40,"yellow");
49 | $canvas->draw();
50 | sleep 2;
51 | for (0..20){
52 | $canvas->scroll("d");
53 | sleep 0.05;
54 | $canvas->draw();
55 | }
56 | }
57 |
58 | sub turtle{
59 | $canvas->clear();
60 | $canvas->{borderColour}="magenta";
61 | $canvas->{title}="Turtle";
62 | printAt(5,50, paint("Turtle Graphics ", "white on_black"));
63 | printAt(7,50, paint(["This early version supports ",
64 | "Turtle-like drawing as well e.g.",
65 | "fd,bk,lt,rt,pu,pd,ce,sp "," "x30,], "yellow"));
66 | printAt(11,50, paint(["\$canvas->logo('fd 35;lt 75')",
67 | " for (0..23); ",
68 | " "x 30," "x30," "x 30," "x30,], "green"));
69 | $canvas->logo("mv 15,30;pc magenta;sp 8;");
70 | my @clrs=qw/red yellow green cyan magenta blue green red yellow/;
71 | $canvas->logo("fd 50;lt 160;pc $clrs[$_]") for (0..8);
72 | sleep 2;
73 | }
74 |
75 |
76 | sub cube{
77 | # adapted from http://www.rosettacode.org/wiki/Draw_a_rotating_cube
78 | my $size = 60;
79 | my ($height, $width) = ($size, $size * sqrt 8/9);
80 | my $mid = $width / 2;
81 | my $rot = atan2(0, -1) / 3; # middle corners every 60 degrees
82 | $canvas->{borderColour}="green";
83 |
84 | printAt(5,50, paint("Animated drawings ", "white on_black"));
85 | printAt(7,50, paint(["Rotating cube. This algorithm ",
86 | "was adapted from code from ",
87 | "http://www.rosettacode.org/ ",
88 | " "x 30," "x30," "x30," "x30,],"yellow"));
89 | $canvas->{title}="Rotating Cube";
90 | foreach my $a (0..300)
91 | {
92 | my $angle = $a/30;
93 | my @points = map { $mid + $mid * cos $angle + $_ * $rot,
94 | $height * ($_ % 2 + 1) / 3 } 0 .. 5;
95 | $canvas->line(@points[0, 1], $mid, 0,"red");
96 | $canvas->line(@points[0, 1], @points[2, 3],"green");
97 | $canvas->line(@points[4, 5], $mid, 0,"yellow");
98 | $canvas->line(@points[4, 5], @points[6, 7],"blue");
99 | $canvas->line(@points[8, 9],$mid, 0,"magenta");
100 | $canvas->line(@points[8, 9],@points[10, 11],"white");
101 | $canvas->line(@points[2, 3], $mid, $height,"cyan");
102 | $canvas->line(@points[2, 3], @points[4, 5],"blue");
103 | $canvas->line(@points[6, 7],$mid, $height,"red");
104 | $canvas->line(@points[6, 7],@points[8, 9],"green");
105 | $canvas->line(@points[10, 11],$mid, $height,"yellow");
106 | $canvas->line(@points[10, 11],@points[0, 1]);
107 | $canvas->draw();
108 | sleep .01;
109 | $canvas->clear();
110 | }
111 | sleep 2;
112 | }
113 |
114 | sub lines{
115 | $canvas->clear();;
116 | $canvas->{borderColour}="yellow";
117 | $canvas->{title}="Lines, Curves, Circles Etc";
118 | printAt(5,50, paint("Drawing Primitives ", "white on_black"));
119 | printAt(7,50, paint("Lines ","yellow"));
120 | printAt(8,50, paint(["\$canvas->line(10,10, ",
121 | " 30,30) "],"green"));
122 | printAt(10,50, paint("Curves ","yellow"));
123 | printAt(11,50, paint(["\$canvas->quad_bezier(10,10, ",
124 | " 30,30,50,10); "],"green"));
125 | printAt(13,50, paint("Circles ","yellow"));
126 | printAt(14,50, paint("\$canvas->circle(30,30,5); ", "green"));
127 |
128 | $canvas->quad_bezier(10,30,37,-10,64,30,"green");
129 | $canvas->line(10,30,10,45,"green");
130 | $canvas->line(64,30,64,45,"green");
131 |
132 | for my $rl(0..1){ # draw eyes
133 | for (0..4){
134 | $canvas->ellipse_rect(15+$_+30*$rl,45,30-$_+30*$rl,40,"magenta");
135 | }
136 | }
137 |
138 |
139 | $canvas->quad_bezier(25,25,37,10,49,25,"red");
140 | $canvas->quad_bezier(25,25,37,20,49,25,"red");
141 |
142 | $canvas->circle(37,33,5,"yellow");
143 | $canvas->polyline(10,55,15,58,20,55,25,58,30,55,35,58,
144 | 40,55,45,58,50,55,55,58,60,55,65,58,
145 | 65,50,10,50,10,55,"yellow");
146 | $canvas->draw();
147 | sleep 2;
148 | }
149 |
150 | sub waves{
151 | $canvas->clear();;
152 | $canvas->{borderColour}="blue";
153 | $canvas->{title}="Waves";
154 | printAt(5,50, paint("Charting/graphing ", "white on_black"));
155 | printAt(7,50, paint(["This example plots a line ",
156 | "on the left most two pixels ",
157 | "and then scrolls the frame left ",
158 | "by 2 pixels. e.g :- ",
159 | " "x30], "yellow"));
160 | printAt(12,50, paint(["foreach my \$c (1..1000){ ",
161 | "\$canvas->line(70,20*sin(\$c/20)+",
162 | "40,71,20*sin((\$c+0.5)/20)+40); ",
163 | "\$canvas->scroll('l'); ",
164 | "sleep 0.01; ",
165 | "\$canvas->draw();} "], "green"));
166 | foreach my $c (1..500){
167 | sleep .01;
168 | $canvas->line(70,20*sin($c/20)+40,71,20*sin(($c+0.5)/20)+40,"red");
169 | $canvas->line(70,20*cos($c/2)+40,71,20*cos(($c+0.5)/2)+40,"green");
170 | $canvas->scroll("l");
171 | $canvas->draw();
172 | }
173 |
174 | sleep 5
175 |
176 | }
177 |
178 |
179 |
180 |
--------------------------------------------------------------------------------
/examples/editor.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 |
3 | use strict; use warnings;
4 | use utf8;
5 | use lib "../lib";
6 | use open ":std", ":encoding(UTF-8)";
7 | use Term::Graille qw/colour paint printAt cursorAt clearScreen border blockBlit block2braille pixelAt/;
8 | use Term::Graille::Interact ;
9 | use Term::Graille::Menu;
10 | use Term::Graille::Textarea;
11 | use Term::Graille::Selector;
12 | use Term::Graille::Dialog ;
13 | use Time::HiRes qw/sleep/;
14 | use Data::Dumper;
15 |
16 | my $io=Term::Graille::Interact->new();
17 | $io->{debugCursor}=[22,45];
18 |
19 | my @colours=qw/red blue green yellow cyan magenta white/;
20 |
21 | # setup keyboard short cuts
22 |
23 | my $menu=new Term::Graille::Menu( # no object offered so id will be o0
24 | menu=>[["File","New","Load","Insert","Save","Quit"],
25 | ["Edit",["Select","All","Start","End"],["Selection","Copy","Cut","Paste"],"Search","Replace"],
26 | ["Run","Logo","Perl","Python"],
27 | ["test","Death","Message","Input","Selector"],
28 | "About"],
29 | redraw=>\&refreshScreen,
30 | dispatcher=>\&menuActions,
31 | );
32 |
33 | # in this case the dispatcher directs to subroutines based on name of
34 | my %actions = ( New => sub{new()},
35 | Load => sub{ load()},
36 | Save => sub{ save() },
37 | Insert => sub{ load(undef,undef,1) },
38 | Editor=>sub{mode("Editor")},
39 | Viewer=>sub{mode("Viewer")},
40 | Message=>sub{message("Test Message")},
41 | "Logo"=>sub{logo()},
42 | );
43 |
44 | sub menuActions{ # dispatcher for menu
45 | my ($action,$gV)=@_;
46 | if (exists $actions{$action}){
47 | $actions{$action}->($gV)
48 | }
49 | else{
50 | printAt(2,60,$action)
51 | }
52 | };
53 |
54 | my $currentFile="";
55 |
56 | my $textarea=new Term::Graille::Textarea(); # no objectId offered so id will be o0
57 |
58 | my $canvas= Term::Graille->new(
59 | width => 80,
60 | height => 50,
61 | top=>4,
62 | left=>8,
63 | borderStyle => "double",
64 | title=>"Running $currentFile",
65 | );
66 |
67 | $io->addObject(object => $menu,trigger=>"m");
68 | $io->addObject(object => $textarea,trigger=>"e");
69 | $io->start("o1");
70 | $io->run("o1");
71 | refreshScreen();
72 |
73 | sub refreshScreen{
74 | clearScreen() unless (shift);
75 | $textarea->draw();
76 | }
77 |
78 | sub new{
79 | $textarea->{text}=[""];
80 | $textarea->{title}="Untitled";
81 | $textarea->{cursor}=[0,0];
82 | refreshScreen(1);
83 | $io->start("o1");
84 |
85 | }
86 |
87 | sub load{
88 | my ($dir,$filters,$insert)=@_;
89 | $dir//=".";
90 | $filters//="\.txt|\.pl|\.logo\$";
91 | opendir(my $DIR, $dir) || die "Can't open directory $dir: $!";
92 | my @files = sort(grep {(/$filters/i) && -f "$dir/$_" } readdir($DIR));
93 | closedir $DIR;
94 | my $selector=new Term::Graille::Selector(
95 | redraw=>\&refreshScreen,
96 | callback=>\&confirmLoad,
97 | options=>[@files],
98 | transient=>1,
99 | title=>"Load File",
100 | );
101 | my $selId=$io->addObject(object => $selector);
102 | $io->start($selId);
103 |
104 | }
105 |
106 | sub confirmLoad{ # if about to overwrite warn
107 | my ($param)=@_;
108 | my $file=$param->{selected};
109 | my $dialog=new Term::Graille::Dialog(
110 | redraw=>\&refreshScreen,
111 | callback=>\&loadFile,
112 | message=>"Are you sure you want to load this file? You will lose current work",
113 | param=>{file=>$file,action=>"load"},
114 | icon=>"info",
115 | title=>"Confirm Load",
116 | buttons=>[qw/Load Cancel/],
117 | );
118 | my $dialogId=$io->addObject(object => $dialog);
119 | $io->start($dialogId);
120 |
121 | }
122 |
123 |
124 |
125 | sub loadFile{
126 | my $param=shift;
127 | if ($param->{button} && $param->{button} eq "Cancel"){
128 | $io->close();
129 | $io->start("o1");
130 | return;
131 | };
132 | my $file=$param->{file};
133 | open(my $fh, "<", "$file") or die("Can't open file $file:$! ");
134 | chomp(my @lines = <$fh>);
135 | close($fh);
136 | $textarea->{text}=[@lines];
137 | $io->close();
138 | $textarea->{title}=$file;
139 | $textarea->{cursor}=[0,0];
140 | $currentFile=$file;
141 | $io->start("o1");
142 | }
143 |
144 | sub save{
145 | my ($dir,$filters)=@_;
146 | $dir//=".";
147 | $filters//="\.txt|\.pl|\.logo\$";
148 | opendir(my $DIR, $dir) || die "Can't open directory $dir: $!";
149 | my @files = sort(grep {(/$filters/i) && -f "$dir/$_" } readdir($DIR));
150 | closedir $DIR;
151 | my $selector=new Term::Graille::Selector(
152 | redraw=>\&refreshScreen,
153 | #callback=>\&saveFile,
154 | callback=>\&confirmSave,
155 | options=>[@files],
156 | transient=>1,
157 | selected =>$currentFile,
158 | title=>"Save File",
159 | );
160 | my $selId=$io->addObject(object => $selector);
161 | $io->start($selId);
162 |
163 | }
164 |
165 | sub confirmSave{ # if about to overwrite warn
166 | my ($param)=@_;
167 | my $file=$param->{selected};
168 | if (-e $file){
169 | my $dialog=new Term::Graille::Dialog(
170 | redraw=>\&refreshScreen,
171 | callback=>\&saveFile,
172 | message=>"Are you sure you want to save this file? it will overwrite $file",
173 | param=>{file=>$file,action=>"save"},
174 | icon=>"info",
175 | title=>"Confirm Save",
176 | buttons=>[qw/Overwrite Cancel/]
177 | );
178 | my $dialogId=$io->addObject(object => $dialog);
179 | $io->start($dialogId);
180 | }
181 | else{
182 | saveFile({file=>$file});
183 | }
184 |
185 | }
186 |
187 | sub saveFile{
188 | my ($param)=@_;
189 | $io->close();
190 | if ($param->{button} && $param->{button} eq "Cancel"){
191 | $io->start("o1");
192 | return;
193 | };
194 | my $file=$param->{file};
195 | open(my $fh, ">", "$file") or die("Can't open file $file:$! ");
196 | print $fh join("\n",@{$textarea->{text}});
197 | close($fh);
198 | $textarea->{title}=$file;
199 | $currentFile=$file;
200 | $io->start("o1");
201 | }
202 |
203 | sub message{
204 | my ($message,$input)=@_;
205 | my $dialog=new Term::Graille::Dialog(
206 | redraw=>\&refreshScreen,
207 | callback=>\&messageReturn,
208 | message=>$message,
209 | icon=>"info",
210 | title=>"Test Message",
211 | );
212 | $dialog->mode("ync");
213 | my $dialogId=$io->addObject(object => $dialog);
214 | $io->start($dialogId);
215 | }
216 |
217 | sub messageReturn{
218 | my ($ret,$params)=@_;
219 | $ret||="nothing" ;
220 | $params="" unless (defined $params);
221 | $io->close();
222 | if ($ret){ printAt(2,50,"$ret $params returned") }
223 |
224 | }
225 |
226 | sub logo{
227 | $canvas->logo(join (";",@{$textarea->{text}}));
228 | $canvas->{title}="Running $currentFile";
229 | $canvas-> draw();
230 | }
231 |
232 |
--------------------------------------------------------------------------------
/examples/fontDemo.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use utf8;
4 |
5 | use open ":std", ":encoding(UTF-8)";
6 | use Term::Graille qw/colour paint printAt clearScreen border/;
7 | use Term::Graille::Font qw/convertDG saveGrf loadGrf fontWrite/;
8 | use Time::HiRes qw/sleep/;
9 |
10 |
11 | my $canvas = Term::Graille->new(
12 | width => 120,
13 | height => 60,
14 | top=>4,
15 | left=>10,
16 | borderStyle => "double",
17 | );
18 |
19 | my @fontNames=("Area51","Cinema Bold","Mutual","Everest","ZX Times");
20 | my @fonts = map {my $f=loadGrf("./fonts/$_.grf");$f} @fontNames;
21 | my @texts = map {" $_->{info} 8x8 Fonts imported from https://damieng.com/typography/zx-origins/ "} @fonts;
22 |
23 | my @pointers=(0) x scalar @fontNames;
24 |
25 | fontWrite($canvas,$fonts[0],10,8,"Font Demo");
26 | $canvas->textAt(30,25,"Mixed text is also possible");
27 | $canvas->textAt(30,22,"printable directly on canvas");
28 |
29 | $canvas->draw();
30 | sleep 2;
31 |
32 | for (0..100){
33 | for my $fn (0..$#fontNames){
34 | fontWrite($canvas,$fonts[$fn],55,1+$fn*3,substr($texts[$fn],$pointers[$fn]++,1));
35 | $pointers[$fn]=0 if ($pointers[$fn]>=length $texts[$fn]);
36 | }
37 |
38 | for (0..3){
39 | $canvas->scroll("l");
40 | sleep .05;
41 | $canvas->draw();
42 | }
43 |
44 | }
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/examples/fonts/Anvil Alternate.grf:
--------------------------------------------------------------------------------
1 | {'c' => [["⢀","⡤","⣄","⡄"],["⢸","⣇","⣠","⠆"]],
2 | '}' => [["⠈","⠹","⣇","⡀"],["⢀","⣸","⡇","⠀"]],
3 | 'G' => [["⣴","⠋","⠳","⠇"],["⢿","⣄","⢽","⡏"]],
4 | 'J' => [["⠀","⠈","⢹","⡏"],["⢾","⣀","⡼","⠃"]],
5 | 'd' => [["⢀","⡤","⣹","⡇"],["⠸","⣇","⡸","⣇"]],
6 | 'u' => [["⢀","⡄","⢀","⡄"],["⠹","⣇","⡼","⣇"]],
7 | 'm' => [["⣤","⣠","⣠","⡀"],["⣿","⠸","⢸","⡇"]],
8 | 'A' => [["⠀","⣴","⢻","⡇"],["⣹","⡏","⣹","⡇"]],
9 | ';' => [["⠀","⠰","⠆","⠀"],["⠀","⡲","⠂","⠀"]],
10 | 'H' => [["⢹","⣇","⣸","⡏"],["⣹","⡇","⢸","⣇"]],
11 | '7' => [["⠟","⠉","⣽","⠃"],["⢀","⣽","⡋","⠁"]],
12 | '"' => [["⠨","⠋","⠝","⠁"],["⠀","⠀","⠀","⠀"]],
13 | 'f' => [["⠀","⣴","⠋","⠓"],["⢉","⣿","⡉","⠀"]],
14 | '?' => [["⠸","⠋","⣹","⠆"],["⠀","⢨","⡅","⠀"]],
15 | 'I' => [["⠈","⢹","⡏","⠁"],["⢀","⣸","⣇","⡀"]],
16 | 'Q' => [["⣴","⠋","⢹","⡆"],["⠻","⣬","⡳","⣅"]],
17 | 'x' => [["⢤","⡀","⣤","⠄"],["⣠","⡟","⢧","⡀"]],
18 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⡲","⠂","⠀"]],
19 | 'e' => [["⠀","⣠","⢤","⡀"],["⢸","⣗","⣪","⠆"]],
20 | '3' => [["⠟","⣩","⡟","⠁"],["⣦","⣀","⣹","⠆"]],
21 | 'O' => [["⣴","⠋","⢻","⡄"],["⢻","⣄","⡼","⠃"]],
22 | '4' => [["⢴","⡇","⣾","⠀"],["⠛","⠒","⣿","⠂"]],
23 | 'w' => [["⣤","⢠","⢠","⡄"],["⣿","⠞","⢾","⡇"]],
24 | ')' => [["⠀","⠙","⣦","⠀"],["⠀","⣠","⠟","⠀"]],
25 | '8' => [["⣴","⢋","⣹","⠆"],["⢾","⣉","⡼","⠃"]],
26 | 'D' => [["⢹","⡏","⢷","⡀"],["⣸","⣇","⣸","⠇"]],
27 | 'W' => [["⣿","⢀","⢸","⡇"],["⣿","⠎","⢾","⡇"]],
28 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
29 | '<' => [["⢀","⡴","⠋","⠀"],["⠈","⠳","⣄","⠀"]],
30 | 'M' => [["⣿","⡄","⣼","⡇"],["⣿","⠘","⢸","⡇"]],
31 | 'R' => [["⢹","⡏","⣹","⠆"],["⣹","⡏","⢳","⣄"]],
32 | 'Z' => [["⠟","⢉","⡽","⠃"],["⣴","⣋","⣠","⡆"]],
33 | 'y' => [["⢤","⡄","⢠","⡤"],["⠀","⣹","⣏","⠀"]],
34 | '&' => [["⠰","⣏","⣓","⡀"],["⢾","⣁","⣻","⣄"]],
35 | "£" => [["⢀","⡾","⠱","⠇"],["⣹","⣏","⣡","⡆"]],
36 | 'U' => [["⣿","⠁","⢹","⡇"],["⠹","⣆","⡾","⠁"]],
37 | 'o' => [["⠀","⣠","⢤","⡄"],["⠸","⣇","⡼","⠃"]],
38 | 'E' => [["⢹","⣏","⡙","⠇"],["⣹","⣇","⣠","⡆"]],
39 | '$' => [["⠠","⣞","⡳","⡄"],["⠘","⢮","⡽","⠂"]],
40 | '@' => [["⣴","⢫","⢽","⡆"],["⢿","⣌","⣋","⠄"]],
41 | 's' => [["⢀","⡤","⢄","⡄"],["⠰","⣍","⣳","⠆"]],
42 | 'K' => [["⢹","⣇","⡼","⠃"],["⣹","⡇","⢻","⡄"]],
43 | '~' => [["⡾","⠳","⣴","⠇"],["⠀","⠀","⠀","⠀"]],
44 | '5' => [["⣿","⣉","⡙","⠇"],["⣦","⣀","⣹","⠆"]],
45 | 'j' => [["⠀","⠀","⢈","⡅"],["⠠","⣄","⣹","⠇"]],
46 | 'k' => [["⢴","⡇","⣠","⠄"],["⣸","⡟","⣧","⡀"]],
47 | 'F' => [["⢹","⣏","⡙","⠇"],["⣹","⣇","⠀","⠀"]],
48 | '0' => [["⣴","⢉","⢵","⡄"],["⠻","⣊","⡸","⠃"]],
49 | '\\' => [["⠳","⣄","⠀","⠀"],["⠀","⠈","⠳","⡄"]],
50 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
51 | 'X' => [["⠹","⣇","⡽","⠃"],["⣴","⡋","⢳","⣄"]],
52 | ':' => [["⠀","⠰","⠆","⠀"],["⠀","⠰","⠆","⠀"]],
53 | '(' => [["⠀","⣴","⠋","⠀"],["⠀","⠻","⣄","⠀"]],
54 | '2' => [["⠸","⠋","⣹","⠆"],["⣴","⣋","⣠","⡆"]],
55 | '^' => [["⣠","⣾","⣦","⡀"],["⠀","⡿","⡇","⠀"]],
56 | 'i' => [["⠀","⢈","⡅","⠀"],["⠀","⣹","⣇","⠀"]],
57 | 'T' => [["⠟","⢹","⡏","⠻"],["⠀","⣸","⣇","⠀"]],
58 | 'p' => [["⢀","⡤","⢤","⡀"],["⢹","⡗","⠼","⠇"]],
59 | 't' => [["⠤","⣾","⠤","⠄"],["⠀","⢿","⣠","⡆"]],
60 | 'n' => [["⢀","⣄","⢤","⡄"],["⢹","⡇","⢸","⡇"]],
61 | '+' => [["⢀","⣰","⣇","⡀"],["⠀","⠸","⠃","⠀"]],
62 | '9' => [["⠠","⣞","⢉","⣷"],["⢰","⣌","⣡","⠟"]],
63 | 'v' => [["⢀","⡄","⢀","⡄"],["⢹","⣧","⠞","⠁"]],
64 | 'r' => [["⢀","⣄","⢤","⡄"],["⢀","⣿","⡀","⠀"]],
65 | 'a' => [["⠀","⣠","⢤","⡄"],["⢸","⣇","⢼","⣇"]],
66 | 'B' => [["⢹","⡏","⣹","⠆"],["⣹","⣏","⣸","⠇"]],
67 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
68 | '1' => [["⠀","⢴","⡇","⠀"],["⠀","⣸","⣇","⠀"]],
69 | '\'' => [["⠀","⠝","⠁","⠀"],["⠀","⠀","⠀","⠀"]],
70 | 'N' => [["⣿","⢦","⢹","⡏"],["⣿","⡀","⢻","⣇"]],
71 | '%' => [["⠺","⢃","⡴","⠃"],["⡴","⠋","⢴","⠆"]],
72 | 'C' => [["⣴","⠋","⠳","⠇"],["⢿","⣄","⣠","⠆"]],
73 | 'V' => [["⣿","⠁","⣽","⠋"],["⣿","⡼","⠃","⠀"]],
74 | 'z' => [["⢠","⡤","⢤","⡄"],["⢨","⣞","⣡","⡆"]],
75 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠶","⠀","⠀"]],
76 | '6' => [["⣴","⣋","⡙","⠇"],["⠻","⣄","⣹","⡆"]],
77 | 'info' => ' Anvil Alternate font ','!' => [["⠀","⢴","⡇","⠀"],["⠀","⢨","⡅","⠀"]],
78 | '[' => [["⢨","⡟","⠉","⠀"],["⢸","⣇","⣀","⠀"]],
79 | 'h' => [["⢴","⣇","⢤","⡀"],["⣸","⡇","⣸","⡇"]],
80 | '=' => [["⠠","⠤","⠤","⠄"],["⠈","⠉","⠉","⠁"]],
81 | '#' => [["⢤","⡿","⣼","⠇"],["⣾","⢳","⡟","⠂"]],
82 | '/' => [["⠀","⢀","⡴","⠃"],["⡴","⠋","⠀","⠀"]],
83 | ']' => [["⠈","⠉","⣿","⠀"],["⢀","⣠","⣟","⠀"]],
84 | 'P' => [["⢹","⡏","⣹","⠆"],["⣹","⣏","⠀","⠀"]],
85 | '*' => [["⠠","⣴","⣦","⠄"],["⠈","⠙","⠋","⠁"]],
86 | 'b' => [["⢴","⣇","⢤","⡀"],["⣸","⣇","⣸","⠇"]],
87 | '|' => [["⠀","⢸","⡇","⠀"],["⠀","⢸","⡇","⠀"]],
88 | 'l' => [["⠀","⢴","⡇","⠀"],["⠀","⣸","⣇","⠀"]],
89 | 'Y' => [["⠹","⣇","⣸","⠏"],["⠀","⣸","⣇","⠀"]],
90 | "©" => [["⡔","⣩","⢭","⢢"],["⠣","⣛","⣒","⠜"]],
91 | '>' => [["⠈","⠳","⣄","⠀"],["⢀","⡴","⠋","⠀"]],
92 | '{' => [["⢀","⣸","⠏","⠁"],["⠀","⢸","⣇","⡀"]],
93 | 'L' => [["⢹","⡏","⠀","⠀"],["⣸","⣇","⣠","⡆"]],
94 | 'S' => [["⠰","⣏","⡓","⠇"],["⡷","⣄","⣹","⠆"]],
95 | 'g' => [["⠀","⣠","⠤","⠄"],["⢸","⣇","⣹","⡏"]],
96 | 'q' => [["⢀","⡤","⢤","⡀"],["⠸","⠧","⢺","⡏"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Area51 Overwide.grf:
--------------------------------------------------------------------------------
1 | {'Q' => [["⢰","⠉","⡆","⠀"],["⠘","⠔","⠅","⠀"]],
2 | "£" => [["⢰","⣉","⠂","⠀"],["⠸","⠤","⠄","⠀"]],
3 | 'i' => [["⠠","⡅","⠀","⠀"],["⠀","⠧","⠀","⠀"]],
4 | 'w' => [["⡄","⠀","⡄","⠀"],["⠗","⠑","⠇","⠀"]],
5 | 'J' => [["⠀","⠀","⡇","⠀"],["⠘","⠤","⠃","⠀"]],
6 | '0' => [["⢰","⠉","⡆","⠀"],["⠘","⠤","⠃","⠀"]],
7 | '%' => [["⠰","⢀","⠆","⠀"],["⠰","⠁","⠆","⠀"]],
8 | '|' => [["⠀","⡇","⠀","⠀"],["⠀","⠇","⠀","⠀"]],
9 | '<' => [["⢀","⠔","⠀","⠀"],["⠀","⠑","⠀","⠀"]],
10 | 'I' => [["⠈","⡏","⠀","⠀"],["⠠","⠧","⠀","⠀"]],
11 | 'X' => [["⠣","⡠","⠃","⠀"],["⠎","⠈","⠆","⠀"]],
12 | 'r' => [["⢠","⡠","⠄","⠀"],["⠸","⠀","⠀","⠀"]],
13 | 'U' => [["⢸","⠀","⡇","⠀"],["⠘","⠤","⠃","⠀"]],
14 | '9' => [["⠰","⣉","⡆","⠀"],["⠀","⠔","⠁","⠀"]],
15 | '7' => [["⠈","⢉","⠇","⠀"],["⠀","⠎","⠀","⠀"]],
16 | ',' => [["⠀","⠀","⠀","⠀"],["⢀","⠆","⠀","⠀"]],
17 | 'a' => [["⠀","⠤","⡀","⠀"],["⠐","⠭","⠇","⠀"]],
18 | '2' => [["⠈","⢉","⠆","⠀"],["⠰","⠥","⠄","⠀"]],
19 | '>' => [["⠐","⢄","⠀","⠀"],["⠐","⠁","⠀","⠀"]],
20 | 'V' => [["⢸","⠀","⡇","⠀"],["⠸","⠔","⠁","⠀"]],
21 | 'g' => [["⢀","⠤","⡄","⠀"],["⠈","⣒","⠇","⠀"]],
22 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
23 | 'Y' => [["⠣","⡠","⠃","⠀"],["⠀","⠇","⠀","⠀"]],
24 | 'G' => [["⢰","⢉","⡁","⠀"],["⠘","⠤","⠇","⠀"]],
25 | 'P' => [["⢸","⣉","⠆","⠀"],["⠸","⠀","⠀","⠀"]],
26 | 'v' => [["⠠","⡀","⡠","⠀"],["⠀","⠱","⠁","⠀"]],
27 | '!' => [["⠀","⡇","⠀","⠀"],["⠀","⠅","⠀","⠀"]],
28 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠆","⠀","⠀"]],
29 | 'O' => [["⢰","⠉","⡆","⠀"],["⠘","⠤","⠃","⠀"]],
30 | 'q' => [["⢀","⠤","⡄","⠀"],["⠈","⠒","⡇","⠀"]],
31 | '4' => [["⢀","⠎","⡇","⠀"],["⠈","⠉","⠇","⠀"]],
32 | '&' => [["⠰","⣉","⡄","⠀"],["⠘","⠤","⠇","⠀"]],
33 | 'A' => [["⢰","⣉","⡆","⠀"],["⠸","⠀","⠇","⠀"]],
34 | 'H' => [["⢸","⣀","⡇","⠀"],["⠸","⠀","⠇","⠀"]],
35 | ']' => [["⠈","⢹","⠀","⠀"],["⠠","⠼","⠀","⠀"]],
36 | '6' => [["⢠","⣊","⠀","⠀"],["⠘","⠤","⠃","⠀"]],
37 | 'b' => [["⢸","⠤","⡀","⠀"],["⠸","⠤","⠃","⠀"]],
38 | 'Z' => [["⠈","⡩","⠃","⠀"],["⠸","⠤","⠄","⠀"]],
39 | 'e' => [["⢀","⠤","⡀","⠀"],["⠘","⠭","⠅","⠀"]],
40 | '{' => [["⢀","⠎","⠀","⠀"],["⠀","⠣","⠀","⠀"]],
41 | 'u' => [["⢠","⠀","⡄","⠀"],["⠘","⠤","⠇","⠀"]],
42 | 'x' => [["⢄","⢀","⠄","⠀"],["⠔","⠑","⠄","⠀"]],
43 | '+' => [["⢀","⣆","⠀","⠀"],["⠀","⠃","⠀","⠀"]],
44 | 's' => [["⢀","⠤","⠄","⠀"],["⠠","⠭","⠂","⠀"]],
45 | '5' => [["⢸","⣉","⠁","⠀"],["⠠","⠤","⠃","⠀"]],
46 | 'j' => [["⠀","⠀","⡅","⠀"],["⠰","⣀","⠇","⠀"]],
47 | 'd' => [["⢀","⠤","⡇","⠀"],["⠘","⠤","⠇","⠀"]],
48 | 'T' => [["⠈","⡏","⠀","⠀"],["⠀","⠇","⠀","⠀"]],
49 | 'y' => [["⢠","⠀","⡄","⠀"],["⠈","⣒","⠇","⠀"]],
50 | '8' => [["⠰","⣉","⠆","⠀"],["⠘","⠤","⠃","⠀"]],
51 | '~' => [["⠠","⠢","⠂","⠀"],["⠀","⠀","⠀","⠀"]],
52 | '3' => [["⠈","⣩","⠃","⠀"],["⠐","⠤","⠃","⠀"]],
53 | '^' => [["⠔","⡗","⠄","⠀"],["⠀","⠇","⠀","⠀"]],
54 | '"' => [["⠠","⠣","⠃","⠀"],["⠀","⠀","⠀","⠀"]],
55 | '#' => [["⢰","⠤","⡆","⠀"],["⠸","⠒","⠇","⠀"]],
56 | 't' => [["⢸","⠤","⠀","⠀"],["⠘","⠤","⠂","⠀"]],
57 | 'z' => [["⠠","⢤","⠀","⠀"],["⠰","⠥","⠀","⠀"]],
58 | ')' => [["⠈","⢢","⠀","⠀"],["⠠","⠊","⠀","⠀"]],
59 | 'B' => [["⢸","⣉","⠆","⠀"],["⠸","⠤","⠃","⠀"]],
60 | ';' => [["⠀","⡄","⠀","⠀"],["⢀","⠆","⠀","⠀"]],
61 | 'k' => [["⢸","⢀","⠄","⠀"],["⠸","⠑","⠄","⠀"]],
62 | 'h' => [["⢸","⠤","⡀","⠀"],["⠸","⠀","⠇","⠀"]],
63 | '$' => [["⠠","⡚","⠄","⠀"],["⠐","⡬","⠂","⠀"]],
64 | 'D' => [["⢸","⠉","⡆","⠀"],["⠸","⠤","⠃","⠀"]],
65 | ':' => [["⠀","⡄","⠀","⠀"],["⠀","⠆","⠀","⠀"]],
66 | '\\' => [["⠈","⢆","⠀","⠀"],["⠀","⠈","⠆","⠀"]],
67 | 'E' => [["⢸","⣉","⠁","⠀"],["⠸","⠤","⠄","⠀"]],
68 | '(' => [["⢠","⠊","⠀","⠀"],["⠈","⠢","⠀","⠀"]],
69 | '=' => [["⠠","⠤","⠄","⠀"],["⠈","⠉","⠁","⠀"]],
70 | '@' => [["⢰","⡩","⡆","⠀"],["⠘","⠬","⠅","⠀"]],
71 | 'm' => [["⡠","⡠","⡀","⠀"],["⠇","⠁","⠇","⠀"]],
72 | '-' => [["⢀","⣀","⡀","⠀"],["⠀","⠀","⠀","⠀"]],
73 | 'p' => [["⢠","⠤","⡀","⠀"],["⢸","⠒","⠁","⠀"]],
74 | 'N' => [["⢸","⠢","⡇","⠀"],["⠸","⠀","⠇","⠀"]],
75 | 'o' => [["⢀","⠤","⡀","⠀"],["⠘","⠤","⠃","⠀"]],
76 | '/' => [["⠀","⡰","⠁","⠀"],["⠰","⠁","⠀","⠀"]],
77 | 'F' => [["⢸","⣉","⠁","⠀"],["⠸","⠀","⠀","⠀"]],
78 | 'M' => [["⡗","⡔","⡇","⠀"],["⠇","⠀","⠇","⠀"]],
79 | 'l' => [["⠈","⡇","⠀","⠀"],["⠀","⠧","⠀","⠀"]],
80 | '[' => [["⢸","⠉","⠀","⠀"],["⠸","⠤","⠀","⠀"]],
81 | 'c' => [["⢀","⠤","⡀","⠀"],["⠘","⠤","⠂","⠀"]],
82 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⡀","⠀"]],
83 | 'L' => [["⢸","⠀","⠀","⠀"],["⠸","⠤","⠄","⠀"]],
84 | '?' => [["⠐","⢉","⠆","⠀"],["⠀","⠅","⠀","⠀"]],
85 | 'info' => ' Area51 Overwide font from https://damieng.com/zx-origins','W' => [["⡇","⡀","⡇","⠀"],["⠗","⠑","⠇","⠀"]],
86 | 'R' => [["⢸","⣉","⠆","⠀"],["⠸","⠈","⠆","⠀"]],
87 | 'n' => [["⢠","⠤","⡀","⠀"],["⠸","⠀","⠇","⠀"]],
88 | 'C' => [["⢰","⠉","⠂","⠀"],["⠘","⠤","⠂","⠀"]],
89 | '}' => [["⠈","⢆","⠀","⠀"],["⠠","⠃","⠀","⠀"]],
90 | '1' => [["⠐","⡇","⠀","⠀"],["⠠","⠧","⠀","⠀"]],
91 | 'S' => [["⠰","⣉","⠁","⠀"],["⠠","⠤","⠃","⠀"]],
92 | '*' => [["⢐","⣔","⠀","⠀"],["⠐","⠑","⠀","⠀"]],
93 | 'f' => [["⢰","⣉","⠂","⠀"],["⠸","⠀","⠀","⠀"]],
94 | 'K' => [["⢸","⡠","⠃","⠀"],["⠸","⠈","⠆","⠀"]],
95 | '\'' => [["⠠","⠃","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
96 | "©" => [["⣎","⠍","⡆","⠀"],["⢏","⣂","⠇","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Area51 Serif Bold.grf:
--------------------------------------------------------------------------------
1 | {':' => [["⠀","⣤","⠀","⠀"],["⠀","⠶","⠀","⠀"]],
2 | '\\' => [["⠘","⣧","⠀","⠀"],["⠀","⠹","⠆","⠀"]],
3 | '=' => [["⠠","⠤","⠄","⠀"],["⠈","⠉","⠁","⠀"]],
4 | 'E' => [["⢸","⣏","⠃","⠀"],["⠸","⠧","⠆","⠀"]],
5 | '(' => [["⢠","⡎","⠀","⠀"],["⠈","⠣","⠀","⠀"]],
6 | '-' => [["⢀","⣀","⡀","⠀"],["⠀","⠀","⠀","⠀"]],
7 | 'm' => [["⢠","⣀","⡄","⠀"],["⠸","⠇","⠇","⠀"]],
8 | '@' => [["⢰","⡯","⡆","⠀"],["⠘","⠯","⠅","⠀"]],
9 | 'o' => [["⢀","⡤","⡀","⠀"],["⠘","⠧","⠃","⠀"]],
10 | 'N' => [["⢸","⡦","⡇","⠀"],["⠸","⠇","⠇","⠀"]],
11 | '/' => [["⠀","⣼","⠃","⠀"],["⠰","⠏","⠀","⠀"]],
12 | 'p' => [["⢠","⡤","⡀","⠀"],["⢸","⡗","⠁","⠀"]],
13 | 'c' => [["⢀","⡤","⡄","⠀"],["⠘","⠧","⠄","⠀"]],
14 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⡀","⠀"]],
15 | '?' => [["⠘","⣹","⠆","⠀"],["⠨","⠅","⠀","⠀"]],
16 | 'L' => [["⢸","⡇","⠀","⠀"],["⠸","⠧","⠆","⠀"]],
17 | 'F' => [["⢸","⣏","⠃","⠀"],["⠸","⠇","⠀","⠀"]],
18 | 'M' => [["⢸","⡖","⡇","⠀"],["⠸","⠇","⠇","⠀"]],
19 | 'l' => [["⠈","⣿","⠀","⠀"],["⠠","⠿","⠄","⠀"]],
20 | '[' => [["⢸","⡏","⠀","⠀"],["⠸","⠧","⠀","⠀"]],
21 | 'W' => [["⢸","⡇","⡇","⠀"],["⠸","⠓","⠇","⠀"]],
22 | 'n' => [["⢠","⡤","⡀","⠀"],["⠸","⠇","⠇","⠀"]],
23 | 'R' => [["⢸","⣏","⠆","⠀"],["⠸","⠇","⠇","⠀"]],
24 | 'info' => ' Area51 Serif Bold font from https://damieng.com/zx-origins','}' => [["⠈","⢷","⡀","⠀"],["⠠","⠟","⠀","⠀"]],
25 | '1' => [["⠐","⣿","⠀","⠀"],["⠠","⠿","⠄","⠀"]],
26 | 'C' => [["⢰","⡏","⠃","⠀"],["⠘","⠧","⠆","⠀"]],
27 | 'K' => [["⢸","⡧","⠃","⠀"],["⠸","⠏","⠆","⠀"]],
28 | '\'' => [["⠰","⠃","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
29 | "©" => [["⣎","⡭","⢱","⠀"],["⢏","⣓","⡸","⠀"]],
30 | 'S' => [["⠰","⣏","⠃","⠀"],["⠰","⠼","⠃","⠀"]],
31 | '*' => [["⢐","⣴","⡂","⠀"],["⠐","⠋","⠂","⠀"]],
32 | 'f' => [["⢰","⣏","⠃","⠀"],["⠸","⠇","⠀","⠀"]],
33 | '+' => [["⢀","⣶","⡀","⠀"],["⠀","⠛","⠀","⠀"]],
34 | 'x' => [["⢠","⡄","⡄","⠀"],["⠰","⠹","⠆","⠀"]],
35 | 's' => [["⢀","⡤","⠄","⠀"],["⠠","⠽","⠂","⠀"]],
36 | 'u' => [["⢠","⢠","⡄","⠀"],["⠘","⠼","⠇","⠀"]],
37 | '{' => [["⢀","⡾","⠁","⠀"],["⠀","⠻","⠄","⠀"]],
38 | 'j' => [["⠀","⢬","⡅","⠀"],["⢠","⣸","⠇","⠀"]],
39 | 'd' => [["⢀","⢽","⡇","⠀"],["⠘","⠼","⠇","⠀"]],
40 | 'T' => [["⠈","⣿","⠁","⠀"],["⠀","⠿","⠀","⠀"]],
41 | '5' => [["⢸","⣏","⠃","⠀"],["⠐","⠼","⠃","⠀"]],
42 | '3' => [["⠘","⣹","⠇","⠀"],["⠐","⠼","⠃","⠀"]],
43 | 'y' => [["⢠","⢠","⡄","⠀"],["⢠","⠟","⠀","⠀"]],
44 | '8' => [["⠰","⣏","⠆","⠀"],["⠘","⠼","⠃","⠀"]],
45 | '~' => [["⠰","⠢","⠆","⠀"],["⠀","⠀","⠀","⠀"]],
46 | '#' => [["⢰","⡦","⡆","⠀"],["⠸","⠗","⠇","⠀"]],
47 | '"' => [["⠰","⠳","⠃","⠀"],["⠀","⠀","⠀","⠀"]],
48 | ')' => [["⠈","⣦","⠀","⠀"],["⠠","⠋","⠀","⠀"]],
49 | 't' => [["⢸","⡧","⠀","⠀"],["⠘","⠧","⠆","⠀"]],
50 | 'z' => [["⠠","⣤","⠀","⠀"],["⠰","⠧","⠀","⠀"]],
51 | '^' => [["⠐","⣿","⠂","⠀"],["⠀","⠿","⠀","⠀"]],
52 | 'B' => [["⢸","⣏","⠆","⠀"],["⠸","⠧","⠃","⠀"]],
53 | 'k' => [["⢸","⣇","⠄","⠀"],["⠸","⠗","⠄","⠀"]],
54 | ';' => [["⠀","⣤","⠀","⠀"],["⠀","⡴","⠀","⠀"]],
55 | '$' => [["⠠","⣞","⠆","⠀"],["⠰","⡽","⠂","⠀"]],
56 | 'D' => [["⢸","⡏","⡆","⠀"],["⠸","⠧","⠃","⠀"]],
57 | 'h' => [["⢸","⡧","⡀","⠀"],["⠸","⠇","⠇","⠀"]],
58 | 'g' => [["⢀","⢤","⡄","⠀"],["⠈","⣺","⠇","⠀"]],
59 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
60 | 'V' => [["⢸","⡇","⡇","⠀"],["⠸","⠗","⠁","⠀"]],
61 | 'Y' => [["⠸","⣸","⡇","⠀"],["⠀","⠿","⠀","⠀"]],
62 | 'P' => [["⢸","⣏","⠆","⠀"],["⠸","⠇","⠀","⠀"]],
63 | 'G' => [["⢰","⡏","⡃","⠀"],["⠘","⠧","⠇","⠀"]],
64 | 'v' => [["⢠","⡄","⣤","⠀"],["⠀","⠻","⠃","⠀"]],
65 | 'O' => [["⢰","⡏","⡆","⠀"],["⠘","⠧","⠃","⠀"]],
66 | '!' => [["⠀","⣿","⠀","⠀"],["⠀","⠭","⠀","⠀"]],
67 | '.' => [["⠀","⠀","⠀","⠀"],["⠰","⠆","⠀","⠀"]],
68 | 'q' => [["⢀","⢤","⡄","⠀"],["⠈","⢺","⡇","⠀"]],
69 | '&' => [["⠰","⣏","⡃","⠀"],["⠘","⠯","⠆","⠀"]],
70 | '4' => [["⢀","⢾","⡇","⠀"],["⠈","⠽","⠇","⠀"]],
71 | 'A' => [["⢰","⣏","⡆","⠀"],["⠸","⠇","⠇","⠀"]],
72 | 'H' => [["⢸","⣇","⡇","⠀"],["⠸","⠇","⠇","⠀"]],
73 | ']' => [["⠈","⣿","⠀","⠀"],["⠠","⠿","⠀","⠀"]],
74 | 'Z' => [["⠘","⣹","⠇","⠀"],["⠸","⠧","⠆","⠀"]],
75 | 'e' => [["⢀","⡤","⡀","⠀"],["⠘","⠯","⠅","⠀"]],
76 | '6' => [["⢠","⣞","⠀","⠀"],["⠘","⠧","⠃","⠀"]],
77 | 'b' => [["⢸","⡧","⡀","⠀"],["⠸","⠧","⠃","⠀"]],
78 | 'Q' => [["⢰","⡏","⡆","⠀"],["⠘","⠷","⡅","⠀"]],
79 | 'J' => [["⠀","⢹","⡇","⠀"],["⠸","⠼","⠃","⠀"]],
80 | '0' => [["⢰","⡏","⡆","⠀"],["⠘","⠧","⠃","⠀"]],
81 | 'w' => [["⢠","⡄","⡄","⠀"],["⠸","⠓","⠇","⠀"]],
82 | 'i' => [["⠠","⣭","⠀","⠀"],["⠠","⠿","⠄","⠀"]],
83 | "£" => [["⢰","⣏","⠃","⠀"],["⠸","⠧","⠆","⠀"]],
84 | '%' => [["⠰","⣠","⠆","⠀"],["⠰","⠋","⠆","⠀"]],
85 | 'I' => [["⠈","⣿","⠁","⠀"],["⠠","⠿","⠄","⠀"]],
86 | 'X' => [["⠸","⣇","⠇","⠀"],["⠸","⠸","⠇","⠀"]],
87 | 'r' => [["⢠","⣄","⡄","⠀"],["⠸","⠇","⠀","⠀"]],
88 | 'U' => [["⢸","⡇","⡇","⠀"],["⠘","⠧","⠃","⠀"]],
89 | '|' => [["⠀","⣿","⠀","⠀"],["⠀","⠿","⠀","⠀"]],
90 | '<' => [["⢀","⡴","⠂","⠀"],["⠀","⠙","⠂","⠀"]],
91 | '9' => [["⠰","⣹","⡆","⠀"],["⠀","⠾","⠁","⠀"]],
92 | '7' => [["⢘","⣹","⠇","⠀"],["⠰","⠏","⠀","⠀"]],
93 | 'a' => [["⠀","⢤","⡀","⠀"],["⠐","⠽","⠇","⠀"]],
94 | ',' => [["⠀","⠀","⠀","⠀"],["⢠","⠆","⠀","⠀"]],
95 | '>' => [["⠐","⢦","⡀","⠀"],["⠐","⠋","⠀","⠀"]],
96 | '2' => [["⠘","⣹","⠆","⠀"],["⠸","⠧","⠄","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Area51.grf:
--------------------------------------------------------------------------------
1 | {'C' => [["⢰","⠉","⠂","⠀"],["⠘","⠤","⠂","⠀"]],
2 | '}' => [["⠈","⢆","⠀","⠀"],["⠠","⠃","⠀","⠀"]],
3 | '1' => [["⠐","⡇","⠀","⠀"],["⠠","⠧","⠀","⠀"]],
4 | 'S' => [["⠰","⣉","⠁","⠀"],["⠠","⠤","⠃","⠀"]],
5 | '*' => [["⢐","⣔","⠀","⠀"],["⠐","⠑","⠀","⠀"]],
6 | 'f' => [["⢰","⣉","⠂","⠀"],["⠸","⠀","⠀","⠀"]],
7 | '\'' => [["⠠","⠃","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
8 | 'K' => [["⢸","⡠","⠃","⠀"],["⠸","⠈","⠆","⠀"]],
9 | "©" => [["⣎","⠍","⡆","⠀"],["⢏","⣂","⠇","⠀"]],
10 | 'F' => [["⢸","⣉","⠁","⠀"],["⠸","⠀","⠀","⠀"]],
11 | 'M' => [["⢸","⠒","⡇","⠀"],["⠸","⠀","⠇","⠀"]],
12 | 'l' => [["⠈","⡇","⠀","⠀"],["⠀","⠧","⠀","⠀"]],
13 | '[' => [["⢸","⠉","⠀","⠀"],["⠸","⠤","⠀","⠀"]],
14 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⡀","⠀"]],
15 | 'c' => [["⢀","⠤","⡀","⠀"],["⠘","⠤","⠂","⠀"]],
16 | 'L' => [["⢸","⠀","⠀","⠀"],["⠸","⠤","⠄","⠀"]],
17 | '?' => [["⠐","⢉","⠆","⠀"],["⠀","⠅","⠀","⠀"]],
18 | 'info' => ' Area51 font from https://damieng.com/zx-origins','R' => [["⢸","⣉","⠆","⠀"],["⠸","⠈","⠆","⠀"]],
19 | 'W' => [["⢸","⠀","⡇","⠀"],["⠸","⠒","⠇","⠀"]],
20 | 'n' => [["⢠","⠤","⡀","⠀"],["⠸","⠀","⠇","⠀"]],
21 | '@' => [["⢰","⡩","⡆","⠀"],["⠘","⠬","⠅","⠀"]],
22 | 'm' => [["⢠","⣀","⡄","⠀"],["⠸","⠀","⠇","⠀"]],
23 | '-' => [["⢀","⣀","⡀","⠀"],["⠀","⠀","⠀","⠀"]],
24 | 'p' => [["⢠","⠤","⡀","⠀"],["⢸","⠒","⠁","⠀"]],
25 | 'N' => [["⢸","⠢","⡇","⠀"],["⠸","⠀","⠇","⠀"]],
26 | 'o' => [["⢀","⠤","⡀","⠀"],["⠘","⠤","⠃","⠀"]],
27 | '/' => [["⠀","⡰","⠁","⠀"],["⠰","⠁","⠀","⠀"]],
28 | '\\' => [["⠈","⢆","⠀","⠀"],["⠀","⠈","⠆","⠀"]],
29 | ':' => [["⠀","⡄","⠀","⠀"],["⠀","⠆","⠀","⠀"]],
30 | 'E' => [["⢸","⣉","⠁","⠀"],["⠸","⠤","⠄","⠀"]],
31 | '(' => [["⢠","⠊","⠀","⠀"],["⠈","⠢","⠀","⠀"]],
32 | '=' => [["⠠","⠤","⠄","⠀"],["⠈","⠉","⠁","⠀"]],
33 | ';' => [["⠀","⡄","⠀","⠀"],["⢀","⠆","⠀","⠀"]],
34 | 'k' => [["⢸","⢀","⠄","⠀"],["⠸","⠑","⠄","⠀"]],
35 | 'h' => [["⢸","⠤","⡀","⠀"],["⠸","⠀","⠇","⠀"]],
36 | '$' => [["⠠","⡚","⠄","⠀"],["⠐","⡬","⠂","⠀"]],
37 | 'D' => [["⢸","⠉","⡆","⠀"],["⠸","⠤","⠃","⠀"]],
38 | '^' => [["⠐","⡗","⠀","⠀"],["⠀","⠇","⠀","⠀"]],
39 | '"' => [["⠠","⠣","⠃","⠀"],["⠀","⠀","⠀","⠀"]],
40 | '#' => [["⢰","⠤","⡆","⠀"],["⠸","⠒","⠇","⠀"]],
41 | ')' => [["⠈","⢢","⠀","⠀"],["⠠","⠊","⠀","⠀"]],
42 | 'z' => [["⠠","⢤","⠀","⠀"],["⠰","⠥","⠀","⠀"]],
43 | 't' => [["⢸","⠤","⠀","⠀"],["⠘","⠤","⠂","⠀"]],
44 | 'B' => [["⢸","⣉","⠆","⠀"],["⠸","⠤","⠃","⠀"]],
45 | 'y' => [["⢠","⠀","⡄","⠀"],["⠈","⣒","⠇","⠀"]],
46 | '8' => [["⠰","⣉","⠆","⠀"],["⠘","⠤","⠃","⠀"]],
47 | '~' => [["⠠","⠢","⠂","⠀"],["⠀","⠀","⠀","⠀"]],
48 | '3' => [["⠈","⣩","⠃","⠀"],["⠐","⠤","⠃","⠀"]],
49 | '{' => [["⢀","⠎","⠀","⠀"],["⠀","⠣","⠀","⠀"]],
50 | 'u' => [["⢠","⠀","⡄","⠀"],["⠘","⠤","⠇","⠀"]],
51 | 'x' => [["⢠","⠀","⡄","⠀"],["⠰","⠉","⠆","⠀"]],
52 | '+' => [["⢀","⣆","⠀","⠀"],["⠀","⠃","⠀","⠀"]],
53 | 's' => [["⢀","⠤","⠄","⠀"],["⠠","⠭","⠂","⠀"]],
54 | '5' => [["⢸","⣉","⠁","⠀"],["⠠","⠤","⠃","⠀"]],
55 | 'j' => [["⠀","⠀","⡅","⠀"],["⠰","⣀","⠇","⠀"]],
56 | 'd' => [["⢀","⠤","⡇","⠀"],["⠘","⠤","⠇","⠀"]],
57 | 'T' => [["⠈","⡏","⠀","⠀"],["⠀","⠇","⠀","⠀"]],
58 | 'A' => [["⢰","⣉","⡆","⠀"],["⠸","⠀","⠇","⠀"]],
59 | 'H' => [["⢸","⣀","⡇","⠀"],["⠸","⠀","⠇","⠀"]],
60 | ']' => [["⠈","⢹","⠀","⠀"],["⠠","⠼","⠀","⠀"]],
61 | '6' => [["⢠","⣊","⠀","⠀"],["⠘","⠤","⠃","⠀"]],
62 | 'b' => [["⢸","⠤","⡀","⠀"],["⠸","⠤","⠃","⠀"]],
63 | 'Z' => [["⠈","⡩","⠃","⠀"],["⠸","⠤","⠄","⠀"]],
64 | 'e' => [["⢀","⠤","⡀","⠀"],["⠘","⠭","⠅","⠀"]],
65 | '4' => [["⢀","⠎","⡇","⠀"],["⠈","⠉","⠇","⠀"]],
66 | '&' => [["⠰","⣉","⡄","⠀"],["⠘","⠤","⠇","⠀"]],
67 | '!' => [["⠀","⡇","⠀","⠀"],["⠀","⠅","⠀","⠀"]],
68 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠆","⠀","⠀"]],
69 | 'O' => [["⢰","⠉","⡆","⠀"],["⠘","⠤","⠃","⠀"]],
70 | 'q' => [["⢀","⠤","⡄","⠀"],["⠈","⠒","⡇","⠀"]],
71 | 'V' => [["⢸","⠀","⡇","⠀"],["⠸","⠔","⠁","⠀"]],
72 | 'g' => [["⢀","⠤","⡄","⠀"],["⠈","⣒","⠇","⠀"]],
73 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
74 | 'Y' => [["⠸","⣀","⡇","⠀"],["⠠","⠤","⠃","⠀"]],
75 | 'P' => [["⢸","⣉","⠆","⠀"],["⠸","⠀","⠀","⠀"]],
76 | 'G' => [["⢰","⢉","⡁","⠀"],["⠘","⠤","⠇","⠀"]],
77 | 'v' => [["⢠","⠀","⡄","⠀"],["⠸","⠔","⠁","⠀"]],
78 | ',' => [["⠀","⠀","⠀","⠀"],["⢀","⠆","⠀","⠀"]],
79 | 'a' => [["⠀","⠤","⡀","⠀"],["⠐","⠭","⠇","⠀"]],
80 | '2' => [["⠈","⢉","⠆","⠀"],["⠰","⠥","⠄","⠀"]],
81 | '>' => [["⠐","⢄","⠀","⠀"],["⠐","⠁","⠀","⠀"]],
82 | '|' => [["⠀","⡇","⠀","⠀"],["⠀","⠇","⠀","⠀"]],
83 | '<' => [["⢀","⠔","⠀","⠀"],["⠀","⠑","⠀","⠀"]],
84 | 'I' => [["⠈","⡏","⠀","⠀"],["⠠","⠧","⠀","⠀"]],
85 | 'X' => [["⠸","⣀","⠇","⠀"],["⠸","⠀","⠇","⠀"]],
86 | 'r' => [["⢠","⡠","⠄","⠀"],["⠸","⠀","⠀","⠀"]],
87 | 'U' => [["⢸","⠀","⡇","⠀"],["⠘","⠤","⠃","⠀"]],
88 | '9' => [["⠰","⣉","⡆","⠀"],["⠀","⠔","⠁","⠀"]],
89 | '7' => [["⠈","⢉","⠇","⠀"],["⠀","⠎","⠀","⠀"]],
90 | 'w' => [["⢠","⠀","⡄","⠀"],["⠸","⠒","⠇","⠀"]],
91 | "£" => [["⢰","⣉","⠂","⠀"],["⠸","⠤","⠄","⠀"]],
92 | 'i' => [["⠠","⡅","⠀","⠀"],["⠀","⠧","⠀","⠀"]],
93 | 'J' => [["⠀","⠀","⡇","⠀"],["⠘","⠤","⠃","⠀"]],
94 | '0' => [["⢰","⠉","⡆","⠀"],["⠘","⠤","⠃","⠀"]],
95 | '%' => [["⠰","⢀","⠆","⠀"],["⠰","⠁","⠆","⠀"]],
96 | 'Q' => [["⢰","⠉","⡆","⠀"],["⠘","⠔","⠅","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Cinema Bold.grf:
--------------------------------------------------------------------------------
1 | {'l' => [["⠀","⢹","⣿","⠀"],["⠀","⠸","⠿","⠀"]],
2 | '[' => [["⢸","⣿","⠉","⠀"],["⠸","⠿","⠤","⠀"]],
3 | 'M' => [["⣿","⣦","⣴","⡇"],["⠿","⠏","⠹","⠇"]],
4 | 'F' => [["⣿","⣏","⡉","⠁"],["⠿","⠇","⠀","⠀"]],
5 | 'L' => [["⣿","⡇","⠀","⠀"],["⠿","⠧","⠤","⠄"]],
6 | '?' => [["⠚","⢉","⣿","⠆"],["⠀","⠶","⠆","⠀"]],
7 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
8 | 'c' => [["⣠","⡤","⢤","⡀"],["⠻","⠧","⠴","⠂"]],
9 | 'info' => ' Cinema Bold font ','R' => [["⣿","⣏","⣹","⠆"],["⠿","⠇","⠹","⠆"]],
10 | 'n' => [["⣤","⡤","⢤","⡀"],["⠿","⠇","⠸","⠇"]],
11 | 'W' => [["⣿","⣇","⣸","⡇"],["⠿","⠋","⠙","⠇"]],
12 | 'C' => [["⣾","⡏","⠙","⠂"],["⠻","⠧","⠴","⠂"]],
13 | '}' => [["⠉","⢿","⣆","⡀"],["⠤","⠿","⠃","⠀"]],
14 | '1' => [["⠐","⣿","⡇","⠀"],["⠠","⠿","⠧","⠀"]],
15 | 'S' => [["⢾","⣏","⣙","⠂"],["⠲","⠦","⠼","⠃"]],
16 | 'f' => [["⣰","⣿","⡙","⠂"],["⠸","⠿","⠀","⠀"]],
17 | '*' => [["⢤","⣶","⣦","⠄"],["⠉","⠛","⠋","⠁"]],
18 | '\'' => [["⠠","⠿","⠃","⠀"],["⠀","⠀","⠀","⠀"]],
19 | 'K' => [["⣿","⣇","⡼","⠃"],["⠿","⠇","⠹","⠆"]],
20 | "©" => [["⡔","⣩","⡭","⢢"],["⠣","⣙","⣓","⠜"]],
21 | '\\' => [["⠻","⣷","⣄","⠀"],["⠀","⠈","⠻","⠷"]],
22 | ':' => [["⠀","⣤","⡄","⠀"],["⠀","⠶","⠆","⠀"]],
23 | '(' => [["⢠","⣾","⠋","⠁"],["⠈","⠻","⠦","⠄"]],
24 | 'E' => [["⣿","⣏","⡉","⠁"],["⠿","⠧","⠤","⠄"]],
25 | '=' => [["⠠","⠤","⠤","⠄"],["⠈","⠉","⠉","⠁"]],
26 | '@' => [["⣾","⡏","⣽","⡆"],["⠻","⠧","⠭","⠅"]],
27 | 'm' => [["⣤","⣄","⣤","⡀"],["⠿","⠸","⠇","⠇"]],
28 | '-' => [["⠀","⠀","⠀","⠀"],["⠈","⠉","⠉","⠁"]],
29 | 'p' => [["⣤","⡤","⢤","⡀"],["⣿","⡗","⠚","⠁"]],
30 | '/' => [["⠀","⣠","⣾","⠟"],["⠾","⠟","⠁","⠀"]],
31 | 'o' => [["⣠","⡤","⢤","⡀"],["⠻","⠧","⠼","⠃"]],
32 | 'N' => [["⣿","⣦","⣸","⡇"],["⠿","⠏","⠻","⠇"]],
33 | '^' => [["⣠","⣾","⣦","⡀"],["⠀","⠿","⠇","⠀"]],
34 | '"' => [["⠿","⠃","⠿","⠃"],["⠀","⠀","⠀","⠀"]],
35 | '#' => [["⢾","⡷","⣿","⠆"],["⠻","⠟","⠿","⠃"]],
36 | 'z' => [["⠤","⢤","⣤","⠄"],["⠴","⠿","⠥","⠄"]],
37 | ')' => [["⠈","⠙","⣷","⡄"],["⠠","⠴","⠟","⠁"]],
38 | 't' => [["⢼","⣿","⠤","⠀"],["⠘","⠿","⠤","⠄"]],
39 | 'B' => [["⣿","⣏","⣹","⠆"],["⠿","⠧","⠼","⠃"]],
40 | ';' => [["⠀","⣤","⡄","⠀"],["⢀","⣶","⠆","⠀"]],
41 | 'k' => [["⣿","⡇","⣠","⠄"],["⠿","⠏","⠳","⠄"]],
42 | 'h' => [["⣿","⡧","⢤","⡀"],["⠿","⠇","⠸","⠇"]],
43 | 'D' => [["⣿","⡏","⢳","⡄"],["⠿","⠧","⠞","⠁"]],
44 | '$' => [["⢴","⣞","⣓","⠂"],["⠒","⠶","⠛","⠁"]],
45 | '{' => [["⣀","⣾","⠏","⠁"],["⠀","⠻","⠧","⠄"]],
46 | 'u' => [["⣤","⠀","⣤","⡄"],["⠻","⠤","⠿","⠇"]],
47 | 's' => [["⣠","⡤","⠤","⠄"],["⠬","⠭","⠿","⠂"]],
48 | 'x' => [["⢤","⣄","⣠","⠄"],["⠴","⠛","⠷","⠄"]],
49 | '+' => [["⣀","⣶","⣆","⡀"],["⠀","⠛","⠃","⠀"]],
50 | '5' => [["⠿","⠭","⣭","⡁"],["⠲","⠤","⠿","⠃"]],
51 | 'T' => [["⠉","⣿","⡏","⠁"],["⠀","⠿","⠇","⠀"]],
52 | 'd' => [["⣠","⠤","⣿","⡇"],["⠻","⠤","⠿","⠇"]],
53 | 'j' => [["⠀","⠀","⣭","⡅"],["⢤","⣀","⣿","⠇"]],
54 | '~' => [["⠞","⠻","⠶","⠃"],["⠀","⠀","⠀","⠀"]],
55 | 'y' => [["⣤","⠀","⣤","⡄"],["⢙","⣒","⣿","⠇"]],
56 | '8' => [["⢾","⣏","⣹","⠆"],["⠻","⠧","⠼","⠃"]],
57 | '3' => [["⠚","⣉","⣿","⠆"],["⠲","⠤","⠿","⠃"]],
58 | '4' => [["⣴","⢻","⣿","⠀"],["⠉","⠹","⠿","⠁"]],
59 | '&' => [["⢾","⣏","⣷","⡀"],["⠻","⠧","⠿","⠄"]],
60 | ']' => [["⠈","⢹","⣿","⠀"],["⠠","⠼","⠿","⠀"]],
61 | 'A' => [["⣴","⡟","⢳","⡄"],["⠿","⠏","⠹","⠇"]],
62 | 'H' => [["⣿","⣇","⣸","⡇"],["⠿","⠇","⠸","⠇"]],
63 | 'b' => [["⣿","⡧","⢤","⡀"],["⠿","⠧","⠼","⠃"]],
64 | '6' => [["⣴","⣟","⣁","⠀"],["⠻","⠧","⠼","⠃"]],
65 | 'e' => [["⣠","⡤","⢤","⡀"],["⠻","⠯","⠭","⠅"]],
66 | 'Z' => [["⠉","⣩","⡿","⠃"],["⠾","⠯","⠤","⠄"]],
67 | 'V' => [["⣿","⡇","⢸","⡇"],["⠙","⠷","⠞","⠁"]],
68 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
69 | 'g' => [["⣠","⠤","⣤","⡄"],["⢙","⣒","⣿","⠇"]],
70 | 'Y' => [["⢿","⣇","⣸","⠇"],["⠠","⠟","⠁","⠀"]],
71 | 'G' => [["⣾","⡏","⣉","⡁"],["⠻","⠧","⠿","⠇"]],
72 | 'P' => [["⣿","⡏","⢹","⡆"],["⠿","⠏","⠉","⠀"]],
73 | 'v' => [["⣤","⡄","⢠","⡄"],["⠙","⠷","⠟","⠁"]],
74 | '!' => [["⠀","⣿","⡇","⠀"],["⠀","⠶","⠆","⠀"]],
75 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠶","⠆","⠀"]],
76 | 'O' => [["⣾","⡏","⢹","⡆"],["⠻","⠧","⠼","⠃"]],
77 | 'q' => [["⣠","⠤","⣤","⡄"],["⠙","⠒","⣿","⡇"]],
78 | '<' => [["⢀","⣴","⠟","⠁"],["⠀","⠙","⠷","⠄"]],
79 | '|' => [["⠀","⣿","⡇","⠀"],["⠀","⠿","⠇","⠀"]],
80 | 'r' => [["⣤","⡤","⢤","⡀"],["⠿","⠇","⠀","⠀"]],
81 | 'U' => [["⣿","⡇","⢸","⡇"],["⠻","⠧","⠼","⠃"]],
82 | 'I' => [["⠈","⣿","⡏","⠀"],["⠠","⠿","⠧","⠀"]],
83 | 'X' => [["⠻","⣧","⡼","⠃"],["⠾","⠉","⠿","⠆"]],
84 | '9' => [["⢾","⣉","⣿","⡆"],["⠠","⠾","⠋","⠀"]],
85 | '7' => [["⠉","⢉","⣿","⠇"],["⠀","⠿","⠇","⠀"]],
86 | ',' => [["⠀","⠀","⠀","⠀"],["⢀","⣶","⠆","⠀"]],
87 | 'a' => [["⠠","⠤","⣤","⡀"],["⠺","⠭","⠿","⠇"]],
88 | '2' => [["⠚","⢉","⣿","⠆"],["⠴","⠿","⠥","⠄"]],
89 | '>' => [["⠈","⠻","⣦","⡀"],["⠠","⠾","⠋","⠀"]],
90 | 'Q' => [["⣾","⡏","⢹","⡆"],["⠻","⠧","⠻","⠆"]],
91 | 'w' => [["⣤","⢀","⢠","⡄"],["⠻","⠟","⠿","⠃"]],
92 | 'i' => [["⠀","⣭","⡅","⠀"],["⠀","⠿","⠇","⠀"]],
93 | "£" => [["⣰","⣿","⣙","⠂"],["⠼","⠿","⠤","⠄"]],
94 | '0' => [["⣴","⡏","⢳","⡄"],["⠙","⠧","⠞","⠁"]],
95 | 'J' => [["⠀","⠀","⣿","⡇"],["⠲","⠤","⠿","⠃"]],
96 | '%' => [["⠺","⣢","⡾","⠂"],["⠺","⠋","⠺","⠂"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Computer.grf:
--------------------------------------------------------------------------------
1 | {'W' => [["⣿","⠘","⠃","⡇"],["⠿","⠊","⠑","⠇"]],
2 | 'm' => [["⢠","⢄","⢤","⡄"],["⠸","⠰","⠸","⠇"]],
3 | '@' => [["⢠","⢊","⡭","⡆"],["⠘","⠬","⠭","⠁"]],
4 | '\\' => [["⠘","⢦","⡀","⠀"],["⠀","⠀","⠙","⠆"]],
5 | '"' => [["⠘","⠇","⠻","⠀"],["⠀","⠀","⠀","⠀"]],
6 | ']' => [["⠀","⠉","⣹","⠀"],["⠀","⠤","⠿","⠀"]],
7 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
8 | 'q' => [["⢠","⠤","⣤","⠀"],["⠘","⠒","⣿","⠀"]],
9 | 'f' => [["⢀","⣿","⣉","⠀"],["⠀","⠿","⠀","⠀"]],
10 | 'N' => [["⢸","⠑","⢄","⡇"],["⠸","⠰","⠆","⠇"]],
11 | '9' => [["⢸","⣉","⣹","⠀"],["⠀","⠀","⠿","⠀"]],
12 | 'G' => [["⢸","⡏","⣙","⡃"],["⠸","⠧","⠤","⠇"]],
13 | 'J' => [["⠀","⠀","⢸","⡀"],["⠰","⠦","⠼","⠇"]],
14 | '7' => [["⠘","⠉","⡹","⠀"],["⠀","⠸","⠀","⠀"]],
15 | '6' => [["⢸","⠙","⠀","⠀"],["⠸","⠭","⠽","⠀"]],
16 | 'C' => [["⢸","⠉","⠿","⠀"],["⠸","⠤","⠼","⠀"]],
17 | 'h' => [["⢸","⡧","⢤","⠀"],["⠸","⠇","⠸","⠀"]],
18 | 'y' => [["⢠","⠀","⣤","⠀"],["⢘","⣒","⣿","⠀"]],
19 | 'n' => [["⢠","⡤","⠤","⡄"],["⠸","⠇","⠆","⠇"]],
20 | '*' => [["⠠","⣴","⡤","⠀"],["⠈","⠙","⠉","⠀"]],
21 | 'H' => [["⢸","⣇","⣀","⡇"],["⠸","⠇","⠀","⠇"]],
22 | '0' => [["⢰","⢉","⡉","⡇"],["⠸","⠬","⠥","⠃"]],
23 | 'I' => [["⠀","⣸","⠀","⠀"],["⠀","⠿","⠀","⠀"]],
24 | 'x' => [["⢠","⡄","⢠","⠀"],["⠰","⠉","⠷","⠀"]],
25 | 'X' => [["⠘","⢧","⡠","⠃"],["⠰","⠁","⠹","⠆"]],
26 | '3' => [["⠈","⣉","⣇","⠀"],["⠠","⠤","⠿","⠀"]],
27 | 'E' => [["⢸","⣉","⣉","⠀"],["⠸","⠧","⠤","⠀"]],
28 | '-' => [["⢀","⣀","⣀","⡀"],["⠀","⠀","⠀","⠀"]],
29 | 'L' => [["⢀","⡇","⠀","⠀"],["⠸","⠧","⠤","⠀"]],
30 | '|' => [["⠀","⢸","⡇","⠀"],["⠀","⠸","⠇","⠀"]],
31 | 'R' => [["⢸","⣉","⣹","⠀"],["⠸","⠇","⠸","⠇"]],
32 | ':' => [["⠀","⠰","⠆","⠀"],["⠀","⠰","⠆","⠀"]],
33 | '!' => [["⠀","⢸","⡇","⠀"],["⠀","⠨","⠅","⠀"]],
34 | 'T' => [["⠈","⢹","⡏","⠁"],["⠀","⠸","⠇","⠀"]],
35 | 'l' => [["⠀","⢸","⡇","⠀"],["⠀","⠸","⠇","⠀"]],
36 | '^' => [["⢠","⡼","⢤","⠀"],["⠈","⠁","⠈","⠀"]],
37 | 'M' => [["⡏","⠢","⢺","⡇"],["⠇","⠶","⠸","⠇"]],
38 | ';' => [["⠀","⠰","⠆","⠀"],["⠀","⠰","⡆","⠀"]],
39 | 'r' => [["⢠","⡤","⢤","⠀"],["⠸","⠇","⠀","⠀"]],
40 | 't' => [["⠠","⣧","⠄","⠀"],["⠀","⠿","⠀","⠀"]],
41 | 'g' => [["⢠","⠤","⣤","⠀"],["⢘","⣒","⣿","⠀"]],
42 | 'i' => [["⠀","⣭","⠀","⠀"],["⠀","⠿","⠀","⠀"]],
43 | '5' => [["⢸","⣉","⣉","⠀"],["⠠","⠤","⠿","⠀"]],
44 | 'F' => [["⢸","⣏","⣉","⠀"],["⠀","⠇","⠀","⠀"]],
45 | 'U' => [["⢸","⠀","⢸","⡇"],["⠸","⠤","⠼","⠇"]],
46 | 'Z' => [["⠘","⢉","⠝","⠀"],["⠰","⠥","⠶","⠀"]],
47 | '8' => [["⢀","⣏","⣹","⡀"],["⠸","⠧","⠼","⠇"]],
48 | '?' => [["⠸","⢉","⣿","⠀"],["⠀","⠰","⠆","⠀"]],
49 | 'k' => [["⢸","⣇","⣔","⠀"],["⠸","⠇","⠸","⠀"]],
50 | 'S' => [["⢸","⣉","⣙","⠀"],["⠰","⠦","⠼","⠀"]],
51 | '(' => [["⠀","⣴","⠋","⠀"],["⠀","⠙","⠦","⠀"]],
52 | '%' => [["⠿","⢇","⠔","⠁"],["⠔","⠁","⠿","⠇"]],
53 | "£" => [["⢀","⣸","⣙","⠀"],["⠠","⠿","⠤","⠄"]],
54 | '#' => [["⠠","⣶","⢴","⠄"],["⠐","⠗","⠿","⠂"]],
55 | 'j' => [["⠀","⢨","⡅","⠀"],["⢀","⣸","⡇","⠀"]],
56 | 'z' => [["⠠","⠤","⣤","⠀"],["⠰","⠯","⠥","⠀"]],
57 | 'a' => [["⠠","⠤","⣤","⠀"],["⠸","⠭","⠿","⠀"]],
58 | 'B' => [["⢸","⣏","⣹","⡀"],["⠸","⠧","⠤","⠇"]],
59 | 'p' => [["⢠","⡤","⢤","⠀"],["⢸","⡗","⠚","⠀"]],
60 | '}' => [["⠈","⢿","⣀","⠀"],["⠠","⠿","⠀","⠀"]],
61 | '&' => [["⠀","⣯","⠽","⠀"],["⠸","⠧","⠵","⠅"]],
62 | '=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
63 | 'u' => [["⢠","⠀","⣤","⠀"],["⠸","⠤","⠿","⠀"]],
64 | '2' => [["⠀","⣉","⣹","⠀"],["⠀","⠧","⠤","⠀"]],
65 | 'v' => [["⢠","⠀","⣤","⠀"],["⠈","⠢","⠟","⠀"]],
66 | '1' => [["⠀","⢹","⠀","⠀"],["⠀","⠿","⠿","⠀"]],
67 | 'Y' => [["⠘","⢄","⡠","⠃"],["⠀","⠸","⠇","⠀"]],
68 | 'Q' => [["⢸","⡍","⠉","⡇"],["⠸","⠧","⢧","⠇"]],
69 | '[' => [["⠀","⣏","⠉","⠀"],["⠀","⠿","⠤","⠀"]],
70 | 'D' => [["⢸","⡏","⠉","⡆"],["⠸","⠧","⠤","⠃"]],
71 | 'K' => [["⢸","⣠","⣊","⡀"],["⠸","⠇","⠸","⠇"]],
72 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⡆","⠀"]],
73 | 'c' => [["⢠","⠤","⢤","⠀"],["⠸","⠧","⠴","⠀"]],
74 | 'e' => [["⢠","⡤","⢤","⠀"],["⠸","⠯","⠭","⠀"]],
75 | 'A' => [["⢀","⣏","⣉","⡇"],["⠸","⠇","⠀","⠇"]],
76 | '>' => [["⠀","⠲","⣄","⠀"],["⠀","⠚","⠁","⠀"]],
77 | 'o' => [["⢠","⡤","⢤","⠀"],["⠸","⠧","⠼","⠀"]],
78 | '<' => [["⢀","⡴","⠂","⠀"],["⠀","⠙","⠂","⠀"]],
79 | '{' => [["⢀","⣸","⠏","⠀"],["⠀","⠸","⠧","⠀"]],
80 | '$' => [["⢰","⣞","⣒","⠀"],["⠐","⠲","⠚","⠀"]],
81 | 'd' => [["⢠","⠤","⣿","⠀"],["⠸","⠤","⠿","⠀"]],
82 | 'b' => [["⢸","⡧","⢤","⠀"],["⠸","⠧","⠼","⠀"]],
83 | 'w' => [["⢠","⡄","⡄","⡄"],["⠸","⠧","⠢","⠇"]],
84 | "©" => [["⡏","⣭","⢭","⢹"],["⣇","⣛","⣒","⣸"]],
85 | '\'' => [["⠀","⠘","⠇","⠀"],["⠀","⠀","⠀","⠀"]],
86 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠆","⠀"]],
87 | '+' => [["⢀","⣰","⣆","⡀"],["⠀","⠘","⠃","⠀"]],
88 | '4' => [["⢸","⡇","⣀","⠀"],["⠈","⠉","⠿","⠀"]],
89 | 's' => [["⢠","⡤","⠤","⠀"],["⠨","⠭","⠽","⠀"]],
90 | 'P' => [["⢸","⣉","⣹","⠀"],["⠸","⠇","⠀","⠀"]],
91 | 'V' => [["⢸","⠀","⢸","⡇"],["⠈","⠳","⠋","⠀"]],
92 | '/' => [["⠀","⢀","⡴","⠃"],["⠰","⠋","⠀","⠀"]],
93 | 'O' => [["⢸","⠉","⢉","⡇"],["⠸","⠤","⠼","⠇"]],
94 | 'info' => ' Computer font ',')' => [["⠀","⠙","⣦","⠀"],["⠀","⠴","⠋","⠀"]],
95 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
96 | '~' => [["⠸","⠻","⠾","⠀"],["⠀","⠀","⠀","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Coolant.grf:
--------------------------------------------------------------------------------
1 | {'C' => [["⢀","⠔","⠉","⠂"],["⠘","⠤","⠤","⠄"]],
2 | 'a' => [["⠀","⡠","⠤","⠀"],["⠘","⠤","⠚","⠤"]],
3 | 'k' => [["⠀","⡜","⣀","⠀"],["⠼","⠙","⠤","⠤"]],
4 | 'Z' => [["⠉","⢉","⡩","⠃"],["⠮","⠥","⠤","⠤"]],
5 | 'X' => [["⠉","⢆","⡠","⠊"],["⠔","⠁","⠘","⠤"]],
6 | 'o' => [["⠀","⡠","⠤","⡀"],["⠘","⠤","⠔","⠁"]],
7 | 'P' => [["⠉","⣍","⡩","⠂"],["⠜","⠀","⠀","⠀"]],
8 | '$' => [["⠀","⢀","⢴","⠤"],["⠤","⡴","⠕","⠀"]],
9 | '%' => [["⠠","⠖","⡠","⠒"],["⠤","⠊","⠴","⠂"]],
10 | '9' => [["⢠","⠊","⣉","⠆"],["⠤","⠭","⠊","⠀"]],
11 | 'w' => [["⢤","⠀","⡀","⢠"],["⠸","⠊","⠗","⠁"]],
12 | 'x' => [["⠠","⡀","⢀","⠤"],["⠤","⠊","⠑","⠄"]],
13 | 'm' => [["⠀","⣄","⢀","⡄"],["⠼","⠈","⠹","⠤"]],
14 | '>' => [["⠀","⠢","⡀","⠀"],["⠀","⠊","⠀","⠀"]],
15 | '0' => [["⢀","⠔","⠉","⡆"],["⠘","⠤","⠊","⠀"]],
16 | 'r' => [["⠀","⣄","⠤","⡄"],["⠴","⠁","⠒","⠥"]],
17 | 'O' => [["⡠","⠊","⠑","⡄"],["⠣","⠤","⠔","⠁"]],
18 | '*' => [["⠀","⣄","⣆","⠄"],["⠈","⠘","⠈","⠀"]],
19 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠀","⠀"]],
20 | '=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
21 | 'z' => [["⠠","⠤","⢤","⠤"],["⠤","⠮","⠥","⠄"]],
22 | 'I' => [["⠈","⢩","⠂","⠀"],["⠀","⠣","⠤","⠄"]],
23 | 'j' => [["⠀","⠀","⡨","⠤"],["⠢","⠔","⠁","⠀"]],
24 | 'A' => [["⠀","⢠","⢻","⠀"],["⠤","⠋","⠉","⠆"]],
25 | '2' => [["⠀","⠊","⣉","⠆"],["⠰","⠭","⠤","⠀"]],
26 | '|' => [["⠀","⢠","⠃","⠀"],["⠀","⠎","⠀","⠀"]],
27 | '&' => [["⠀","⢎","⡕","⡀"],["⠐","⠥","⠚","⠄"]],
28 | 'h' => [["⠀","⣜","⠤","⡀"],["⠼","⠀","⠰","⠥"]],
29 | '7' => [["⠀","⠉","⡩","⠃"],["⠠","⠊","⠀","⠀"]],
30 | "£" => [["⣀","⣰","⡉","⠂"],["⠴","⠥","⠤","⠄"]],
31 | '{' => [["⠠","⢜","⠉","⠁"],["⠰","⠥","⠄","⠀"]],
32 | 'Q' => [["⡠","⠊","⠑","⡄"],["⠣","⠬","⠕","⠥"]],
33 | '@' => [["⢠","⢒","⢦","⠀"],["⠣","⠤","⠭","⠤"]],
34 | 'G' => [["⡠","⠊","⢑","⣀"],["⠣","⠤","⠬","⠆"]],
35 | 'E' => [["⠩","⣋","⡉","⠀"],["⠪","⠤","⠤","⠤"]],
36 | "©" => [["⢠","⢊","⢭","⢢"],["⠣","⣓","⡢","⠊"]],
37 | '?' => [["⠉","⢉","⡱","⠀"],["⠀","⠂","⠀","⠀"]],
38 | 'T' => [["⠉","⢉","⠏","⠉"],["⠀","⠎","⠀","⠀"]],
39 | '[' => [["⠀","⡜","⠉","⠁"],["⠰","⠥","⠄","⠀"]],
40 | 'J' => [["⠀","⠀","⢰","⠉"],["⠢","⠤","⠃","⠀"]],
41 | '3' => [["⠀","⠩","⡝","⠁"],["⠢","⠤","⠜","⠀"]],
42 | 'V' => [["⠉","⡇","⠀","⡜"],["⠀","⠧","⠊","⠀"]],
43 | 'S' => [["⠐","⢍","⠉","⠉"],["⠤","⠤","⠕","⠀"]],
44 | '4' => [["⢀","⠎","⡰","⠀"],["⠈","⠩","⠋","⠀"]],
45 | 'b' => [["⠀","⣜","⠤","⡀"],["⠬","⠤","⠔","⠁"]],
46 | 'K' => [["⠈","⣇","⠔","⠁"],["⠜","⠀","⠑","⠤"]],
47 | 'Y' => [["⠉","⢆","⡠","⠊"],["⠔","⠁","⠀","⠀"]],
48 | ';' => [["⠀","⠠","⠀","⠀"],["⠀","⠔","⠀","⠀"]],
49 | '\'' => [["⠀","⠜","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
50 | '8' => [["⠀","⢎","⡩","⠂"],["⠐","⠥","⠜","⠀"]],
51 | 'F' => [["⠠","⣊","⡉","⠉"],["⠜","⠀","⠀","⠀"]],
52 | '+' => [["⢀","⣀","⣆","⡀"],["⠀","⠘","⠀","⠀"]],
53 | 'f' => [["⠀","⣀","⣔","⠒"],["⠤","⠜","⠀","⠀"]],
54 | 'g' => [["⠀","⡠","⠤","⠤"],["⢀","⣑","⡪","⠃"]],
55 | 'info' => ' Coolant font ','i' => [["⠤","⠤","⡌","⠀"],["⠀","⠪","⠤","⠤"]],
56 | 'd' => [["⠀","⡠","⢄","⡜"],["⠘","⠤","⠤","⠅"]],
57 | 'n' => [["⠀","⣄","⠤","⡀"],["⠼","⠀","⠰","⠥"]],
58 | ':' => [["⠀","⠠","⠀","⠀"],["⠀","⠐","⠀","⠀"]],
59 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
60 | 'R' => [["⠉","⣍","⡩","⠂"],["⠜","⠀","⠑","⠤"]],
61 | 't' => [["⠤","⢤","⠧","⠄"],["⠀","⠣","⠤","⠤"]],
62 | '"' => [["⠠","⠃","⠜","⠀"],["⠀","⠀","⠀","⠀"]],
63 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
64 | 'l' => [["⠉","⢉","⠆","⠀"],["⠀","⠪","⠤","⠤"]],
65 | 's' => [["⠀","⢀","⠤","⠤"],["⠤","⠤","⠕","⠀"]],
66 | 'v' => [["⠤","⡀","⢀","⠤"],["⠀","⠗","⠁","⠀"]],
67 | '#' => [["⠠","⡴","⢤","⠦"],["⠙","⠉","⠋","⠁"]],
68 | ']' => [["⠀","⠈","⢩","⠃"],["⠠","⠤","⠎","⠀"]],
69 | '6' => [["⠀","⣔","⠭","⡉"],["⠘","⠤","⠔","⠁"]],
70 | 'p' => [["⠤","⠤","⠤","⡀"],["⡸","⠢","⠔","⠁"]],
71 | '}' => [["⠀","⠈","⠩","⣃"],["⠠","⠤","⠎","⠀"]],
72 | 'W' => [["⢩","⢃","⠆","⡜"],["⠣","⠺","⠜","⠀"]],
73 | 'N' => [["⢉","⢆","⢀","⠎"],["⠜","⠀","⠙","⠤"]],
74 | 'c' => [["⠀","⡠","⢄","⠀"],["⠘","⠤","⠤","⠤"]],
75 | 'B' => [["⠉","⡍","⣩","⠂"],["⠸","⠤","⠔","⠁"]],
76 | '5' => [["⠀","⠼","⢍","⠉"],["⠢","⠤","⠊","⠀"]],
77 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⡰","⠀","⠀"]],
78 | 'u' => [["⠤","⡄","⠀","⡄"],["⠘","⠤","⠲","⠁"]],
79 | 'D' => [["⠉","⡍","⠑","⡄"],["⠸","⠤","⠔","⠁"]],
80 | '(' => [["⠀","⡔","⠉","⠀"],["⠘","⠤","⠀","⠀"]],
81 | '\\' => [["⠑","⢄","⠀","⠀"],["⠀","⠀","⠑","⠄"]],
82 | '/' => [["⠀","⢀","⠔","⠁"],["⠔","⠁","⠀","⠀"]],
83 | 'e' => [["⠀","⡠","⢄","⠀"],["⠘","⠮","⠥","⠤"]],
84 | '<' => [["⠀","⡠","⠂","⠀"],["⠀","⠈","⠂","⠀"]],
85 | '~' => [["⠀","⠖","⠴","⠀"],["⠀","⠀","⠀","⠀"]],
86 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⡀"]],
87 | '1' => [["⠀","⠠","⡞","⠀"],["⠀","⠰","⠁","⠀"]],
88 | 'y' => [["⠀","⡠","⠀","⡠"],["⣀","⣑","⡪","⠃"]],
89 | 'U' => [["⢩","⠃","⠀","⡜"],["⠣","⠤","⠔","⠁"]],
90 | '^' => [["⢀","⢴","⢄","⠀"],["⠀","⠸","⠀","⠀"]],
91 | 'H' => [["⢉","⣆","⣀","⠎"],["⠜","⠀","⠘","⠤"]],
92 | 'M' => [["⢉","⠦","⡠","⡎"],["⠎","⠘","⠘","⠤"]],
93 | '!' => [["⠀","⢠","⠃","⠀"],["⠀","⠆","⠀","⠀"]],
94 | ')' => [["⠀","⠈","⡱","⠀"],["⠠","⠔","⠁","⠀"]],
95 | 'q' => [["⢀","⠤","⠤","⠤"],["⠣","⢔","⠎","⠀"]],
96 | 'L' => [["⠉","⡕","⠀","⠀"],["⠘","⠤","⠤","⠤"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Everest Bold.grf:
--------------------------------------------------------------------------------
1 | {'Q' => [["⣴","⠋","⢳","⡄"],["⠻","⣔","⢮","⡃"]],
2 | '%' => [["⢴","⡢","⡠","⠀"],["⠠","⠪","⣖","⠄"]],
3 | 'J' => [["⠀","⠀","⢸","⡇"],["⠰","⣀","⣸","⠇"]],
4 | '0' => [["⣴","⢋","⢳","⡄"],["⠻","⣌","⡼","⠃"]],
5 | 'w' => [["⣤","⢀","⢠","⡄"],["⠹","⡾","⡾","⠁"]],
6 | "£" => [["⣰","⣏","⡉","⠂"],["⣸","⣇","⣀","⡀"]],
7 | 'i' => [["⠀","⢨","⡅","⠀"],["⠀","⢸","⡇","⠀"]],
8 | '7' => [["⠈","⠉","⣹","⠇"],["⠀","⢸","⡇","⠀"]],
9 | '9' => [["⢰","⡏","⢹","⡆"],["⠠","⣉","⣹","⠇"]],
10 | 'X' => [["⠻","⣄","⡼","⠃"],["⣴","⠋","⢳","⡄"]],
11 | 'I' => [["⠈","⢹","⡏","⠁"],["⢀","⣸","⣇","⡀"]],
12 | 'U' => [["⢸","⡇","⢸","⡇"],["⠸","⣇","⣸","⠇"]],
13 | 'r' => [["⢠","⣄","⢤","⡀"],["⢸","⡇","⠀","⠀"]],
14 | '|' => [["⠀","⢸","⡇","⠀"],["⠀","⢸","⡇","⠀"]],
15 | '<' => [["⠀","⣠","⠖","⠀"],["⠀","⠈","⠓","⠀"]],
16 | '>' => [["⠀","⠲","⣄","⠀"],["⠀","⠚","⠁","⠀"]],
17 | '2' => [["⠐","⠉","⣹","⠆"],["⢠","⣞","⣁","⡀"]],
18 | 'a' => [["⠀","⠤","⢤","⡀"],["⠰","⣏","⣹","⡇"]],
19 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⢘","⠇","⠀"]],
20 | 'G' => [["⢠","⡞","⠉","⠂"],["⠘","⢧","⣹","⡇"]],
21 | 'v' => [["⢠","⡄","⢠","⡄"],["⢸","⡷","⠋","⠀"]],
22 | 'P' => [["⢸","⡏","⢹","⡆"],["⢸","⡏","⠉","⠀"]],
23 | 'Y' => [["⠸","⣇","⣸","⠇"],["⠀","⢸","⡇","⠀"]],
24 | 'g' => [["⢀","⡤","⢤","⡄"],["⠈","⣓","⣹","⠇"]],
25 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
26 | 'V' => [["⢻","⡄","⣼","⠃"],["⠈","⢷","⠏","⠀"]],
27 | 'q' => [["⢀","⡤","⣠","⡄"],["⠈","⠓","⢺","⡇"]],
28 | 'O' => [["⣴","⠋","⢳","⡄"],["⠻","⣄","⡼","⠃"]],
29 | '!' => [["⠀","⣾","⡆","⠀"],["⠀","⢨","⠀","⠀"]],
30 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠆","⠀"]],
31 | '&' => [["⢾","⣹","⠆","⠀"],["⢿","⣈","⡷","⡁"]],
32 | '4' => [["⢀","⡴","⣋","⠀"],["⠘","⠓","⣿","⠂"]],
33 | 'Z' => [["⠉","⢉","⡽","⠃"],["⣴","⣋","⣀","⡀"]],
34 | 'e' => [["⢀","⡤","⢤","⡀"],["⠸","⣏","⣉","⠅"]],
35 | '6' => [["⢰","⣏","⣉","⠂"],["⠸","⣇","⣸","⠇"]],
36 | 'b' => [["⢸","⣇","⢤","⡀"],["⢸","⣇","⣸","⠇"]],
37 | 'H' => [["⢸","⣇","⣸","⡇"],["⢸","⡇","⢸","⡇"]],
38 | 'A' => [["⢠","⡟","⣧","⠀"],["⣾","⠉","⢹","⡆"]],
39 | ']' => [["⠀","⠉","⣿","⠀"],["⠀","⣀","⣿","⠀"]],
40 | 'd' => [["⢀","⡤","⣸","⡇"],["⠸","⣇","⣸","⡇"]],
41 | 'j' => [["⠀","⠀","⢨","⡅"],["⠠","⣀","⣸","⠇"]],
42 | 'T' => [["⠈","⢹","⡏","⠁"],["⠀","⢸","⡇","⠀"]],
43 | '5' => [["⢸","⣏","⣉","⠁"],["⠠","⣀","⣸","⠇"]],
44 | 'x' => [["⠠","⣄","⣠","⠄"],["⢠","⡞","⢳","⡄"]],
45 | '+' => [["⢀","⣰","⣆","⡀"],["⠀","⠘","⠃","⠀"]],
46 | 's' => [["⢀","⡤","⠤","⡀"],["⠠","⣙","⣳","⠄"]],
47 | 'u' => [["⢠","⡄","⢠","⡄"],["⠸","⣇","⢼","⡇"]],
48 | '{' => [["⢀","⣰","⠏","⠁"],["⠀","⠸","⣇","⡀"]],
49 | '3' => [["⠈","⢉","⣽","⠃"],["⠠","⣀","⣸","⠇"]],
50 | '8' => [["⠰","⣏","⣹","⠆"],["⠸","⣇","⣸","⠇"]],
51 | 'y' => [["⢠","⡄","⢠","⡄"],["⠈","⣓","⣹","⠇"]],
52 | '~' => [["⠰","⠛","⠶","⠃"],["⠀","⠀","⠀","⠀"]],
53 | 'B' => [["⢸","⣏","⣹","⠆"],["⢸","⣇","⣸","⠇"]],
54 | ')' => [["⠀","⠙","⣦","⠀"],["⠀","⣠","⠟","⠀"]],
55 | 't' => [["⠠","⣿","⠄","⠀"],["⠀","⢿","⣀","⠄"]],
56 | 'z' => [["⠠","⠤","⢤","⡄"],["⢀","⣴","⣋","⡀"]],
57 | '#' => [["⢼","⡧","⣿","⠄"],["⢺","⡗","⣿","⠂"]],
58 | '"' => [["⢘","⠇","⡻","⠀"],["⠀","⠀","⠀","⠀"]],
59 | '^' => [["⢠","⠞","⢦","⠀"],["⠀","⠀","⠀","⠀"]],
60 | '$' => [["⢠","⣖","⡓","⠄"],["⠐","⢬","⠽","⠃"]],
61 | 'D' => [["⢸","⡏","⢳","⡄"],["⢸","⣇","⡼","⠃"]],
62 | 'h' => [["⢸","⣇","⢤","⡀"],["⢸","⡇","⢸","⡇"]],
63 | 'k' => [["⢸","⡇","⣰","⠆"],["⢸","⡏","⢳","⡄"]],
64 | ';' => [["⠀","⠰","⠆","⠀"],["⠀","⢘","⠇","⠀"]],
65 | '=' => [["⠠","⠤","⠤","⠄"],["⠈","⠉","⠉","⠁"]],
66 | '(' => [["⠀","⣴","⠋","⠀"],["⠀","⠻","⣄","⠀"]],
67 | 'E' => [["⢸","⣏","⡉","⠁"],["⢸","⣇","⣀","⡀"]],
68 | '\\' => [["⠘","⣧","⠀","⠀"],["⠀","⠘","⣧","⠀"]],
69 | ':' => [["⠀","⠰","⠆","⠀"],["⠀","⠰","⠆","⠀"]],
70 | 'o' => [["⢀","⡤","⢤","⡀"],["⠸","⣇","⣸","⠇"]],
71 | 'N' => [["⢸","⣦","⣸","⡇"],["⢸","⡏","⠻","⡇"]],
72 | '/' => [["⠀","⢠","⡟","⠀"],["⢠","⡟","⠀","⠀"]],
73 | 'p' => [["⢠","⣄","⢤","⡀"],["⢸","⡗","⠚","⠁"]],
74 | '-' => [["⢀","⣀","⣀","⡀"],["⠀","⠀","⠀","⠀"]],
75 | 'm' => [["⣤","⣄","⣤","⡀"],["⣿","⢸","⢸","⡇"]],
76 | '@' => [["⣴","⣫","⢷","⡄"],["⠻","⣝","⣚","⡃"]],
77 | 'W' => [["⣿","⢠","⢸","⡇"],["⢿","⠟","⢿","⠇"]],
78 | 'R' => [["⢸","⡏","⢹","⡆"],["⢸","⡏","⢻","⡄"]],
79 | 'n' => [["⢠","⣄","⢤","⡀"],["⢸","⡇","⢸","⡇"]],
80 | 'info' => ' Everest Bold font ','c' => [["⢀","⡤","⠤","⡀"],["⠸","⣇","⣀","⠄"]],
81 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
82 | '?' => [["⠰","⠏","⣹","⠆"],["⠀","⢨","⡅","⠀"]],
83 | 'L' => [["⢸","⡇","⠀","⠀"],["⢸","⣇","⣀","⡀"]],
84 | 'M' => [["⣷","⣄","⣴","⡇"],["⣿","⠹","⢹","⡇"]],
85 | 'F' => [["⢸","⣏","⡉","⠁"],["⢸","⡇","⠀","⠀"]],
86 | '[' => [["⠀","⣿","⠉","⠀"],["⠀","⣿","⣀","⠀"]],
87 | 'l' => [["⠀","⠉","⣿","⠀"],["⠀","⠀","⣿","⠀"]],
88 | "©" => [["⡾","⣵","⠪","⣳"],["⢷","⡻","⢔","⡽"]],
89 | '\'' => [["⠀","⡻","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
90 | 'K' => [["⢸","⣇","⡼","⠃"],["⢸","⡏","⢳","⡄"]],
91 | 'f' => [["⣀","⣾","⣉","⠂"],["⢄","⡿","⠀","⠀"]],
92 | '*' => [["⠠","⣴","⡤","⠀"],["⠈","⠙","⠉","⠀"]],
93 | 'S' => [["⢾","⣉","⠉","⠂"],["⢄","⣈","⣹","⠆"]],
94 | '1' => [["⠠","⢺","⡇","⠀"],["⢀","⣸","⣇","⡀"]],
95 | '}' => [["⠈","⠹","⣆","⡀"],["⢀","⣸","⠇","⠀"]],
96 | 'C' => [["⢠","⡞","⠉","⠂"],["⠘","⢧","⣀","⠄"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Everest Condensed SemiBold.grf:
--------------------------------------------------------------------------------
1 | {'j' => [["⠀","⠀","⣭","⠀"],["⠠","⣀","⡿","⠀"]],
2 | 'd' => [["⢀","⠤","⣿","⠀"],["⠸","⣀","⣿","⠀"]],
3 | 'T' => [["⠈","⢹","⡏","⠁"],["⠀","⢸","⡇","⠀"]],
4 | '5' => [["⢸","⣏","⡉","⠀"],["⠠","⣀","⡿","⠀"]],
5 | 'x' => [["⢠","⡄","⢠","⠀"],["⢠","⠛","⣧","⠀"]],
6 | '+' => [["⢀","⣰","⣆","⡀"],["⠀","⠘","⠃","⠀"]],
7 | 's' => [["⢀","⡤","⢄","⠀"],["⠠","⣙","⡦","⠀"]],
8 | 'u' => [["⢠","⠀","⣤","⠀"],["⠸","⣀","⣿","⠀"]],
9 | '{' => [["⢀","⣰","⠏","⠀"],["⠀","⠸","⣇","⠀"]],
10 | '3' => [["⠈","⣉","⡟","⠀"],["⠠","⣀","⡿","⠀"]],
11 | 'y' => [["⢠","⠀","⣤","⠀"],["⠈","⣒","⡿","⠀"]],
12 | '8' => [["⠰","⣏","⡱","⠀"],["⠸","⣀","⡿","⠀"]],
13 | '~' => [["⠰","⠟","⠞","⠀"],["⠀","⠀","⠀","⠀"]],
14 | 'B' => [["⢸","⣏","⡱","⠀"],["⢸","⣇","⡸","⠀"]],
15 | '#' => [["⠠","⣿","⢼","⠄"],["⠐","⣿","⢺","⠂"]],
16 | '"' => [["⠠","⠟","⠼","⠃"],["⠀","⠀","⠀","⠀"]],
17 | ')' => [["⠀","⠙","⣦","⠀"],["⠀","⣠","⠟","⠀"]],
18 | 't' => [["⠠","⣿","⠄","⠀"],["⠀","⢿","⡠","⠀"]],
19 | 'z' => [["⠠","⠤","⣤","⠀"],["⢠","⣞","⣁","⠀"]],
20 | '^' => [["⢠","⠞","⢦","⠀"],["⠀","⠀","⠀","⠀"]],
21 | '$' => [["⠠","⣞","⠢","⠀"],["⠐","⢬","⠗","⠀"]],
22 | 'D' => [["⢸","⡏","⢢","⠀"],["⢸","⣇","⠜","⠀"]],
23 | 'h' => [["⢸","⡧","⢄","⠀"],["⢸","⡇","⢸","⠀"]],
24 | ';' => [["⠀","⢠","⡄","⠀"],["⠀","⣰","⠆","⠀"]],
25 | 'k' => [["⢸","⣇","⠔","⠀"],["⢸","⡗","⢄","⠀"]],
26 | '=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
27 | 'E' => [["⢸","⣏","⡉","⠀"],["⢸","⣇","⣀","⠀"]],
28 | '(' => [["⠀","⣴","⠋","⠀"],["⠀","⠻","⣄","⠀"]],
29 | ':' => [["⠀","⢠","⡄","⠀"],["⠀","⠰","⠆","⠀"]],
30 | '\\' => [["⠘","⣧","⠀","⠀"],["⠀","⠘","⣧","⠀"]],
31 | 'o' => [["⢀","⡤","⢄","⠀"],["⠸","⣇","⡸","⠀"]],
32 | 'N' => [["⢸","⣧","⢸","⠀"],["⢸","⡇","⢻","⠀"]],
33 | '/' => [["⠀","⢠","⡟","⠀"],["⢠","⡟","⠀","⠀"]],
34 | 'p' => [["⢠","⡤","⢄","⠀"],["⢸","⡧","⠜","⠀"]],
35 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
36 | 'm' => [["⢠","⡤","⡠","⡀"],["⢸","⡇","⡇","⡇"]],
37 | '@' => [["⢠","⡞","⡩","⡆"],["⠘","⢧","⣑","⡃"]],
38 | 'R' => [["⢸","⡏","⢱","⠀"],["⢸","⡟","⢅","⠀"]],
39 | 'n' => [["⢠","⡤","⢄","⠀"],["⢸","⡇","⢸","⠀"]],
40 | 'W' => [["⢸","⡇","⡄","⡇"],["⠈","⣷","⢱","⠁"]],
41 | 'info' => ' Everest Condensed SemiBold font ','_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
42 | 'c' => [["⢀","⡤","⢄","⠀"],["⠸","⣇","⡠","⠀"]],
43 | '?' => [["⠰","⢉","⡷","⠀"],["⠀","⣭","⠀","⠀"]],
44 | 'L' => [["⢸","⡇","⠀","⠀"],["⢸","⣇","⣀","⠀"]],
45 | 'M' => [["⢸","⡷","⡰","⡇"],["⢸","⡇","⠁","⡇"]],
46 | 'F' => [["⢸","⣏","⡉","⠀"],["⢸","⡇","⠀","⠀"]],
47 | 'l' => [["⠀","⢹","⡇","⠀"],["⠀","⢸","⡇","⠀"]],
48 | '[' => [["⠀","⣿","⠉","⠀"],["⠀","⣿","⣀","⠀"]],
49 | '\'' => [["⠀","⠼","⠃","⠀"],["⠀","⠀","⠀","⠀"]],
50 | 'K' => [["⢸","⡧","⠊","⠀"],["⢸","⡏","⢢","⠀"]],
51 | "©" => [["⡎","⣴","⠢","⢱"],["⢇","⠻","⠔","⡸"]],
52 | 'S' => [["⠰","⣏","⠑","⠀"],["⠠","⣈","⡷","⠀"]],
53 | 'f' => [["⢀","⣾","⣉","⠀"],["⢀","⡿","⠀","⠀"]],
54 | '*' => [["⠠","⣴","⡤","⠀"],["⠈","⠙","⠉","⠀"]],
55 | '}' => [["⠈","⢷","⣀","⠀"],["⢀","⡿","⠀","⠀"]],
56 | '1' => [["⠀","⢺","⡇","⠀"],["⠀","⣸","⣇","⠀"]],
57 | 'C' => [["⢰","⡏","⠑","⠀"],["⠸","⣇","⡠","⠀"]],
58 | 'Q' => [["⢰","⡏","⢱","⠀"],["⠸","⣗","⢜","⠀"]],
59 | '%' => [["⠰","⢝","⡴","⠀"],["⠰","⢫","⡲","⠀"]],
60 | 'J' => [["⠀","⠀","⣿","⠀"],["⠰","⣀","⡿","⠀"]],
61 | '0' => [["⢰","⡏","⢱","⠀"],["⠸","⣇","⡸","⠀"]],
62 | 'w' => [["⢠","⡄","⠀","⡄"],["⠘","⣧","⢣","⠃"]],
63 | "£" => [["⢀","⣾","⡑","⠀"],["⢀","⣿","⣀","⠀"]],
64 | 'i' => [["⠀","⢨","⡅","⠀"],["⠀","⢸","⡇","⠀"]],
65 | '9' => [["⢰","⠉","⣷","⠀"],["⠠","⣉","⡿","⠀"]],
66 | '7' => [["⠈","⢉","⡿","⠀"],["⠀","⣿","⠀","⠀"]],
67 | 'I' => [["⠈","⣿","⠁","⠀"],["⢀","⣿","⡀","⠀"]],
68 | 'X' => [["⠸","⣇","⡸","⠀"],["⢰","⠉","⣷","⠀"]],
69 | 'r' => [["⢠","⡤","⢄","⠀"],["⢸","⡇","⠀","⠀"]],
70 | 'U' => [["⢸","⡇","⢸","⠀"],["⠸","⣇","⡸","⠀"]],
71 | '<' => [["⢀","⡴","⠂","⠀"],["⠀","⠙","⠂","⠀"]],
72 | '|' => [["⠀","⢸","⡇","⠀"],["⠀","⢸","⡇","⠀"]],
73 | '>' => [["⠀","⠲","⣄","⠀"],["⠀","⠚","⠁","⠀"]],
74 | '2' => [["⠐","⢉","⡷","⠀"],["⢰","⣏","⣀","⠀"]],
75 | 'a' => [["⠀","⠤","⣄","⠀"],["⠰","⣉","⣿","⠀"]],
76 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⣰","⠆","⠀"]],
77 | 'Y' => [["⠸","⣇","⣀","⠇"],["⠀","⢸","⡇","⠀"]],
78 | 'G' => [["⢰","⡏","⠑","⠀"],["⠸","⣇","⣹","⠀"]],
79 | 'v' => [["⢠","⡄","⢠","⠀"],["⢸","⠗","⠁","⠀"]],
80 | 'P' => [["⢸","⡏","⢱","⠀"],["⢸","⡏","⠁","⠀"]],
81 | 'g' => [["⢀","⠤","⣤","⠀"],["⢈","⣒","⡿","⠀"]],
82 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
83 | 'V' => [["⢸","⡇","⢸","⠀"],["⠀","⢻","⠃","⠀"]],
84 | 'q' => [["⢀","⠤","⣤","⠀"],["⠘","⠤","⣿","⠀"]],
85 | 'O' => [["⢰","⡏","⢱","⠀"],["⠸","⣇","⡸","⠀"]],
86 | '!' => [["⠀","⢸","⡇","⠀"],["⠀","⢨","⡅","⠀"]],
87 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠆","⠀"]],
88 | '&' => [["⠰","⣏","⠆","⠀"],["⠸","⣇","⢏","⠀"]],
89 | '4' => [["⢀","⢴","⡇","⠀"],["⠘","⢺","⡗","⠀"]],
90 | 'Z' => [["⠈","⢉","⡿","⠀"],["⢰","⣏","⣀","⠀"]],
91 | 'e' => [["⢀","⡤","⢄","⠀"],["⠸","⣏","⡩","⠀"]],
92 | '6' => [["⢰","⣏","⡑","⠀"],["⠸","⣇","⡸","⠀"]],
93 | 'b' => [["⢸","⡧","⢄","⠀"],["⢸","⣇","⡸","⠀"]],
94 | 'A' => [["⢀","⡾","⢆","⠀"],["⢸","⡏","⢹","⠀"]],
95 | 'H' => [["⢸","⣇","⣸","⠀"],["⢸","⡇","⢸","⠀"]],
96 | ']' => [["⠀","⠉","⣿","⠀"],["⠀","⣀","⣿","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Everest Condensed.grf:
--------------------------------------------------------------------------------
1 | {'$' => [["⠠","⣚","⠢","⠀"],["⠐","⢤","⠕","⠀"]],
2 | 'D' => [["⢸","⠉","⢢","⠀"],["⢸","⣀","⠜","⠀"]],
3 | 'h' => [["⢸","⡠","⢄","⠀"],["⢸","⠀","⢸","⠀"]],
4 | ';' => [["⠀","⠠","⠀","⠀"],["⠀","⡰","⠀","⠀"]],
5 | 'k' => [["⢸","⢀","⠔","⠀"],["⢸","⠑","⢄","⠀"]],
6 | 'B' => [["⢸","⣉","⡱","⠀"],["⢸","⣀","⡸","⠀"]],
7 | ')' => [["⠀","⠑","⡄","⠀"],["⠀","⡠","⠃","⠀"]],
8 | 't' => [["⠠","⡧","⠄","⠀"],["⠀","⢇","⡠","⠀"]],
9 | 'z' => [["⠠","⠤","⡤","⠀"],["⢠","⣊","⣀","⠀"]],
10 | '#' => [["⠠","⡧","⢼","⠄"],["⠐","⡗","⢺","⠂"]],
11 | '"' => [["⠠","⠃","⠜","⠀"],["⠀","⠀","⠀","⠀"]],
12 | '^' => [["⠠","⠊","⠢","⠀"],["⠀","⠀","⠀","⠀"]],
13 | '3' => [["⠈","⣉","⡝","⠀"],["⠠","⣀","⡸","⠀"]],
14 | '8' => [["⠰","⣉","⡱","⠀"],["⠸","⣀","⡸","⠀"]],
15 | 'y' => [["⢠","⠀","⢠","⠀"],["⠈","⣒","⡺","⠀"]],
16 | '~' => [["⠰","⠑","⠜","⠀"],["⠀","⠀","⠀","⠀"]],
17 | 'j' => [["⠀","⠀","⢨","⠀"],["⠠","⣀","⡸","⠀"]],
18 | 'd' => [["⢀","⠤","⣸","⠀"],["⠸","⣀","⢼","⠀"]],
19 | 'T' => [["⠈","⢹","⠉","⠀"],["⠀","⢸","⠀","⠀"]],
20 | '5' => [["⢸","⣉","⡉","⠀"],["⠠","⣀","⡸","⠀"]],
21 | 'x' => [["⠠","⡀","⡠","⠀"],["⢀","⠜","⢄","⠀"]],
22 | '+' => [["⢀","⣰","⣀","⠀"],["⠀","⠘","⠀","⠀"]],
23 | 's' => [["⢀","⠤","⢄","⠀"],["⠠","⣉","⡢","⠀"]],
24 | 'u' => [["⢠","⠀","⢠","⠀"],["⠸","⣀","⢼","⠀"]],
25 | '{' => [["⢀","⡰","⠉","⠀"],["⠀","⠸","⣀","⠀"]],
26 | "©" => [["⡎","⡔","⠢","⢱"],["⢇","⠣","⠔","⡸"]],
27 | 'K' => [["⢸","⡠","⠊","⠀"],["⢸","⠈","⢢","⠀"]],
28 | '\'' => [["⠀","⠜","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
29 | '*' => [["⠠","⣰","⡠","⠀"],["⠈","⠘","⠈","⠀"]],
30 | 'f' => [["⢀","⣰","⣉","⠀"],["⢀","⡸","⠀","⠀"]],
31 | 'S' => [["⠰","⣉","⠑","⠀"],["⠠","⣀","⡱","⠀"]],
32 | '1' => [["⠀","⢺","⠀","⠀"],["⠀","⣸","⡀","⠀"]],
33 | '}' => [["⠈","⠱","⣀","⠀"],["⢀","⡸","⠀","⠀"]],
34 | 'C' => [["⢰","⠉","⠑","⠀"],["⠸","⣀","⡠","⠀"]],
35 | 'W' => [["⢸","⢠","⢸","⠀"],["⠈","⡎","⡎","⠀"]],
36 | 'R' => [["⢸","⠉","⢱","⠀"],["⢸","⠙","⢅","⠀"]],
37 | 'n' => [["⢠","⡠","⢄","⠀"],["⢸","⠀","⢸","⠀"]],
38 | 'info' => ' Everest Condensed font ','_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
39 | 'c' => [["⢀","⠤","⢄","⠀"],["⠸","⣀","⡠","⠀"]],
40 | 'L' => [["⢸","⠀","⠀","⠀"],["⢸","⣀","⣀","⠀"]],
41 | '?' => [["⠰","⠉","⡱","⠀"],["⠀","⢨","⠀","⠀"]],
42 | 'F' => [["⢸","⣉","⡉","⠀"],["⢸","⠀","⠀","⠀"]],
43 | 'M' => [["⢸","⢆","⢾","⠀"],["⢸","⠈","⢸","⠀"]],
44 | '[' => [["⠀","⡏","⠁","⠀"],["⠀","⣇","⡀","⠀"]],
45 | 'l' => [["⠀","⠉","⡇","⠀"],["⠀","⠀","⡇","⠀"]],
46 | 'N' => [["⢸","⢆","⢸","⠀"],["⢸","⠈","⢾","⠀"]],
47 | 'o' => [["⢀","⠤","⢄","⠀"],["⠸","⣀","⡸","⠀"]],
48 | '/' => [["⠀","⠀","⡜","⠀"],["⠀","⡜","⠀","⠀"]],
49 | 'p' => [["⢠","⡠","⢄","⠀"],["⢸","⠢","⠜","⠀"]],
50 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
51 | 'm' => [["⢠","⢄","⢄","⠀"],["⢸","⢸","⢸","⠀"]],
52 | '@' => [["⢠","⢊","⢕","⡄"],["⠘","⢌","⣒","⡁"]],
53 | '=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
54 | 'E' => [["⢸","⣉","⡉","⠀"],["⢸","⣀","⣀","⠀"]],
55 | '(' => [["⠀","⡔","⠁","⠀"],["⠀","⠣","⡀","⠀"]],
56 | '\\' => [["⠀","⢣","⠀","⠀"],["⠀","⠀","⢣","⠀"]],
57 | ':' => [["⠀","⠠","⠀","⠀"],["⠀","⠐","⠀","⠀"]],
58 | '>' => [["⠀","⠢","⡀","⠀"],["⠀","⠊","⠀","⠀"]],
59 | '2' => [["⠐","⠉","⡱","⠀"],["⢠","⣊","⣀","⠀"]],
60 | 'a' => [["⠀","⠤","⢄","⠀"],["⠰","⣉","⣹","⠀"]],
61 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⡰","⠀","⠀"]],
62 | '7' => [["⠈","⠉","⡹","⠀"],["⠀","⡎","⠀","⠀"]],
63 | '9' => [["⢰","⠉","⢱","⠀"],["⠠","⣉","⡹","⠀"]],
64 | 'X' => [["⠘","⢄","⠜","⠀"],["⢠","⠊","⢢","⠀"]],
65 | 'I' => [["⠈","⢹","⠉","⠀"],["⢀","⣸","⣀","⠀"]],
66 | 'U' => [["⢸","⠀","⢸","⠀"],["⠸","⣀","⡸","⠀"]],
67 | 'r' => [["⢠","⡠","⢄","⠀"],["⢸","⠀","⠀","⠀"]],
68 | '<' => [["⠀","⡠","⠂","⠀"],["⠀","⠈","⠂","⠀"]],
69 | '|' => [["⠀","⢸","⠀","⠀"],["⠀","⢸","⠀","⠀"]],
70 | '%' => [["⠠","⡢","⡠","⠀"],["⠠","⠪","⡢","⠀"]],
71 | 'J' => [["⠀","⠀","⢸","⠀"],["⠰","⣀","⡸","⠀"]],
72 | '0' => [["⢰","⢉","⢱","⠀"],["⠸","⣈","⡸","⠀"]],
73 | "£" => [["⢀","⣎","⡑","⠀"],["⢀","⣇","⣀","⠀"]],
74 | 'w' => [["⢠","⠀","⢠","⠀"],["⠘","⡜","⡜","⠀"]],
75 | 'i' => [["⠀","⢨","⠀","⠀"],["⠀","⢸","⠀","⠀"]],
76 | 'Q' => [["⢰","⠉","⢱","⠀"],["⠸","⣐","⢜","⠀"]],
77 | 'Z' => [["⠈","⢉","⠝","⠀"],["⢰","⣁","⣀","⠀"]],
78 | 'e' => [["⢀","⠤","⢄","⠀"],["⠸","⣉","⡩","⠀"]],
79 | '6' => [["⢰","⣉","⡑","⠀"],["⠸","⣀","⡸","⠀"]],
80 | 'b' => [["⢸","⡠","⢄","⠀"],["⢸","⢄","⡸","⠀"]],
81 | 'H' => [["⢸","⣀","⣸","⠀"],["⢸","⠀","⢸","⠀"]],
82 | 'A' => [["⢀","⠎","⢆","⠀"],["⢸","⠉","⢹","⠀"]],
83 | ']' => [["⠀","⠉","⡇","⠀"],["⠀","⣀","⡇","⠀"]],
84 | '&' => [["⠰","⣉","⠆","⠀"],["⠸","⣀","⢏","⠀"]],
85 | '4' => [["⢀","⠔","⡇","⠀"],["⠘","⠒","⡗","⠀"]],
86 | 'q' => [["⢀","⠤","⣠","⠀"],["⠘","⠤","⢺","⠀"]],
87 | 'O' => [["⢰","⠉","⢱","⠀"],["⠸","⣀","⡸","⠀"]],
88 | '!' => [["⠀","⢸","⠀","⠀"],["⠀","⢨","⠀","⠀"]],
89 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠀","⠀"]],
90 | 'P' => [["⢸","⠉","⢱","⠀"],["⢸","⠉","⠁","⠀"]],
91 | 'v' => [["⢠","⠀","⢠","⠀"],["⢸","⠔","⠁","⠀"]],
92 | 'G' => [["⢰","⠉","⠑","⠀"],["⠸","⣀","⣹","⠀"]],
93 | 'Y' => [["⠸","⡀","⡸","⠀"],["⠀","⢸","⠀","⠀"]],
94 | 'g' => [["⢀","⠤","⢤","⠀"],["⢈","⣒","⡹","⠀"]],
95 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
96 | 'V' => [["⢸","⠀","⢸","⠀"],["⠀","⢣","⠃","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Everest.grf:
--------------------------------------------------------------------------------
1 | {'4' => [["⢀","⠔","⢁","⠀"],["⠘","⠒","⢺","⠂"]],
2 | '&' => [["⠰","⣉","⠆","⠀"],["⢎","⣀","⡱","⡁"]],
3 | ']' => [["⠀","⠉","⡇","⠀"],["⠀","⣀","⡇","⠀"]],
4 | 'A' => [["⢀","⠎","⢆","⠀"],["⡜","⠉","⠙","⡄"]],
5 | 'H' => [["⢸","⣀","⣀","⡇"],["⢸","⠀","⠀","⡇"]],
6 | 'b' => [["⢸","⡠","⠤","⡀"],["⢸","⢄","⣀","⠇"]],
7 | '6' => [["⢰","⣉","⣉","⠂"],["⠸","⣀","⣀","⠇"]],
8 | 'e' => [["⢀","⠤","⠤","⡀"],["⠸","⣉","⣉","⠅"]],
9 | 'Z' => [["⠉","⢉","⠝","⠁"],["⣔","⣁","⣀","⡀"]],
10 | 'V' => [["⢣","⠀","⢠","⠃"],["⠀","⢣","⠃","⠀"]],
11 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
12 | 'g' => [["⢀","⠤","⠤","⡄"],["⠈","⣒","⣊","⠇"]],
13 | 'Y' => [["⠣","⡀","⡠","⠃"],["⠀","⢸","⠀","⠀"]],
14 | 'v' => [["⢠","⠀","⢀","⠄"],["⢸","⠔","⠁","⠀"]],
15 | 'G' => [["⢠","⠊","⠉","⠂"],["⠘","⢄","⣉","⡇"]],
16 | 'P' => [["⢸","⠉","⠉","⡆"],["⢸","⠉","⠉","⠀"]],
17 | '!' => [["⠀","⢸","⠀","⠀"],["⠀","⢨","⠀","⠀"]],
18 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠀","⠀"]],
19 | 'O' => [["⡔","⠉","⠑","⡄"],["⠣","⣀","⡠","⠃"]],
20 | 'q' => [["⢀","⠤","⢄","⡄"],["⠘","⠤","⠔","⡇"]],
21 | '<' => [["⠀","⡠","⠂","⠀"],["⠀","⠈","⠂","⠀"]],
22 | '|' => [["⠀","⢸","⠀","⠀"],["⠀","⢸","⠀","⠀"]],
23 | 'r' => [["⢠","⡠","⠤","⡀"],["⢸","⠀","⠀","⠀"]],
24 | 'U' => [["⢸","⠀","⠀","⡇"],["⠸","⣀","⣀","⠇"]],
25 | 'I' => [["⠈","⢹","⠉","⠀"],["⢀","⣸","⣀","⠀"]],
26 | 'X' => [["⠑","⢄","⠔","⠁"],["⡠","⠊","⠢","⡀"]],
27 | '9' => [["⢰","⠉","⠉","⡆"],["⠠","⣉","⣉","⠇"]],
28 | '7' => [["⠈","⠉","⢉","⠇"],["⠀","⢰","⠁","⠀"]],
29 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⡰","⠂","⠀"]],
30 | 'a' => [["⠀","⠤","⠤","⡀"],["⠰","⣉","⣉","⡇"]],
31 | '2' => [["⠐","⠉","⡩","⠂"],["⢠","⣊","⣀","⡀"]],
32 | '>' => [["⠀","⠐","⢄","⠀"],["⠀","⠐","⠁","⠀"]],
33 | 'Q' => [["⡔","⠉","⠑","⡄"],["⠣","⣀","⡢","⡃"]],
34 | 'i' => [["⠀","⢨","⠀","⠀"],["⠀","⢸","⠀","⠀"]],
35 | 'w' => [["⡄","⠀","⠀","⡄"],["⠘","⡜","⡜","⠀"]],
36 | "£" => [["⣰","⣉","⠉","⠂"],["⣸","⣀","⣀","⡀"]],
37 | '0' => [["⡔","⢉","⠑","⡄"],["⠣","⣈","⡠","⠃"]],
38 | 'J' => [["⠀","⠀","⠀","⡇"],["⠰","⣀","⣀","⠇"]],
39 | '%' => [["⢔","⠄","⡠","⠀"],["⠠","⠊","⢔","⠄"]],
40 | 'l' => [["⠀","⠉","⡇","⠀"],["⠀","⠀","⡇","⠀"]],
41 | '[' => [["⠀","⡏","⠁","⠀"],["⠀","⣇","⡀","⠀"]],
42 | 'F' => [["⢸","⣉","⡉","⠁"],["⢸","⠀","⠀","⠀"]],
43 | 'M' => [["⣧","⠀","⢠","⡇"],["⡇","⢣","⠃","⡇"]],
44 | '?' => [["⠰","⠉","⢉","⠆"],["⠀","⠀","⡅","⠀"]],
45 | 'L' => [["⢸","⠀","⠀","⠀"],["⢸","⣀","⣀","⡀"]],
46 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
47 | 'c' => [["⢀","⠤","⠤","⡀"],["⠸","⣀","⣀","⠄"]],
48 | 'info' => ' Everest font ','R' => [["⢸","⠉","⠉","⡆"],["⢸","⠉","⠫","⡀"]],
49 | 'W' => [["⡇","⢠","⠀","⡇"],["⢣","⠃","⢣","⠃"]],
50 | 'n' => [["⢠","⡠","⠤","⡀"],["⢸","⠀","⠀","⡇"]],
51 | 'C' => [["⢠","⠊","⠉","⠂"],["⠘","⢄","⣀","⠄"]],
52 | '}' => [["⠈","⠉","⢆","⡀"],["⢀","⣀","⠇","⠀"]],
53 | '1' => [["⠀","⢺","⠀","⠀"],["⢀","⣸","⣀","⠀"]],
54 | 'S' => [["⢎","⣉","⠉","⠂"],["⢄","⣀","⣉","⠆"]],
55 | '*' => [["⠠","⣰","⡠","⠀"],["⠈","⠘","⠈","⠀"]],
56 | 'f' => [["⢀","⣰","⣉","⠂"],["⢄","⡸","⠀","⠀"]],
57 | '\'' => [["⠀","⠜","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
58 | 'K' => [["⢸","⣀","⠔","⠁"],["⢸","⠀","⠑","⡄"]],
59 | "©" => [["⡎","⡔","⠢","⢱"],["⢇","⠣","⠔","⡸"]],
60 | '\\' => [["⠀","⢣","⠀","⠀"],["⠀","⠀","⢣","⠀"]],
61 | ':' => [["⠀","⠠","⠄","⠀"],["⠀","⠐","⠂","⠀"]],
62 | '(' => [["⠀","⡔","⠁","⠀"],["⠀","⠣","⡀","⠀"]],
63 | 'E' => [["⢸","⣉","⡉","⠁"],["⢸","⣀","⣀","⡀"]],
64 | '=' => [["⠠","⠤","⠤","⠄"],["⠈","⠉","⠉","⠁"]],
65 | '@' => [["⡔","⡩","⡕","⡄"],["⠣","⣑","⣓","⡃"]],
66 | '-' => [["⢀","⣀","⣀","⡀"],["⠀","⠀","⠀","⠀"]],
67 | 'm' => [["⡤","⢄","⠤","⡀"],["⡇","⢸","⠀","⡇"]],
68 | 'p' => [["⢠","⡠","⠤","⡀"],["⢸","⠢","⠤","⠃"]],
69 | '/' => [["⠀","⠀","⡜","⠀"],["⠀","⡜","⠀","⠀"]],
70 | 'o' => [["⢀","⠤","⠤","⡀"],["⠸","⣀","⣀","⠇"]],
71 | 'N' => [["⢸","⢣","⠀","⡇"],["⢸","⠀","⢣","⡇"]],
72 | '^' => [["⠠","⠊","⠢","⠀"],["⠀","⠀","⠀","⠀"]],
73 | '#' => [["⠠","⡧","⢼","⠄"],["⠐","⡗","⢺","⠂"]],
74 | '"' => [["⠠","⠃","⠜","⠀"],["⠀","⠀","⠀","⠀"]],
75 | ')' => [["⠀","⠑","⡄","⠀"],["⠀","⡠","⠃","⠀"]],
76 | 't' => [["⠠","⡧","⠄","⠀"],["⠀","⢇","⣀","⠄"]],
77 | 'z' => [["⠠","⠤","⢤","⠄"],["⢀","⣔","⣁","⡀"]],
78 | 'B' => [["⢸","⣉","⣉","⠆"],["⢸","⣀","⣀","⠇"]],
79 | ';' => [["⠀","⠠","⠄","⠀"],["⠀","⡰","⠂","⠀"]],
80 | 'k' => [["⢸","⠀","⡠","⠂"],["⢸","⠉","⠢","⡀"]],
81 | 'h' => [["⢸","⡠","⠤","⡀"],["⢸","⠀","⠀","⡇"]],
82 | 'D' => [["⢸","⠉","⠑","⡄"],["⢸","⣀","⡠","⠃"]],
83 | '$' => [["⠠","⣒","⠓","⠄"],["⠐","⢤","⠭","⠂"]],
84 | '{' => [["⢀","⡰","⠉","⠁"],["⠀","⠸","⣀","⡀"]],
85 | 'u' => [["⢠","⠀","⠀","⡄"],["⠸","⣀","⡠","⡇"]],
86 | 's' => [["⢀","⠤","⠤","⡀"],["⠠","⣉","⣒","⠄"]],
87 | '+' => [["⢀","⣰","⣀","⠀"],["⠀","⠘","⠀","⠀"]],
88 | 'x' => [["⠠","⡀","⢀","⠄"],["⢠","⠊","⠑","⡄"]],
89 | '5' => [["⢸","⣉","⣉","⠁"],["⠠","⣀","⣀","⠇"]],
90 | 'T' => [["⠉","⢹","⠉","⠁"],["⠀","⢸","⠀","⠀"]],
91 | 'j' => [["⠀","⠀","⠀","⡅"],["⠠","⣀","⣀","⠇"]],
92 | 'd' => [["⢀","⠤","⢄","⡇"],["⠸","⣀","⡠","⡇"]],
93 | '~' => [["⠰","⠙","⠦","⠃"],["⠀","⠀","⠀","⠀"]],
94 | 'y' => [["⢠","⠀","⠀","⡄"],["⠈","⣒","⣒","⠇"]],
95 | '8' => [["⠰","⣉","⣉","⠆"],["⠸","⣀","⣀","⠇"]],
96 | '3' => [["⠈","⢉","⣩","⠃"],["⠠","⣀","⣀","⠇"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Mutual.grf:
--------------------------------------------------------------------------------
1 | {'=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
2 | '(' => [["⢀","⠎","⠀","⠀"],["⠈","⢆","⠀","⠀"]],
3 | 'E' => [["⢹","⣉","⡍","⠃"],["⠼","⠤","⠥","⠆"]],
4 | '\\' => [["⠐","⢄","⠀","⠀"],["⠀","⠀","⠑","⠄"]],
5 | ':' => [["⠀","⠰","⠀","⠀"],["⠀","⠰","⠀","⠀"]],
6 | 'N' => [["⢹","⠢","⡈","⡏"],["⠼","⠄","⠈","⠧"]],
7 | 'o' => [["⢀","⠤","⠤","⡀"],["⠘","⠤","⠤","⠃"]],
8 | '/' => [["⠀","⠀","⡠","⠂"],["⠠","⠊","⠀","⠀"]],
9 | 'p' => [["⢤","⠤","⠤","⡀"],["⣸","⡒","⠒","⠁"]],
10 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
11 | 'm' => [["⢤","⢄","⢄","⠀"],["⠼","⠸","⠸","⠄"]],
12 | '@' => [["⢠","⢊","⠭","⡆"],["⠈","⠢","⠭","⠁"]],
13 | 'n' => [["⢤","⡠","⢄","⠀"],["⠼","⠄","⠼","⠄"]],
14 | 'R' => [["⢹","⣉","⣉","⠆"],["⠼","⠄","⠱","⠄"]],
15 | 'W' => [["⢹","⠁","⠈","⡏"],["⠸","⠊","⠑","⠇"]],
16 | 'info' => ' Mutual font ','c' => [["⢀","⠤","⠤","⡀"],["⠘","⠤","⠤","⠂"]],
17 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
18 | '?' => [["⠊","⢉","⣉","⠆"],["⠀","⠰","⠀","⠀"]],
19 | 'L' => [["⢹","⠁","⠀","⠀"],["⠼","⠤","⠤","⠆"]],
20 | 'F' => [["⢹","⣉","⡍","⠃"],["⠼","⠄","⠁","⠀"]],
21 | 'M' => [["⢹","⢆","⡰","⡏"],["⠼","⠄","⠠","⠧"]],
22 | 'l' => [["⠀","⢹","⠀","⠀"],["⠀","⠼","⠄","⠀"]],
23 | '[' => [["⠀","⡏","⠉","⠀"],["⠀","⣇","⣀","⠀"]],
24 | '\'' => [["⠀","⠨","⠃","⠀"],["⠀","⠀","⠀","⠀"]],
25 | 'K' => [["⢹","⣁","⡨","⠋"],["⠼","⠄","⠨","⠦"]],
26 | "©" => [["⡔","⡩","⣩","⢢"],["⠣","⣑","⣒","⠜"]],
27 | 'S' => [["⢎","⣉","⣑","⠃"],["⠖","⠤","⠤","⠃"]],
28 | 'f' => [["⢀","⣎","⡉","⠂"],["⠠","⠧","⠀","⠀"]],
29 | '*' => [["⠠","⣴","⡤","⠀"],["⠀","⠁","⠁","⠀"]],
30 | '}' => [["⠈","⠱","⣀","⠀"],["⠠","⠜","⠀","⠀"]],
31 | '1' => [["⠀","⢺","⠀","⠀"],["⠀","⠼","⠄","⠀"]],
32 | 'C' => [["⡔","⠉","⠉","⠂"],["⠑","⠤","⠤","⠂"]],
33 | 'd' => [["⡠","⠤","⣹","⠀"],["⠣","⠤","⠺","⠄"]],
34 | 'j' => [["⠀","⠀","⢬","⠀"],["⠀","⢄","⡸","⠀"]],
35 | 'T' => [["⠋","⢹","⠉","⠃"],["⠀","⠼","⠄","⠀"]],
36 | '5' => [["⣏","⣉","⣉","⠃"],["⠢","⠤","⠤","⠃"]],
37 | '+' => [["⢀","⣰","⣀","⠀"],["⠀","⠘","⠀","⠀"]],
38 | 'x' => [["⢤","⠄","⢤","⠄"],["⠴","⠍","⠵","⠄"]],
39 | 's' => [["⢀","⠤","⠤","⠄"],["⠠","⠭","⠭","⠂"]],
40 | '{' => [["⢀","⡰","⠉","⠀"],["⠀","⠘","⠤","⠀"]],
41 | 'u' => [["⢤","⠀","⠠","⡄"],["⠘","⠤","⠔","⠧"]],
42 | '3' => [["⠋","⢉","⣝","⠁"],["⠢","⠤","⠤","⠃"]],
43 | 'y' => [["⢤","⠄","⢤","⠄"],["⣄","⡱","⠁","⠀"]],
44 | '8' => [["⢎","⣉","⣉","⠆"],["⠣","⠤","⠤","⠃"]],
45 | '~' => [["⢀","⠤","⣀","⠄"],["⠀","⠀","⠀","⠀"]],
46 | 'B' => [["⢹","⣉","⣉","⠆"],["⠼","⠤","⠤","⠃"]],
47 | '"' => [["⠨","⠃","⠝","⠀"],["⠀","⠀","⠀","⠀"]],
48 | '#' => [["⠠","⡦","⢴","⠄"],["⠺","⠒","⠗","⠀"]],
49 | ')' => [["⠈","⢆","⠀","⠀"],["⢀","⠎","⠀","⠀"]],
50 | 'z' => [["⢠","⠤","⢤","⠄"],["⠠","⠮","⠥","⠆"]],
51 | 't' => [["⠠","⡧","⠄","⠀"],["⠀","⠣","⠤","⠂"]],
52 | '^' => [["⠠","⠊","⠢","⠀"],["⠀","⠀","⠀","⠀"]],
53 | '$' => [["⠠","⣒","⣗","⠂"],["⠐","⠺","⠒","⠁"]],
54 | 'D' => [["⢹","⠉","⠑","⡄"],["⠼","⠤","⠔","⠁"]],
55 | 'h' => [["⢹","⡠","⢄","⠀"],["⠼","⠄","⠼","⠄"]],
56 | ';' => [["⠀","⠀","⠆","⠀"],["⠀","⢐","⠆","⠀"]],
57 | 'k' => [["⢹","⠀","⢤","⠄"],["⠼","⠍","⠵","⠄"]],
58 | 'Y' => [["⠙","⡅","⡝","⠁"],["⠀","⠼","⠄","⠀"]],
59 | 'G' => [["⡔","⠉","⣉","⡂"],["⠑","⠤","⠔","⠇"]],
60 | 'P' => [["⢹","⣉","⣉","⠆"],["⠼","⠄","⠀","⠀"]],
61 | 'v' => [["⢤","⠄","⠠","⡤"],["⠀","⠱","⠎","⠀"]],
62 | 'g' => [["⡠","⠤","⢄","⠄"],["⡪","⠭","⠥","⡀"]],
63 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
64 | 'V' => [["⠹","⡁","⢈","⠏"],["⠀","⠱","⠎","⠀"]],
65 | 'q' => [["⡠","⠤","⣠","⠄"],["⠑","⠒","⣺","⡀"]],
66 | 'O' => [["⡔","⠉","⠑","⡄"],["⠑","⠤","⠔","⠁"]],
67 | '!' => [["⠀","⢸","⠀","⠀"],["⠀","⠨","⠀","⠀"]],
68 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠀","⠀"]],
69 | '&' => [["⢰","⡩","⢂","⡀"],["⠣","⠬","⠪","⠄"]],
70 | '4' => [["⡠","⠊","⡇","⠀"],["⠉","⠩","⠯","⠁"]],
71 | 'Z' => [["⠋","⢉","⠝","⠁"],["⠴","⠥","⠤","⠆"]],
72 | 'e' => [["⢀","⠤","⠤","⡀"],["⠘","⠭","⠭","⠅"]],
73 | '6' => [["⣠","⣊","⣁","⠀"],["⠣","⠤","⠤","⠃"]],
74 | 'b' => [["⢹","⡠","⠤","⡀"],["⠼","⠢","⠤","⠃"]],
75 | 'A' => [["⠀","⡜","⢣","⠀"],["⠼","⠍","⠩","⠧"]],
76 | 'H' => [["⢹","⣁","⣈","⡏"],["⠼","⠄","⠠","⠧"]],
77 | ']' => [["⠀","⠉","⡇","⠀"],["⠀","⣀","⡇","⠀"]],
78 | 'Q' => [["⡔","⠉","⠑","⡄"],["⠑","⠤","⢔","⡁"]],
79 | '%' => [["⠪","⢕","⠔","⠀"],["⠐","⠑","⠭","⠂"]],
80 | 'J' => [["⠀","⠉","⡏","⠁"],["⠣","⠤","⠃","⠀"]],
81 | '0' => [["⡔","⢉","⠕","⡄"],["⠑","⠥","⠔","⠁"]],
82 | 'w' => [["⢤","⠄","⢤","⠄"],["⠈","⠎","⠎","⠀"]],
83 | 'i' => [["⠀","⢬","⠀","⠀"],["⠀","⠼","⠄","⠀"]],
84 | "£" => [["⣰","⣉","⡉","⠂"],["⠼","⠤","⠤","⠆"]],
85 | '9' => [["⢎","⣉","⣉","⡆"],["⠀","⠤","⠊","⠀"]],
86 | '7' => [["⠋","⠉","⡩","⠃"],["⠀","⠸","⠀","⠀"]],
87 | 'I' => [["⠈","⢹","⠉","⠀"],["⠠","⠼","⠤","⠀"]],
88 | 'X' => [["⠙","⢅","⠝","⠁"],["⠴","⠅","⠵","⠄"]],
89 | 'r' => [["⢤","⡠","⠤","⡀"],["⠼","⠄","⠀","⠁"]],
90 | 'U' => [["⢹","⠁","⠈","⡏"],["⠘","⠤","⠤","⠃"]],
91 | '|' => [["⠀","⢸","⠀","⠀"],["⠀","⠸","⠀","⠀"]],
92 | '<' => [["⠀","⡠","⠊","⠀"],["⠀","⠈","⠢","⠀"]],
93 | '>' => [["⠀","⠑","⢄","⠀"],["⠀","⠔","⠁","⠀"]],
94 | '2' => [["⠊","⠉","⣉","⠆"],["⠴","⠭","⠤","⠆"]],
95 | 'a' => [["⠠","⠤","⢄","⠀"],["⠪","⠭","⠝","⠄"]],
96 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⡲","⠀","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Reflections Dark.grf:
--------------------------------------------------------------------------------
1 | {'"' => [["⣯","⠇","⣯","⠇"],["⠀","⠀","⠀","⠀"]],
2 | 'f' => [["⣮","⣏","⡛","⠃"],["⠿","⠇","⠀","⠀"]],
3 | 'I' => [["⠀","⣯","⡇","⠀"],["⠀","⠿","⠇","⠀"]],
4 | '?' => [["⠛","⣋","⣯","⡇"],["⠀","⠶","⠆","⠀"]],
5 | 'c' => [["⣔","⡖","⠶","⠆"],["⠿","⠧","⠶","⠆"]],
6 | '}' => [["⠉","⣯","⣇","⡀"],["⠤","⠿","⠇","⠀"]],
7 | 'G' => [["⣮","⡏","⣛","⡃"],["⠿","⠧","⠷","⠇"]],
8 | 'J' => [["⠀","⠀","⣯","⡇"],["⠶","⠦","⠿","⠇"]],
9 | 'd' => [["⣔","⡖","⣯","⡇"],["⠿","⠧","⠿","⠇"]],
10 | 'u' => [["⣖","⡆","⣖","⡆"],["⠻","⠧","⠿","⠇"]],
11 | 'm' => [["⣖","⣖","⣖","⡄"],["⠿","⠝","⠽","⠇"]],
12 | 'A' => [["⣮","⣏","⣯","⡇"],["⠿","⠇","⠿","⠇"]],
13 | ';' => [["⠀","⠯","⠇","⠀"],["⠀","⣯","⠇","⠀"]],
14 | 'H' => [["⣯","⣇","⣯","⡇"],["⠿","⠇","⠿","⠇"]],
15 | '7' => [["⠛","⢋","⣯","⠇"],["⠀","⠾","⠏","⠀"]],
16 | '4' => [["⣯","⡇","⣯","⡇"],["⠉","⠉","⠿","⠇"]],
17 | 'w' => [["⣖","⡦","⣖","⡆"],["⠻","⠿","⠿","⠃"]],
18 | ')' => [["⠈","⢹","⣵","⠀"],["⠠","⠼","⠟","⠀"]],
19 | '8' => [["⢮","⣏","⣯","⠇"],["⠿","⠧","⠿","⠇"]],
20 | 'x' => [["⢖","⣆","⣖","⠆"],["⠿","⠇","⠿","⠇"]],
21 | 'Q' => [["⣮","⡏","⣯","⡇"],["⠿","⠧","⣫","⡆"]],
22 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⣯","⠇","⠀"]],
23 | 'e' => [["⣔","⡖","⣖","⡆"],["⠿","⠯","⠭","⠅"]],
24 | '3' => [["⠛","⣋","⣯","⠇"],["⠶","⠦","⠿","⠇"]],
25 | 'O' => [["⣮","⡏","⣯","⡇"],["⠿","⠧","⠿","⠇"]],
26 | 'M' => [["⣯","⣗","⣯","⡇"],["⠿","⠝","⠽","⠇"]],
27 | 'R' => [["⣯","⣏","⡯","⠃"],["⠿","⠇","⠿","⠆"]],
28 | 'Z' => [["⠛","⣫","⡯","⠃"],["⠾","⠯","⠶","⠆"]],
29 | 'y' => [["⣖","⡆","⣖","⡆"],["⣙","⣓","⣿","⡇"]],
30 | 'D' => [["⣯","⡏","⣯","⡆"],["⠿","⠧","⠿","⠇"]],
31 | 'W' => [["⣯","⣗","⣯","⡇"],["⠿","⠟","⠿","⠇"]],
32 | '_' => [["⠀","⠀","⠀","⠀"],["⣖","⣶","⣶","⣶"]],
33 | '<' => [["⢀","⣴","⠝","⠀"],["⠀","⠙","⠷","⠀"]],
34 | '$' => [["⣖","⣞","⣓","⡂"],["⠶","⢦","⡷","⠇"]],
35 | 'E' => [["⣮","⣏","⡛","⠃"],["⠿","⠧","⠶","⠆"]],
36 | '@' => [["⣮","⡏","⣯","⡆"],["⠻","⠧","⠭","⠅"]],
37 | 'K' => [["⣯","⣧","⡯","⠃"],["⠿","⠏","⠿","⠆"]],
38 | 's' => [["⣖","⣖","⣒","⡂"],["⠶","⠦","⠷","⠇"]],
39 | '~' => [["⣮","⠷","⣮","⠇"],["⠀","⠀","⠀","⠀"]],
40 | '5' => [["⣯","⣏","⣛","⡃"],["⠶","⠦","⠿","⠃"]],
41 | 'j' => [["⠀","⠀","⡭","⡅"],["⣤","⣄","⣿","⡇"]],
42 | 'k' => [["⣯","⡇","⡤","⡄"],["⠿","⠏","⠿","⠆"]],
43 | '&' => [["⢮","⡏","⣍","⣄"],["⠿","⠧","⠷","⠇"]],
44 | "£" => [["⣮","⣏","⡛","⠃"],["⠿","⠧","⠶","⠆"]],
45 | 'U' => [["⣯","⡇","⣯","⡇"],["⠻","⠧","⠿","⠇"]],
46 | 'o' => [["⣔","⡖","⣖","⡆"],["⠿","⠧","⠿","⠃"]],
47 | '2' => [["⠛","⣫","⡯","⠃"],["⠾","⠯","⠶","⠆"]],
48 | '^' => [["⡠","⣞","⡦","⡀"],["⠀","⠿","⠇","⠀"]],
49 | 'i' => [["⠀","⡭","⡅","⠀"],["⠀","⠿","⠇","⠀"]],
50 | 'T' => [["⠉","⣯","⡏","⠁"],["⠀","⠿","⠇","⠀"]],
51 | 'p' => [["⣖","⡖","⣖","⡆"],["⣿","⡗","⠛","⠃"]],
52 | 't' => [["⣯","⡗","⠒","⠀"],["⠿","⠧","⠶","⠆"]],
53 | 'n' => [["⣖","⡖","⣖","⡄"],["⠿","⠇","⠿","⠇"]],
54 | '+' => [["⠀","⡤","⡄","⠀"],["⠉","⠿","⠏","⠁"]],
55 | '9' => [["⣯","⡏","⣯","⡇"],["⠭","⠭","⠿","⠃"]],
56 | 'F' => [["⣮","⣏","⡛","⠃"],["⠿","⠇","⠀","⠀"]],
57 | '0' => [["⣮","⡏","⣯","⡇"],["⠿","⠧","⠿","⠃"]],
58 | '\\' => [["⠻","⣽","⡀","⠀"],["⠀","⠈","⠿","⠆"]],
59 | '-' => [["⢠","⢤","⣤","⡄"],["⠈","⠉","⠉","⠁"]],
60 | 'X' => [["⢯","⣇","⣯","⠇"],["⠿","⠇","⠿","⠇"]],
61 | ':' => [["⠀","⠯","⠇","⠀"],["⠀","⠯","⠇","⠀"]],
62 | '(' => [["⢰","⣽","⠉","⠀"],["⠘","⠿","⠤","⠀"]],
63 | '1' => [["⠈","⣯","⡇","⠀"],["⠠","⠿","⠧","⠀"]],
64 | '\'' => [["⠀","⣯","⠇","⠀"],["⠀","⠀","⠀","⠀"]],
65 | 'N' => [["⣯","⡏","⣯","⡆"],["⠿","⠇","⠿","⠇"]],
66 | '%' => [["⠛","⣸","⡽","⠃"],["⠾","⠏","⠰","⠆"]],
67 | 'C' => [["⣮","⡏","⠛","⠃"],["⠿","⠧","⠶","⠆"]],
68 | 'z' => [["⠒","⣲","⡲","⠂"],["⠾","⠯","⠶","⠆"]],
69 | 'V' => [["⣯","⡇","⣯","⡇"],["⠙","⠷","⠟","⠁"]],
70 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠯","⠇","⠀"]],
71 | 'v' => [["⣖","⡆","⣖","⡆"],["⠙","⠷","⠟","⠁"]],
72 | 'r' => [["⣖","⡖","⠶","⠆"],["⠿","⠇","⠀","⠀"]],
73 | 'B' => [["⣯","⣏","⣯","⠇"],["⠿","⠧","⠿","⠇"]],
74 | 'a' => [["⣔","⡖","⣖","⡆"],["⠿","⠧","⠻","⠇"]],
75 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
76 | 'h' => [["⣯","⡗","⣖","⡆"],["⠿","⠇","⠿","⠇"]],
77 | '=' => [["⠠","⠤","⠤","⠄"],["⠈","⠉","⠉","⠁"]],
78 | '#' => [["⢴","⢴","⣴","⠄"],["⠺","⠻","⠺","⠂"]],
79 | '/' => [["⠀","⣸","⡽","⠃"],["⠾","⠏","⠀","⠀"]],
80 | ']' => [["⠈","⢹","⣽","⠀"],["⠠","⠼","⠿","⠀"]],
81 | 'P' => [["⣯","⡏","⣯","⡆"],["⠿","⠏","⠉","⠁"]],
82 | '6' => [["⣯","⡯","⡭","⡀"],["⠿","⠧","⠿","⠇"]],
83 | 'info' => ' Reflections Dark font ','!' => [["⠀","⣯","⡇","⠀"],["⠀","⠭","⠅","⠀"]],
84 | '[' => [["⢸","⣽","⠉","⠀"],["⠸","⠿","⠤","⠀"]],
85 | "©" => [["⡎","⡩","⡭","⢱"],["⢇","⣛","⣓","⡸"]],
86 | '{' => [["⣀","⣯","⡏","⠁"],["⠀","⠿","⠧","⠄"]],
87 | '>' => [["⠘","⢵","⣄","⠀"],["⠰","⠟","⠁","⠀"]],
88 | 'L' => [["⣯","⡇","⠀","⠀"],["⠿","⠧","⠶","⠆"]],
89 | 'S' => [["⣯","⣏","⣛","⡃"],["⠶","⠦","⠷","⠇"]],
90 | 'g' => [["⣖","⡖","⣖","⡆"],["⣙","⣓","⣿","⡇"]],
91 | 'q' => [["⣖","⡖","⣖","⡆"],["⠙","⠓","⣿","⡇"]],
92 | '*' => [["⢀","⡤","⣄","⠀"],["⠐","⠿","⠗","⠀"]],
93 | 'b' => [["⣯","⡗","⣖","⡆"],["⠿","⠧","⠿","⠃"]],
94 | 'l' => [["⠀","⢹","⣽","⠀"],["⠀","⠸","⠿","⠀"]],
95 | '|' => [["⠀","⣯","⡇","⠀"],["⠀","⠿","⠇","⠀"]],
96 | 'Y' => [["⢯","⣧","⣯","⠇"],["⠀","⠿","⠇","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Reflections.grf:
--------------------------------------------------------------------------------
1 | {'O' => [["⣎","⡏","⣏","⡆"],["⠻","⠧","⠿","⠃"]],
2 | '3' => [["⠊","⣋","⣏","⠆"],["⠲","⠦","⠿","⠃"]],
3 | 'e' => [["⡔","⣖","⣖","⡄"],["⠻","⠧","⠶","⠂"]],
4 | 'Q' => [["⣎","⡏","⣏","⡆"],["⠻","⠧","⣿","⡇"]],
5 | 'x' => [["⢖","⣆","⣖","⠆"],["⠿","⠇","⠿","⠇"]],
6 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⣴","⠕","⠀"]],
7 | '8' => [["⢎","⣏","⣏","⠆"],["⠻","⠧","⠿","⠃"]],
8 | ')' => [["⠈","⢹","⣱","⠀"],["⠠","⠼","⠟","⠀"]],
9 | '4' => [["⢀","⢴","⣹","⠀"],["⠉","⠹","⠿","⠁"]],
10 | 'w' => [["⡆","⣆","⡆","⡆"],["⠻","⠗","⠿","⠃"]],
11 | '7' => [["⠋","⢋","⣏","⠇"],["⠀","⠾","⠏","⠀"]],
12 | ';' => [["⠀","⢠","⢤","⠀"],["⠀","⣴","⠕","⠀"]],
13 | 'H' => [["⣏","⣇","⣏","⡇"],["⠿","⠇","⠿","⠇"]],
14 | 'A' => [["⡎","⣏","⡏","⡆"],["⠿","⠇","⠿","⠇"]],
15 | 'd' => [["⡔","⡖","⡏","⡇"],["⠻","⠧","⠿","⠇"]],
16 | 'u' => [["⡖","⡆","⡖","⡆"],["⠻","⠧","⠿","⠇"]],
17 | 'm' => [["⡖","⡦","⡖","⡄"],["⠿","⠟","⠿","⠇"]],
18 | 'G' => [["⣎","⡏","⣋","⡃"],["⠻","⠧","⠿","⠇"]],
19 | 'J' => [["⠀","⠀","⡏","⡇"],["⠲","⠦","⠿","⠃"]],
20 | '}' => [["⠉","⡏","⣆","⡀"],["⠤","⠿","⠃","⠀"]],
21 | 'c' => [["⡔","⡖","⠖","⠄"],["⠻","⠧","⠶","⠂"]],
22 | '?' => [["⠊","⣋","⣏","⡆"],["⠀","⠶","⠆","⠀"]],
23 | 'I' => [["⠀","⡏","⡇","⠀"],["⠀","⠿","⠇","⠀"]],
24 | 'f' => [["⣎","⣏","⠋","⠂"],["⠿","⠇","⠀","⠀"]],
25 | '"' => [["⠮","⠆","⠮","⠆"],["⠀","⠀","⠀","⠀"]],
26 | 'o' => [["⡔","⡖","⡖","⡄"],["⠻","⠧","⠿","⠃"]],
27 | 'U' => [["⣏","⡇","⣏","⡇"],["⠻","⠧","⠿","⠃"]],
28 | "£" => [["⣎","⣏","⡋","⠂"],["⠿","⠧","⠶","⠆"]],
29 | '&' => [["⢎","⣏","⣋","⡂"],["⠻","⠧","⠿","⠇"]],
30 | 'k' => [["⡏","⡇","⡤","⡄"],["⠿","⠏","⠿","⠆"]],
31 | '5' => [["⣏","⣏","⣋","⠃"],["⠲","⠦","⠿","⠃"]],
32 | 'j' => [["⠀","⠀","⡮","⡆"],["⢤","⣄","⣷","⠇"]],
33 | 's' => [["⢔","⣖","⠖","⠄"],["⠲","⠮","⠿","⠂"]],
34 | 'K' => [["⡏","⡧","⡫","⠃"],["⠿","⠏","⠿","⠆"]],
35 | '~' => [["⣔","⡦","⣖","⠆"],["⠀","⠀","⠀","⠀"]],
36 | 'E' => [["⣎","⣏","⡋","⠃"],["⠻","⠧","⠶","⠆"]],
37 | '$' => [["⠯","⣏","⡏","⠃"],["⠦","⠿","⠯","⠇"]],
38 | '@' => [["⣎","⣏","⣏","⡆"],["⠻","⠧","⠭","⠅"]],
39 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
40 | '<' => [["⢀","⢔","⠝","⠀"],["⠀","⠙","⠷","⠀"]],
41 | 'W' => [["⣇","⡗","⣇","⡇"],["⠻","⠧","⠿","⠃"]],
42 | 'D' => [["⣏","⡏","⣏","⡆"],["⠿","⠧","⠿","⠃"]],
43 | 'y' => [["⡖","⡆","⡖","⡆"],["⣙","⣓","⣿","⠇"]],
44 | 'Z' => [["⠋","⣫","⡫","⠃"],["⠾","⠯","⠶","⠆"]],
45 | 'R' => [["⣏","⣯","⡫","⠃"],["⠿","⠏","⠻","⠆"]],
46 | 'M' => [["⡏","⡗","⡏","⡇"],["⠿","⠗","⠿","⠇"]],
47 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
48 | 'B' => [["⡏","⣏","⣏","⠆"],["⠿","⠧","⠿","⠃"]],
49 | 'a' => [["⡔","⡖","⡔","⡆"],["⠻","⠧","⠻","⠇"]],
50 | 'r' => [["⡖","⡖","⠖","⠄"],["⠿","⠇","⠀","⠀"]],
51 | 'v' => [["⡖","⡆","⡖","⡆"],["⠙","⠧","⠟","⠁"]],
52 | 'V' => [["⣏","⡇","⣏","⡇"],["⠙","⠧","⠟","⠁"]],
53 | 'z' => [["⠖","⡲","⡲","⠂"],["⠾","⠯","⠶","⠆"]],
54 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠾","⠆","⠀"]],
55 | 'C' => [["⣎","⡏","⠋","⠂"],["⠻","⠧","⠶","⠂"]],
56 | '%' => [["⠮","⢆","⢔","⠆"],["⠰","⠟","⠱","⠷"]],
57 | 'N' => [["⣏","⡏","⣏","⡆"],["⠿","⠇","⠿","⠇"]],
58 | '1' => [["⠐","⣏","⡇","⠀"],["⠠","⠿","⠧","⠀"]],
59 | '\'' => [["⢠","⡪","⠂","⠀"],["⠀","⠀","⠀","⠀"]],
60 | '(' => [["⢰","⣹","⠉","⠀"],["⠘","⠿","⠤","⠀"]],
61 | 'X' => [["⢏","⣇","⣏","⠇"],["⠿","⠇","⠿","⠇"]],
62 | ':' => [["⠀","⡤","⡄","⠀"],["⠀","⠾","⠆","⠀"]],
63 | '\\' => [["⠫","⣢","⡀","⠀"],["⠀","⠈","⠻","⠆"]],
64 | '-' => [["⢀","⣀","⣀","⡀"],["⠀","⠀","⠀","⠀"]],
65 | 'F' => [["⣎","⣏","⡋","⠃"],["⠿","⠇","⠀","⠀"]],
66 | '0' => [["⣎","⡏","⣏","⡆"],["⠻","⠧","⠿","⠃"]],
67 | '9' => [["⢎","⣏","⣏","⡆"],["⠲","⠦","⠿","⠃"]],
68 | '+' => [["⠀","⡤","⡄","⠀"],["⠉","⠿","⠏","⠁"]],
69 | 'n' => [["⡖","⡖","⡖","⡄"],["⠿","⠇","⠿","⠇"]],
70 | 't' => [["⡏","⡧","⠀","⠀"],["⠻","⠧","⠶","⠂"]],
71 | '^' => [["⡠","⣞","⡦","⡀"],["⠀","⠿","⠇","⠀"]],
72 | 'i' => [["⠀","⡮","⡆","⠀"],["⠀","⠿","⠇","⠀"]],
73 | 'T' => [["⠋","⣏","⡏","⠃"],["⠀","⠿","⠇","⠀"]],
74 | 'p' => [["⡖","⡖","⡖","⡄"],["⣿","⡧","⠿","⠃"]],
75 | '2' => [["⠊","⣫","⡫","⠂"],["⠾","⠯","⠶","⠆"]],
76 | 'Y' => [["⢏","⣇","⣏","⠇"],["⠀","⠿","⠇","⠀"]],
77 | '|' => [["⠀","⡏","⡇","⠀"],["⠀","⠿","⠇","⠀"]],
78 | 'l' => [["⠀","⢹","⣹","⠀"],["⠀","⠸","⠿","⠀"]],
79 | '*' => [["⢀","⡤","⣄","⠀"],["⠐","⠿","⠗","⠀"]],
80 | 'b' => [["⡏","⡗","⡖","⡄"],["⠿","⠧","⠿","⠃"]],
81 | 'q' => [["⡔","⡖","⡖","⡆"],["⠻","⠧","⣿","⡇"]],
82 | 'g' => [["⡔","⡖","⡖","⡆"],["⢬","⣍","⣿","⠇"]],
83 | 'L' => [["⡏","⡇","⠀","⠀"],["⠿","⠧","⠶","⠆"]],
84 | 'S' => [["⠯","⣏","⡋","⠃"],["⠶","⠦","⠿","⠇"]],
85 | "©" => [["⡎","⡩","⡭","⢱"],["⢇","⣙","⣓","⡸"]],
86 | '{' => [["⣀","⡎","⡏","⠁"],["⠀","⠻","⠧","⠄"]],
87 | '>' => [["⠘","⢕","⢄","⠀"],["⠰","⠟","⠁","⠀"]],
88 | '[' => [["⠀","⣏","⡏","⠀"],["⠀","⠿","⠧","⠀"]],
89 | '!' => [["⠀","⢸","⣹","⠀"],["⠀","⠰","⠷","⠀"]],
90 | 'info' => ' Reflections font ','6' => [["⣎","⣏","⣋","⠂"],["⠻","⠧","⠿","⠃"]],
91 | ']' => [["⠀","⢹","⣹","⠀"],["⠀","⠼","⠿","⠀"]],
92 | 'P' => [["⣏","⡏","⣏","⡆"],["⠿","⠏","⠉","⠀"]],
93 | '/' => [["⠀","⣠","⡪","⠃"],["⠾","⠋","⠀","⠀"]],
94 | '#' => [["⢴","⢴","⣴","⠄"],["⠺","⠻","⠺","⠂"]],
95 | '=' => [["⠠","⠤","⠤","⠄"],["⠈","⠉","⠉","⠁"]],
96 | 'h' => [["⡏","⡗","⡖","⡄"],["⠿","⠇","⠿","⠇"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Tentacle Bold.grf:
--------------------------------------------------------------------------------
1 | {'0' => [["⢸","⣿","⠉","⡇"],["⠸","⠿","⠤","⠇"]],
2 | 'info' => ' Tentacle Bold font by DamienG https://damieng.com','@' => [["⣿","⡏","⡭","⡇"],["⠿","⠧","⠭","⠁"]],
3 | 'I' => [["⠉","⣿","⡏","⠁"],["⠤","⠿","⠧","⠄"]],
4 | 'h' => [["⢹","⣿","⠤","⡄"],["⠼","⠿","⠄","⠧"]],
5 | 'q' => [["⡤","⢤","⣤","⠄"],["⠓","⣹","⣿","⡀"]],
6 | 'C' => [["⣿","⡏","⠑","⠃"],["⠿","⠧","⠤","⠆"]],
7 | '7' => [["⠘","⣉","⣿","⡇"],["⠀","⠀","⠿","⠇"]],
8 | 'j' => [["⠀","⢬","⣭","⠀"],["⢀","⣸","⣿","⠀"]],
9 | '<' => [["⢀","⣴","⠟","⠁"],["⠀","⠙","⠷","⠄"]],
10 | 'U' => [["⢹","⠁","⣿","⡏"],["⠸","⠤","⠿","⠇"]],
11 | 'o' => [["⡤","⠤","⣤","⡄"],["⠧","⠤","⠿","⠇"]],
12 | 'n' => [["⢤","⣤","⠤","⡄"],["⠼","⠿","⠠","⠧"]],
13 | '6' => [["⢸","⣿","⣙","⡀"],["⠸","⠿","⠤","⠇"]],
14 | 'L' => [["⢹","⣿","⠁","⠀"],["⠼","⠿","⠤","⠆"]],
15 | 'P' => [["⢹","⣿","⢉","⡇"],["⠼","⠿","⠄","⠀"]],
16 | '|' => [["⠀","⣿","⡇","⠀"],["⠀","⠿","⠇","⠀"]],
17 | 'O' => [["⢸","⠉","⣿","⡇"],["⠸","⠤","⠿","⠇"]],
18 | '+' => [["⣀","⣶","⣆","⡀"],["⠀","⠛","⠃","⠀"]],
19 | 'd' => [["⡤","⠬","⣿","⡇"],["⠧","⠔","⠿","⠧"]],
20 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
21 | ')' => [["⠀","⢻","⣦","⠀"],["⠀","⠾","⠋","⠀"]],
22 | '~' => [["⠛","⠙","⠚","⠃"],["⠀","⠀","⠀","⠀"]],
23 | 'V' => [["⠹","⣁","⣿","⠏"],["⠀","⠹","⠏","⠀"]],
24 | 'E' => [["⢹","⣿","⣉","⠃"],["⠼","⠿","⠤","⠆"]],
25 | '*' => [["⣀","⣴","⣄","⡀"],["⠘","⠋","⠛","⠀"]],
26 | 'D' => [["⢹","⠉","⣿","⡇"],["⠼","⠤","⠿","⠇"]],
27 | '4' => [["⣇","⣸","⣿","⡀"],["⠀","⠼","⠿","⠄"]],
28 | 'Y' => [["⢹","⣀","⣿","⡏"],["⠠","⠤","⠿","⠇"]],
29 | 'v' => [["⢤","⣤","⠠","⡤"],["⠸","⠿","⠊","⠀"]],
30 | '^' => [["⡠","⢾","⣦","⡀"],["⠀","⠀","⠀","⠀"]],
31 | '"' => [["⠀","⠇","⠿","⠇"],["⠀","⠀","⠀","⠀"]],
32 | '5' => [["⢸","⣉","⣙","⡀"],["⠰","⠤","⠿","⠇"]],
33 | '{' => [["⣀","⣿","⠏","⠁"],["⠀","⠿","⠧","⠄"]],
34 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
35 | 'K' => [["⢹","⣿","⡡","⠋"],["⠼","⠿","⠌","⠦"]],
36 | 'X' => [["⠹","⣿","⡸","⠁"],["⠼","⠿","⠸","⠄"]],
37 | 'y' => [["⢤","⠄","⣤","⡤"],["⣘","⣒","⣿","⡇"]],
38 | 'W' => [["⢹","⣡","⣌","⡏"],["⠸","⠟","⠻","⠇"]],
39 | '!' => [["⠀","⣿","⡇","⠀"],["⠀","⠭","⠅","⠀"]],
40 | '=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
41 | 'p' => [["⢤","⣤","⠤","⡄"],["⣸","⣿","⡑","⠃"]],
42 | '}' => [["⠉","⢿","⣇","⡀"],["⠤","⠿","⠇","⠀"]],
43 | '[' => [["⢸","⣿","⠉","⠀"],["⠸","⠿","⠤","⠀"]],
44 | '?' => [["⠘","⣉","⣿","⡇"],["⠀","⠥","⠀","⠀"]],
45 | '8' => [["⠸","⣉","⣿","⠇"],["⠸","⠤","⠿","⠇"]],
46 | ';' => [["⠀","⠰","⠶","⠀"],["⠀","⣰","⣶","⠀"]],
47 | '\'' => [["⠀","⠼","⠿","⠀"],["⠀","⠀","⠀","⠀"]],
48 | 'M' => [["⡏","⡏","⣿","⡇"],["⠧","⠡","⠿","⠇"]],
49 | '(' => [["⢠","⣾","⠃","⠀"],["⠈","⠻","⠆","⠀"]],
50 | 'J' => [["⠀","⢹","⣿","⠁"],["⢀","⣸","⣿","⠀"]],
51 | 'i' => [["⠠","⣭","⡅","⠀"],["⠀","⠿","⠧","⠀"]],
52 | '%' => [["⠯","⢟","⠔","⠁"],["⠔","⠱","⠽","⠇"]],
53 | '#' => [["⢴","⢴","⣶","⠄"],["⠙","⠙","⠛","⠁"]],
54 | 'c' => [["⣤","⡤","⢤","⠀"],["⠿","⠧","⠤","⠆"]],
55 | '9' => [["⢸","⣉","⣿","⡇"],["⠀","⠦","⠿","⠇"]],
56 | 'T' => [["⠋","⣿","⡏","⠃"],["⠠","⠿","⠧","⠀"]],
57 | "©" => [["⡔","⣭","⡭","⢢"],["⠣","⣛","⣓","⠜"]],
58 | 'Q' => [["⣿","⡏","⠉","⡇"],["⠿","⠧","⢧","⠇"]],
59 | '1' => [["⠀","⢹","⣿","⠀"],["⠀","⠸","⠿","⠀"]],
60 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠆","⠀"]],
61 | 'R' => [["⢹","⣿","⣉","⡇"],["⠼","⠿","⠈","⠦"]],
62 | '2' => [["⢀","⣋","⣿","⡇"],["⠸","⠤","⠤","⠆"]],
63 | 'm' => [["⡤","⡤","⣤","⡄"],["⠇","⠇","⠿","⠇"]],
64 | '>' => [["⠈","⠻","⣦","⡀"],["⠠","⠾","⠋","⠀"]],
65 | 'H' => [["⢹","⣿","⣈","⡏"],["⠼","⠿","⠠","⠧"]],
66 | 'a' => [["⠠","⢤","⣤","⠀"],["⠯","⠽","⠿","⠄"]],
67 | 'r' => [["⢤","⣄","⠤","⡄"],["⠼","⠿","⠄","⠀"]],
68 | ':' => [["⠀","⠶","⠆","⠀"],["⠀","⠶","⠆","⠀"]],
69 | 'Z' => [["⠋","⣩","⡿","⠃"],["⠾","⠿","⠤","⠆"]],
70 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
71 | '/' => [["⠀","⢀","⣴","⠟"],["⠴","⠟","⠁","⠀"]],
72 | 'x' => [["⣤","⡄","⢤","⡄"],["⠾","⠯","⠹","⠆"]],
73 | 'z' => [["⡤","⢤","⣤","⠄"],["⠴","⠿","⠥","⠆"]],
74 | '3' => [["⠀","⣋","⣿","⠇"],["⠰","⠤","⠿","⠇"]],
75 | 'u' => [["⢤","⠠","⣤","⡄"],["⠸","⠔","⠿","⠧"]],
76 | 'F' => [["⢹","⣿","⣉","⠃"],["⠼","⠿","⠄","⠀"]],
77 | 'S' => [["⢸","⣉","⣑","⡃"],["⠦","⠤","⠿","⠇"]],
78 | ']' => [["⠈","⢹","⣿","⠀"],["⠠","⠼","⠿","⠀"]],
79 | 'N' => [["⢹","⠉","⣿","⡇"],["⠼","⠠","⠿","⠧"]],
80 | 'w' => [["⢤","⢄","⡠","⡤"],["⠸","⠟","⠻","⠇"]],
81 | 'l' => [["⠈","⣿","⡇","⠀"],["⠀","⠿","⠧","⠀"]],
82 | '$' => [["⢰","⣶","⣚","⡂"],["⠐","⠖","⠛","⠃"]],
83 | 'f' => [["⢀","⣿","⣏","⡃"],["⠠","⠿","⠧","⠀"]],
84 | 'k' => [["⢹","⣿","⢀","⠤"],["⠼","⠿","⠑","⠤"]],
85 | 's' => [["⡤","⠤","⠤","⠀"],["⠭","⠭","⠿","⠇"]],
86 | 'G' => [["⣿","⡏","⠚","⠀"],["⠿","⠧","⠽","⠁"]],
87 | 'e' => [["⣤","⡤","⠤","⡄"],["⠿","⠯","⠭","⠅"]],
88 | 'A' => [["⢸","⣉","⣿","⡇"],["⠼","⠄","⠿","⠧"]],
89 | 't' => [["⢼","⣿","⠄","⠀"],["⠸","⠿","⠤","⠆"]],
90 | 'b' => [["⢹","⣿","⡠","⡄"],["⠸","⠿","⠤","⠇"]],
91 | '&' => [["⢿","⣏","⠇","⡀"],["⠿","⠧","⠽","⠥"]],
92 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⣰","⣶","⠀"]],
93 | '\\' => [["⠻","⣦","⡀","⠀"],["⠀","⠈","⠻","⠦"]],
94 | 'g' => [["⡤","⠤","⣠","⡤"],["⣓","⣊","⣿","⡇"]],
95 | 'B' => [["⢹","⢉","⣿","⠇"],["⠼","⠤","⠿","⠇"]],
96 | "£" => [["⣸","⣿","⡙","⠀"],["⠼","⠿","⠤","⠆"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/Tentacle.grf:
--------------------------------------------------------------------------------
1 | {'e' => [["⢠","⡤","⠤","⡄"],["⠸","⠯","⠭","⠅"]],
2 | '~' => [["⠘","⠙","⠚","⠀"],["⠀","⠀","⠀","⠀"]],
3 | '<' => [["⢀","⡴","⠋","⠀"],["⠀","⠙","⠦","⠀"]],
4 | '\\' => [["⠳","⣄","⠀","⠀"],["⠀","⠈","⠳","⠄"]],
5 | '/' => [["⠀","⢀","⡴","⠃"],["⠴","⠋","⠀","⠀"]],
6 | '1' => [["⠀","⢹","⡇","⠀"],["⠀","⠸","⠇","⠀"]],
7 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
8 | 'y' => [["⢤","⠄","⣤","⠄"],["⣘","⣒","⣿","⠀"]],
9 | '^' => [["⡠","⠺","⣦","⡀"],["⠀","⠀","⠀","⠀"]],
10 | 'U' => [["⢹","⠁","⢸","⡏"],["⠸","⠤","⠼","⠇"]],
11 | 'H' => [["⢹","⣇","⣹","⠁"],["⠼","⠇","⠼","⠄"]],
12 | 'M' => [["⢹","⢹","⢹","⡏"],["⠼","⠌","⠼","⠧"]],
13 | '!' => [["⠀","⢸","⡇","⠀"],["⠀","⠨","⠅","⠀"]],
14 | 'L' => [["⢹","⡏","⠀","⠀"],["⠼","⠧","⠴","⠀"]],
15 | ')' => [["⠀","⢳","⡄","⠀"],["⠀","⠞","⠁","⠀"]],
16 | 'q' => [["⢠","⠤","⢤","⡤"],["⠘","⠒","⣹","⣇"]],
17 | 'N' => [["⢹","⠉","⣿","⠀"],["⠼","⠠","⠿","⠄"]],
18 | 'W' => [["⢹","⢡","⡌","⡏"],["⠸","⠟","⠻","⠇"]],
19 | 'c' => [["⢠","⡤","⢤","⠀"],["⠸","⠧","⠤","⠆"]],
20 | '5' => [["⢸","⣉","⣙","⡀"],["⠰","⠤","⠼","⠇"]],
21 | 'B' => [["⢹","⢉","⣹","⠇"],["⠼","⠤","⠼","⠇"]],
22 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⣰","⡆","⠀"]],
23 | 'u' => [["⢤","⠀","⢤","⡄"],["⠸","⠤","⠺","⠧"]],
24 | 'D' => [["⢹","⠉","⢹","⡇"],["⠼","⠤","⠼","⠇"]],
25 | '(' => [["⠀","⣴","⠃","⠀"],["⠀","⠙","⠆","⠀"]],
26 | '"' => [["⠀","⠇","⠿","⠀"],["⠀","⠀","⠀","⠀"]],
27 | 't' => [["⠠","⣿","⠤","⠄"],["⠀","⠿","⠤","⠆"]],
28 | 's' => [["⢠","⠤","⠤","⠀"],["⠨","⠭","⠽","⠇"]],
29 | 'v' => [["⢤","⡄","⢤","⠄"],["⠸","⠗","⠁","⠀"]],
30 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
31 | 'l' => [["⠀","⢹","⡇","⠀"],["⠀","⠸","⠧","⠀"]],
32 | '#' => [["⠠","⡦","⣶","⠄"],["⠈","⠋","⠛","⠁"]],
33 | ']' => [["⠀","⠉","⣿","⠀"],["⠀","⠤","⠿","⠀"]],
34 | '}' => [["⠈","⠹","⣇","⡀"],["⠠","⠼","⠇","⠀"]],
35 | 'p' => [["⢤","⡤","⠤","⡄"],["⣸","⣏","⠒","⠃"]],
36 | '6' => [["⢸","⣏","⣙","⡀"],["⠸","⠧","⠤","⠇"]],
37 | 'g' => [["⢠","⠤","⢄","⡤"],["⢘","⣒","⣹","⡇"]],
38 | 'i' => [["⠀","⢬","⡅","⠀"],["⠀","⠸","⠧","⠀"]],
39 | 'info' => ' Tentacle font by DamienG https://damieng.com','d' => [["⢠","⠤","⢽","⡇"],["⠸","⠤","⠺","⠧"]],
40 | 'n' => [["⢤","⡤","⢤","⠀"],["⠼","⠇","⠼","⠄"]],
41 | ':' => [["⠀","⠰","⠆","⠀"],["⠀","⠰","⠆","⠀"]],
42 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
43 | 'R' => [["⢹","⣏","⣉","⡇"],["⠼","⠇","⠵","⠄"]],
44 | 'T' => [["⠘","⢹","⡏","⠃"],["⠀","⠼","⠧","⠀"]],
45 | '?' => [["⠘","⣉","⣹","⡇"],["⠀","⠥","⠀","⠀"]],
46 | '[' => [["⠀","⣿","⠉","⠀"],["⠀","⠿","⠤","⠀"]],
47 | 'J' => [["⠀","⢹","⡏","⠀"],["⢀","⣸","⡇","⠀"]],
48 | '3' => [["⠀","⢋","⣹","⠇"],["⠰","⠤","⠼","⠇"]],
49 | 'K' => [["⢹","⣏","⠜","⠁"],["⠼","⠧","⠱","⠄"]],
50 | 'S' => [["⢸","⣉","⣑","⡃"],["⠦","⠤","⠼","⠇"]],
51 | 'V' => [["⠹","⣁","⡿","⠁"],["⠀","⠹","⠁","⠀"]],
52 | 'b' => [["⢹","⣇","⠤","⡄"],["⠸","⠧","⠤","⠇"]],
53 | '4' => [["⢸","⣀","⣿","⡀"],["⠀","⠠","⠿","⠄"]],
54 | 'Y' => [["⢹","⣀","⣸","⡏"],["⠠","⠤","⠼","⠇"]],
55 | ';' => [["⠀","⠰","⠆","⠀"],["⠀","⣰","⡆","⠀"]],
56 | '8' => [["⠸","⣉","⣹","⠇"],["⠸","⠤","⠼","⠇"]],
57 | 'F' => [["⢹","⣏","⣉","⠃"],["⠼","⠧","⠄","⠀"]],
58 | '\'' => [["⠀","⠼","⠇","⠀"],["⠀","⠀","⠀","⠀"]],
59 | '+' => [["⢀","⣰","⣆","⡀"],["⠀","⠘","⠃","⠀"]],
60 | 'f' => [["⢀","⣿","⣙","⠀"],["⠠","⠿","⠄","⠀"]],
61 | '|' => [["⠀","⢸","⡇","⠀"],["⠀","⠸","⠇","⠀"]],
62 | '2' => [["⢀","⣋","⣹","⡇"],["⠸","⠤","⠤","⠆"]],
63 | '&' => [["⢿","⡹","⢀","⠀"],["⠿","⠬","⠯","⠄"]],
64 | 'h' => [["⢹","⡧","⢤","⠀"],["⠼","⠧","⠸","⠄"]],
65 | '7' => [["⠘","⢉","⣹","⡇"],["⠀","⠀","⠸","⠇"]],
66 | "£" => [["⣸","⣏","⡙","⠀"],["⠼","⠧","⠤","⠆"]],
67 | '{' => [["⢀","⣸","⠏","⠁"],["⠀","⠸","⠧","⠄"]],
68 | '@' => [["⢸","⡏","⡭","⡇"],["⠸","⠧","⠭","⠁"]],
69 | 'Q' => [["⣿","⠉","⠉","⡇"],["⠿","⠤","⢧","⠇"]],
70 | 'E' => [["⢹","⣏","⣉","⠃"],["⠼","⠧","⠤","⠆"]],
71 | 'G' => [["⣿","⠉","⠚","⠀"],["⠿","⠤","⠽","⠁"]],
72 | "©" => [["⡔","⣭","⢭","⢢"],["⠣","⣛","⣒","⠜"]],
73 | '9' => [["⢸","⣉","⢽","⡇"],["⠀","⠤","⠞","⠁"]],
74 | 'w' => [["⢤","⠄","⢤","⠄"],["⠸","⠞","⠾","⠀"]],
75 | 'x' => [["⢤","⡄","⢠","⠄"],["⠴","⠏","⠱","⠄"]],
76 | '>' => [["⠈","⠳","⣄","⠀"],["⠠","⠞","⠁","⠀"]],
77 | 'm' => [["⢤","⢤","⢤","⡄"],["⠼","⠸","⠸","⠧"]],
78 | 'r' => [["⠠","⣄","⠤","⡄"],["⠠","⠿","⠄","⠀"]],
79 | '*' => [["⢀","⣰","⣀","⠀"],["⠀","⠋","⠃","⠀"]],
80 | 'O' => [["⢸","⠉","⢹","⡇"],["⠸","⠤","⠼","⠇"]],
81 | '0' => [["⢸","⡏","⠉","⡇"],["⠸","⠧","⠤","⠇"]],
82 | '=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
83 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠆","⠀"]],
84 | 'I' => [["⠈","⢹","⡏","⠁"],["⠠","⠼","⠧","⠄"]],
85 | 'z' => [["⢠","⠤","⣤","⠄"],["⠠","⠾","⠥","⠆"]],
86 | 'j' => [["⠀","⠠","⣭","⠀"],["⠀","⣀","⣿","⠀"]],
87 | 'A' => [["⢸","⣉","⣹","⡇"],["⠼","⠄","⠼","⠧"]],
88 | 'C' => [["⢸","⡏","⠑","⠃"],["⠸","⠧","⠤","⠆"]],
89 | 'k' => [["⢹","⡇","⡠","⠄"],["⠼","⠏","⠢","⠄"]],
90 | 'a' => [["⠀","⠤","⣤","⠀"],["⠸","⠭","⠿","⠄"]],
91 | 'Z' => [["⠘","⢉","⡽","⠃"],["⠰","⠿","⠤","⠆"]],
92 | 'X' => [["⠹","⣇","⡸","⠁"],["⠼","⠇","⠸","⠄"]],
93 | 'P' => [["⢹","⡏","⣉","⡇"],["⠼","⠧","⠀","⠀"]],
94 | 'o' => [["⢠","⠤","⢤","⡄"],["⠸","⠤","⠼","⠇"]],
95 | '%' => [["⠯","⢟","⠔","⠁"],["⠔","⠱","⠽","⠇"]],
96 | '$' => [["⠀","⣶","⣚","⠂"],["⠐","⠖","⠛","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/ZX Times.grf:
--------------------------------------------------------------------------------
1 | {'3' => [["⠐","⢋","⣹","⠆"],["⠐","⠦","⠼","⠃"]],
2 | 'o' => [["⢀","⡤","⢤","⡀"],["⠘","⠧","⠼","⠃"]],
3 | 'b' => [["⢹","⣇","⢤","⡀"],["⠸","⠧","⠼","⠃"]],
4 | '#' => [["⠠","⡴","⡴","⠄"],["⠲","⠳","⠓","⠀"]],
5 | '\'' => [["⠀","⠸","⠃","⠀"],["⠀","⠀","⠀","⠀"]],
6 | 'r' => [["⢤","⣄","⢤","⡀"],["⠼","⠧","⠀","⠀"]],
7 | 'M' => [["⢹","⢿","⡸","⡏"],["⠼","⠜","⠣","⠧"]],
8 | '{' => [["⢀","⣰","⠏","⠀"],["⠀","⠸","⣇","⠀"]],
9 | 'L' => [["⢹","⡏","⠀","⠀"],["⠼","⠧","⠤","⠂"]],
10 | ':' => [["⠀","⢠","⡄","⠀"],["⠀","⠰","⠆","⠀"]],
11 | '?' => [["⠐","⠋","⣹","⠆"],["⠀","⠬","⠀","⠀"]],
12 | '|' => [["⠀","⢸","⡇","⠀"],["⠀","⢸","⡇","⠀"]],
13 | '%' => [["⠺","⢽","⡢","⠃"],["⠰","⠑","⠯","⠗"]],
14 | '5' => [["⠰","⠯","⣉","⠁"],["⠐","⠤","⠼","⠃"]],
15 | 'q' => [["⣠","⢄","⣤","⠄"],["⠙","⢒","⣿","⡀"]],
16 | '1' => [["⠀","⢺","⡇","⠀"],["⠀","⠼","⠧","⠀"]],
17 | 'V' => [["⠹","⣇","⢈","⠏"],["⠀","⠹","⠎","⠀"]],
18 | "©" => [["⡔","⣩","⢭","⢢"],["⠣","⣙","⣒","⠜"]],
19 | '@' => [["⣴","⡩","⢵","⡄"],["⠻","⣑","⣚","⠃"]],
20 | 'P' => [["⢹","⡏","⢹","⠆"],["⠼","⠯","⠁","⠀"]],
21 | '/' => [["⠀","⢀","⡾","⠁"],["⢀","⡾","⠁","⠀"]],
22 | '$' => [["⠰","⣯","⣏","⠃"],["⠰","⢼","⠽","⠃"]],
23 | '"' => [["⠸","⠃","⠟","⠀"],["⠀","⠀","⠀","⠀"]],
24 | '~' => [["⠴","⠲","⠴","⠂"],["⠀","⠀","⠀","⠀"]],
25 | 'J' => [["⠀","⠈","⣿","⠁"],["⠘","⠧","⠋","⠀"]],
26 | '4' => [["⢀","⠔","⣿","⠀"],["⠈","⠉","⠿","⠁"]],
27 | '-' => [["⢀","⣀","⣀","⠀"],["⠀","⠀","⠀","⠀"]],
28 | 'm' => [["⢤","⣤","⣠","⡀"],["⠼","⠇","⠇","⠧"]],
29 | 'y' => [["⢤","⡄","⠠","⡤"],["⢀","⣹","⠎","⠀"]],
30 | 'K' => [["⢹","⣇","⠝","⠁"],["⠼","⠏","⠷","⠄"]],
31 | 'E' => [["⢹","⣏","⡍","⠃"],["⠼","⠧","⠥","⠂"]],
32 | 'C' => [["⣴","⠋","⠑","⠃"],["⠙","⠦","⠤","⠂"]],
33 | ']' => [["⠀","⠉","⣿","⠀"],["⠀","⣀","⣿","⠀"]],
34 | 'X' => [["⠙","⣧","⡜","⠁"],["⠴","⠉","⠷","⠄"]],
35 | '}' => [["⠀","⠹","⣆","⡀"],["⠀","⣸","⠇","⠀"]],
36 | 'G' => [["⣴","⠋","⣚","⡀"],["⠙","⠦","⠜","⠀"]],
37 | 'u' => [["⢤","⡄","⢤","⡄"],["⠘","⠧","⠺","⠧"]],
38 | '(' => [["⠀","⣴","⠁","⠀"],["⠀","⠻","⡀","⠀"]],
39 | 'Z' => [["⠘","⢉","⡽","⠃"],["⠰","⠯","⠤","⠆"]],
40 | 'A' => [["⠀","⡜","⣧","⠀"],["⠼","⠍","⠽","⠧"]],
41 | 'l' => [["⠀","⢹","⡇","⠀"],["⠀","⠼","⠧","⠀"]],
42 | '=' => [["⠠","⠤","⠤","⠀"],["⠈","⠉","⠉","⠀"]],
43 | ';' => [["⠀","⢠","⡄","⠀"],["⠀","⢰","⠆","⠀"]],
44 | 'f' => [["⢀","⣾","⡙","⠂"],["⠠","⠿","⠄","⠀"]],
45 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠆","⠀"]],
46 | 'T' => [["⠘","⢹","⡏","⠃"],["⠀","⠼","⠧","⠀"]],
47 | 'W' => [["⢹","⣏","⣎","⡏"],["⠸","⠟","⠙","⠇"]],
48 | 'd' => [["⣠","⢌","⣿","⠀"],["⠻","⠤","⠿","⠄"]],
49 | 'x' => [["⠠","⣤","⡠","⠄"],["⠠","⠎","⠷","⠄"]],
50 | 'S' => [["⠰","⣯","⣑","⠃"],["⠰","⠢","⠽","⠃"]],
51 | ')' => [["⠀","⢱","⡄","⠀"],["⠀","⡸","⠃","⠀"]],
52 | 'Y' => [["⠙","⣯","⢨","⠋"],["⠀","⠼","⠧","⠀"]],
53 | '\\' => [["⠈","⢷","⡀","⠀"],["⠀","⠈","⢷","⡀"]],
54 | 'Q' => [["⣴","⠋","⢳","⡄"],["⠙","⠦","⣞","⠁"]],
55 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⢰","⠆","⠀"]],
56 | '7' => [["⠘","⠉","⣹","⠇"],["⠀","⠰","⠏","⠀"]],
57 | 'w' => [["⢤","⡤","⠠","⡤"],["⠈","⠷","⠱","⠁"]],
58 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
59 | 'N' => [["⢹","⣦","⣹","⠁"],["⠼","⠌","⠻","⠀"]],
60 | '+' => [["⢀","⣰","⣆","⡀"],["⠀","⠘","⠃","⠀"]],
61 | '8' => [["⠰","⣯","⣉","⠆"],["⠘","⠤","⠽","⠃"]],
62 | 't' => [["⠠","⣾","⠤","⠀"],["⠀","⠻","⠔","⠀"]],
63 | 'B' => [["⢹","⣏","⣹","⠆"],["⠼","⠧","⠼","⠃"]],
64 | '9' => [["⠰","⣏","⣹","⡆"],["⠀","⠤","⠞","⠁"]],
65 | '>' => [["⠐","⠦","⣄","⡀"],["⠐","⠋","⠁","⠀"]],
66 | 'h' => [["⢹","⣇","⢤","⡀"],["⠼","⠇","⠼","⠇"]],
67 | 'k' => [["⢹","⡇","⡤","⠀"],["⠼","⠏","⠷","⠄"]],
68 | '0' => [["⢠","⡎","⢱","⡄"],["⠈","⠣","⠜","⠁"]],
69 | "£" => [["⢀","⣾","⡙","⠂"],["⠠","⠿","⠤","⠆"]],
70 | '2' => [["⠐","⠋","⣹","⠆"],["⠠","⠾","⠥","⠆"]],
71 | 'U' => [["⢹","⡇","⠈","⡏"],["⠘","⠧","⠤","⠃"]],
72 | 'H' => [["⢹","⣏","⣸","⡏"],["⠼","⠇","⠼","⠧"]],
73 | 'g' => [["⢀","⡤","⢤","⡠"],["⠐","⠯","⢭","⡀"]],
74 | '&' => [["⢰","⣏","⢆","⣀"],["⠻","⠼","⠳","⠅"]],
75 | '6' => [["⢠","⣞","⣉","⠀"],["⠘","⠧","⠼","⠃"]],
76 | 'info' => ' ZX Times font by DamienG https://damieng.com','v' => [["⢤","⡄","⢤","⠄"],["⠀","⠻","⠃","⠀"]],
77 | 'D' => [["⢹","⡏","⢳","⡄"],["⠼","⠧","⠞","⠁"]],
78 | '<' => [["⢀","⣠","⠴","⠂"],["⠀","⠈","⠙","⠂"]],
79 | 'c' => [["⢀","⡤","⢤","⡀"],["⠘","⠧","⠤","⠂"]],
80 | 'a' => [["⢀","⠤","⢤","⡀"],["⠐","⠯","⠽","⠇"]],
81 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
82 | 's' => [["⢀","⣤","⠤","⠄"],["⠠","⠭","⠿","⠂"]],
83 | 'I' => [["⠀","⢹","⡏","⠀"],["⠀","⠼","⠧","⠀"]],
84 | 'i' => [["⠀","⢬","⡅","⠀"],["⠀","⠼","⠧","⠀"]],
85 | '!' => [["⠀","⢿","⠇","⠀"],["⠀","⠬","⠄","⠀"]],
86 | 'e' => [["⢀","⡤","⢤","⡀"],["⠘","⠯","⠭","⠅"]],
87 | '^' => [["⢠","⠞","⢦","⠀"],["⠀","⠀","⠀","⠀"]],
88 | '[' => [["⠀","⣿","⠉","⠀"],["⠀","⣿","⣀","⠀"]],
89 | '*' => [["⠠","⣰","⡠","⠀"],["⠈","⠘","⠈","⠀"]],
90 | 'p' => [["⢤","⣄","⢤","⡀"],["⣸","⣗","⠚","⠁"]],
91 | 'O' => [["⣴","⠋","⢳","⡄"],["⠙","⠦","⠞","⠁"]],
92 | 'R' => [["⢹","⣏","⣹","⠆"],["⠼","⠧","⠹","⠦"]],
93 | 'F' => [["⢹","⣏","⡍","⠃"],["⠼","⠧","⠁","⠀"]],
94 | 'j' => [["⠀","⠠","⣭","⠀"],["⠀","⣀","⡿","⠀"]],
95 | 'z' => [["⢠","⠤","⣤","⠄"],["⠠","⠾","⠥","⠆"]],
96 | 'n' => [["⢤","⣄","⢤","⡀"],["⠼","⠧","⠸","⠧"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/ZX Venice.grf:
--------------------------------------------------------------------------------
1 | {'g' => [["⣠","⠤","⢤","⡄"],["⠙","⣒","⡹","⠃"]],
2 | 'q' => [["⣠","⠤","⢤","⡄"],["⠻","⠔","⢹","⡧"]],
3 | 'L' => [["⢰","⡏","⠁","⠀"],["⠼","⠧","⠤","⠊"]],
4 | 'S' => [["⠐","⢯","⡉","⠕"],["⠪","⠤","⠽","⠂"]],
5 | "©" => [["⡔","⣩","⢭","⢢"],["⠣","⣙","⣒","⠜"]],
6 | '>' => [["⠀","⠲","⣄","⠀"],["⠀","⠚","⠁","⠀"]],
7 | '{' => [["⢀","⣸","⠏","⠁"],["⠀","⢸","⣇","⡀"]],
8 | 'Y' => [["⢺","⡇","⢸","⡇"],["⠈","⣓","⡹","⠃"]],
9 | '|' => [["⠀","⢸","⡇","⠀"],["⠀","⢸","⡇","⠀"]],
10 | 'l' => [["⠀","⣾","⠁","⠀"],["⠀","⠿","⠔","⠁"]],
11 | '*' => [["⢀","⣢","⣔","⡀"],["⠀","⠊","⠑","⠀"]],
12 | 'b' => [["⢰","⣏","⠤","⣄"],["⠸","⠧","⠴","⠋"]],
13 | ']' => [["⠀","⠉","⣿","⠀"],["⠀","⣀","⣿","⠀"]],
14 | 'P' => [["⠎","⣿","⣉","⡷"],["⠤","⠟","⠀","⠀"]],
15 | '/' => [["⠀","⢀","⡴","⠃"],["⠰","⠋","⠀","⠀"]],
16 | '#' => [["⠠","⡼","⢤","⠧"],["⢲","⠓","⡞","⠂"]],
17 | '=' => [["⠠","⠤","⠤","⠄"],["⠈","⠉","⠉","⠁"]],
18 | 'h' => [["⢰","⡏","⣠","⡄"],["⠸","⠏","⠸","⠗"]],
19 | '!' => [["⠀","⢸","⡇","⠀"],["⠀","⠰","⠆","⠀"]],
20 | '[' => [["⠀","⣿","⠉","⠀"],["⠀","⣿","⣀","⠀"]],
21 | 'info' => ' ZX Venice font by DamienG https://damieng.com','6' => [["⢰","⣏","⢭","⡂"],["⠘","⠧","⠼","⠃"]],
22 | 'z' => [["⢀","⠤","⣤","⠄"],["⠠","⠾","⠥","⠔"]],
23 | 'V' => [["⢺","⡇","⢺","⡆"],["⠘","⠧","⠊","⠀"]],
24 | '.' => [["⠀","⠀","⠀","⠀"],["⠀","⠰","⠆","⠀"]],
25 | '%' => [["⢎","⡱","⡩","⠃"],["⠠","⠊","⢎","⡱"]],
26 | 'C' => [["⢰","⡏","⠩","⠂"],["⠘","⠧","⠔","⠁"]],
27 | '1' => [["⠀","⢺","⡇","⠀"],["⠀","⠼","⠧","⠀"]],
28 | '\'' => [["⠀","⠘","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
29 | 'N' => [["⢹","⢦","⡀","⡏"],["⠜","⠀","⠙","⠇"]],
30 | ' ' => [["⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀"]],
31 | 'B' => [["⢺","⣏","⣹","⠆"],["⠼","⠧","⠤","⠟"]],
32 | 'a' => [["⣠","⠤","⣤","⠀"],["⠻","⠔","⠿","⠊"]],
33 | 'v' => [["⣠","⡀","⣠","⡄"],["⠸","⠧","⠊","⠀"]],
34 | 'r' => [["⢀","⣤","⡠","⠄"],["⠀","⠿","⠂","⠀"]],
35 | '+' => [["⢀","⣰","⣀","⠀"],["⠀","⠘","⠀","⠀"]],
36 | '9' => [["⢰","⡏","⣹","⡆"],["⠐","⠭","⠼","⠃"]],
37 | 'n' => [["⣠","⡄","⣠","⡄"],["⠸","⠏","⠸","⠗"]],
38 | 't' => [["⠠","⣾","⠄","⠀"],["⠀","⠿","⠔","⠁"]],
39 | '2' => [["⠠","⠊","⣹","⠆"],["⠠","⠾","⠥","⠔"]],
40 | 'i' => [["⢀","⣭","⠀","⠀"],["⠀","⠿","⠔","⠁"]],
41 | '^' => [["⠀","⡴","⡷","⡄"],["⠈","⠀","⠇","⠈"]],
42 | 'T' => [["⠎","⢹","⡏","⠁"],["⠠","⠼","⠃","⠀"]],
43 | 'p' => [["⣠","⣄","⠤","⣄"],["⢸","⡗","⠤","⠟"]],
44 | '(' => [["⠀","⣴","⠁","⠀"],["⠀","⠻","⡀","⠀"]],
45 | 'X' => [["⠞","⢦","⡴","⠋"],["⠴","⠋","⠙","⠞"]],
46 | ':' => [["⠀","⠰","⠆","⠀"],["⠀","⠰","⠆","⠀"]],
47 | '\\' => [["⠘","⢦","⡀","⠀"],["⠀","⠀","⠙","⠆"]],
48 | '-' => [["⢀","⣀","⣀","⡀"],["⠀","⠀","⠀","⠀"]],
49 | 'F' => [["⠎","⣿","⣉","⠃"],["⠤","⠟","⠀","⠀"]],
50 | '0' => [["⢰","⡏","⢹","⡆"],["⠘","⠧","⠼","⠃"]],
51 | 'k' => [["⢰","⣏","⠤","⡀"],["⠸","⠏","⠻","⠔"]],
52 | 'j' => [["⠀","⢀","⣭","⠀"],["⠀","⣁","⠟","⠀"]],
53 | '5' => [["⠸","⠯","⢭","⡑"],["⠐","⠤","⠞","⠁"]],
54 | 'K' => [["⢹","⣇","⡴","⠃"],["⠸","⠏","⠳","⠔"]],
55 | 's' => [["⢀","⡤","⠤","⡀"],["⠠","⠭","⠽","⠂"]],
56 | '~' => [["⠐","⠋","⠚","⠁"],["⠀","⠀","⠀","⠀"]],
57 | 'E' => [["⠎","⣿","⣉","⠃"],["⠤","⠿","⠤","⠔"]],
58 | '$' => [["⠠","⣖","⡗","⠢"],["⠐","⠤","⡯","⠗"]],
59 | '@' => [["⡴","⣫","⢽","⡆"],["⠳","⣝","⣊","⠄"]],
60 | "£" => [["⣠","⣞","⡉","⠆"],["⠼","⠧","⠤","⠂"]],
61 | 'U' => [["⢺","⡇","⢸","⡇"],["⠘","⠧","⠺","⠗"]],
62 | 'o' => [["⢀","⡤","⢤","⡀"],["⠘","⠧","⠞","⠁"]],
63 | '&' => [["⠰","⣩","⠗","⣀"],["⠺","⠥","⠝","⠬"]],
64 | 'Z' => [["⠎","⢉","⡽","⠃"],["⠴","⠯","⠤","⠊"]],
65 | 'y' => [["⣠","⡄","⢠","⡄"],["⠈","⣓","⡹","⠃"]],
66 | 'R' => [["⠎","⣿","⣉","⡷"],["⠤","⠏","⠳","⠔"]],
67 | 'M' => [["⢹","⢦","⢺","⡏"],["⠜","⠀","⠸","⠗"]],
68 | '_' => [["⠀","⠀","⠀","⠀"],["⣀","⣀","⣀","⣀"]],
69 | '<' => [["⠀","⣠","⠖","⠀"],["⠀","⠈","⠓","⠀"]],
70 | 'W' => [["⢺","⡇","⠐","⣷"],["⠸","⠗","⠧","⠋"]],
71 | 'D' => [["⠎","⣿","⠙","⣦"],["⠤","⠿","⠤","⠋"]],
72 | ')' => [["⠀","⢱","⡄","⠀"],["⠀","⡸","⠃","⠀"]],
73 | '8' => [["⠰","⣏","⣹","⠆"],["⠘","⠧","⠼","⠃"]],
74 | '4' => [["⢀","⠔","⣿","⢀"],["⠈","⠩","⠿","⠅"]],
75 | 'w' => [["⣠","⢠","⢀","⡄"],["⠿","⠼","⠜","⠁"]],
76 | '3' => [["⠀","⡊","⢽","⡋"],["⠘","⠤","⠤","⠟"]],
77 | 'O' => [["⣴","⠉","⢳","⡄"],["⠙","⠤","⠞","⠁"]],
78 | 'e' => [["⢀","⡤","⢤","⠀"],["⠘","⠷","⠥","⠊"]],
79 | 'Q' => [["⣴","⠉","⢳","⡄"],["⠙","⠬","⠾","⡁"]],
80 | 'x' => [["⡠","⣄","⣠","⠄"],["⠠","⠞","⠳","⠔"]],
81 | ',' => [["⠀","⠀","⠀","⠀"],["⠀","⢘","⠇","⠀"]],
82 | 'I' => [["⠰","⢹","⡇","⠀"],["⠀","⠸","⠧","⠊"]],
83 | '?' => [["⠐","⠉","⣹","⠆"],["⠀","⠀","⠅","⠀"]],
84 | 'f' => [["⠀","⣰","⣏","⠁"],["⢀","⡸","⠃","⠀"]],
85 | '"' => [["⠀","⠃","⠘","⠀"],["⠀","⠀","⠀","⠀"]],
86 | ';' => [["⠀","⠰","⠆","⠀"],["⠀","⢘","⠇","⠀"]],
87 | 'H' => [["⣺","⣇","⣰","⡏"],["⠼","⠃","⠸","⠗"]],
88 | '7' => [["⠐","⠉","⣩","⠟"],["⠀","⠰","⠏","⠀"]],
89 | 'd' => [["⣠","⠤","⣾","⠁"],["⠻","⠔","⠿","⠊"]],
90 | 'u' => [["⣠","⡄","⢠","⡄"],["⠘","⠧","⠺","⠗"]],
91 | 'm' => [["⣠","⣠","⣄","⣤"],["⠿","⠸","⠇","⠿"]],
92 | 'A' => [["⠐","⣩","⢿","⡆"],["⠽","⠋","⠙","⠧"]],
93 | 'G' => [["⣾","⢉","⣋","⠀"],["⠻","⠤","⠻","⠊"]],
94 | 'J' => [["⠀","⠎","⢹","⡇"],["⠀","⣀","⠜","⠁"]],
95 | 'c' => [["⢀","⡤","⠤","⡄"],["⠘","⠧","⠤","⠂"]],
96 | '}' => [["⠈","⠹","⣇","⡀"],["⢀","⣸","⡇","⠀"]]}
97 |
--------------------------------------------------------------------------------
/examples/fonts/asm2grf.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use lib "../../lib/";
4 | use open ":std", ":encoding(UTF-8)";
5 | use Term::Graille qw/colour paint printAt clearScreen border block2braille pixelAt/;
6 | use Term::Graille::Font qw/convertDG saveGrf loadGrf/;
7 | use Time::HiRes qw/sleep/;
8 | use Data::Dumper;
9 | use utf8;
10 |
11 | #find all fonts
12 | opendir my $fontDir,"." or die "Unable to open directory $!;";
13 | my @files=readdir $fontDir;
14 | @files=map{$_=~s/.z80.asm$//;$_} grep /z80.asm$/,@files;
15 |
16 | unless (scalar @files){
17 | print "No unconverted font files found";
18 | exit ;
19 | }
20 | foreach my $fontName(@files){
21 | print "Converting font $fontName\n";
22 | my $grf=convertDG("$fontName.z80.asm");
23 | next unless $grf;
24 | saveGrf($grf,"$fontName.grf");
25 | rename "$fontName.z80.asm","$fontName.z80.asm.done"or
26 | print "Unable to rename fontfile $fontName.z80.asm $!;\n" ;
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/examples/fonts/font2grf.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | #use lib "../../lib/";
4 | use open ":std", ":encoding(UTF-8)";
5 | use Term::Graille qw/colour paint printAt clearScreen border block2braille pixelAt loadGrf/;
6 | use Time::HiRes qw/sleep/;
7 | use Data::Dumper;
8 | use utf8;
9 |
10 | #find all fonts
11 | opendir my $fontDir,"." or die "Unable to open directory $!;";
12 | my @files=readdir $fontDir;
13 | @files=map{$_=~s/.z80.asm$//;$_} grep /z80.asm$/,@files;
14 | unless (scalar @files){
15 | print "No unconverted font files found";
16 | exit ;
17 | }
18 | foreach my $fontName(@files){
19 | print "Converting font $fontName\n";
20 | open my $zxFont,"<:utf8","$fontName.z80.asm" or
21 | print "Unable to open fontfile $fontName.z80.asm $!;\n" && next;
22 | my $font="";
23 | $font.=$_ while(<$zxFont>);
24 | close $zxFont;
25 |
26 | $font=~s/^[\s\t]?;([^\n]+)/{/g;
27 | my $info=$1;
28 | $font=~s/defb &/[[0x/g;
29 | $font=~s/,&/],[0x/g;
30 | $font=~s/ ; /]],# /g;
31 | $font=~s/\s([^#\s]*)#\s(.)/ '$2'=>$1/g;
32 | $font=~s/\'\'\'/\"\'\"/g;
33 | $font=~s/\'\\\'/\'\\\\\'/g;
34 | $font.="\n}\n";
35 | # print $font;
36 | my $binFont=eval($font);
37 | my $grlFont={};
38 | for (keys %$binFont){
39 | use utf8;
40 | $grlFont->{$_}=block2braille($binFont->{$_}) ;
41 | }
42 | $grlFont->{info}=$info||"";
43 |
44 |
45 | my $output=Dumper([$grlFont])=~ s/\\x\{([0-9a-f]{2,})\}/chr hex $1/ger;
46 | $output=~s/^\$VAR1 = \[\n\s+| \];\n?$//g;
47 | $output=~s/\[\n\s+\[/\[\[/g;
48 | $output=~s/\n\s+([^\s])/$1/g;
49 | $output=~s/\]\],/\]\],\n/g;
50 | if (length $output <100){
51 | print "Conversion failed\n";
52 | next;
53 | };
54 |
55 | open my $dat,">:utf8","$fontName.grf" or
56 | print "Unable to save fontfile $fontName.grf $!;\n" && next;
57 | print $dat $output;
58 | close $dat;
59 |
60 | rename "$fontName.z80.asm","$fontName.z80.asm.done"or
61 | print "Unable to rename fontfile $fontName.z80.asm $!;\n" ;
62 |
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/examples/graillepiano.pl:
--------------------------------------------------------------------------------
1 | use strict; use warnings;
2 | use lib "../lib";
3 |
4 | use Term::Graille qw/colour paint printAt cursorAt clearScreen border blockBlit block2braille pixelAt/;
5 | use Term::Graille::Interact;
6 | use Term::Graille::Menu;
7 | use Term::Graille::Audio;
8 | use Term::Graille::Font qw/loadGrf fontWrite/;
9 |
10 | my $beep=Term::Graille::Audio->new(); # TERM::Graille's Audio module
11 | my $io=Term::Graille::Interact->new(); # capture keyboard actions
12 | our $VERSION=0.01;
13 |
14 | my $canvas = Term::Graille->new(
15 | width => 140,
16 | height => 60,
17 | top=>4,
18 | left=>4,
19 | borderStyle => "double",
20 | borderColour => "blue",
21 | title => " A Graille Piano ",
22 | titleColour => "red",
23 | );
24 |
25 | splashScreen();
26 | $canvas->clear();
27 | my ($keyboard,$key2note)=$beep->makeKeyboard;
28 | $beep->setupKeyboard($canvas);
29 | $beep->drawKeyboard();
30 | $canvas->draw();
31 | my $lastKey;
32 |
33 | $io->addAction("MAIN","others",{proc=>sub{
34 | my ($pressed,$GV)=@_;
35 | if (exists $key2note->{$pressed}){
36 | $beep->drawKey($lastKey);
37 | $beep->playSound(undef, $key2note->{$pressed});
38 | $beep->drawKey($pressed,"red on_green");
39 | $lastKey=$pressed;
40 | $canvas->draw();
41 | };
42 | }
43 | }
44 | );
45 |
46 | $io->addAction("MAIN","esc",{proc=>sub{
47 | exit 1;
48 | }
49 | }
50 | );
51 |
52 | $io->run();
53 |
54 | sub splashScreen{
55 | $canvas->clear();
56 | my $grf=loadGrf("./fonts/ZX Times.grf");
57 | fontWrite($canvas,$grf,3,13,"Monophonic Piano");
58 | fontWrite($canvas,$grf,3,10,"A simple demo of");
59 | fontWrite($canvas,$grf,2,7,"Interactive Audio");
60 | $canvas->textAt(30,20,"Press Esc then m to get menu; Enter to start","green");
61 | $canvas->draw();
62 | }
63 |
--------------------------------------------------------------------------------
/examples/image2grl.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use Term::Graille qw/colour paint printAt clearScreen border/;
4 | use Image::Magick;
5 |
6 | # convert2grl--converts an image to .grl format.
7 |
8 | my %params=%ARGV;
9 |
10 | my $canvas = Term::Graille->new(
11 | width => $params{width}||72,
12 | height => $params{height}||60,
13 | top=>2,
14 | left=>10,
15 | borderStyle => "double",
16 | );
17 | clearScreen();
18 | my $inFile=$params{-i}||"perl2.jpg";
19 | my $outFile=$params{-o}||($inFile=~s/\..+$//r).".grl";
20 | loadImage($inFile);
21 | $canvas->exportCanvas($outFile);
22 |
23 | sub loadImage{
24 | my $imgfile=shift;
25 | my $image = Image::Magick->new();
26 | my $wh = $image->Read($imgfile);
27 | $image->Resize(geometry => "$canvas->{width}x$canvas->{height}", filter=>"Cubic");
28 | warn $wh if $wh;
29 | $image->set('monochrome'=>'True','dither'=>'True','dither-method'=>"Floyd-Steinberg");
30 | for (my $x =0;$x<$canvas->{width};$x++){
31 | for (my $y=0;$y<$canvas->{height};$y++){
32 | $canvas->set($x,$y) if $image->GetPixel("x"=>$x,"y",$canvas->{height}-$y);
33 | }
34 | }
35 | }
36 |
37 | $canvas->draw();
38 | print "\n";
39 | print " "x8,"Viewing $inFile, saved as $outFile\n";
40 | printAt(18,0," ")
41 | ;
42 |
--------------------------------------------------------------------------------
/examples/invaders.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use utf8;
4 | use lib "../lib";
5 | use open ":std", ":encoding(UTF-8)";
6 | use Term::Graille qw/colour paint printAt cursorAt clearScreen border blockBlit block2braille pixelAt/;
7 | use Term::Graille::Interact ;
8 | use Term::Graille::Audio;
9 | use Term::Graille::Font qw/loadGrf fontWrite/;
10 |
11 | my $beep=Term::Graille::Audio->new(); # TERM::Graille's Audio module
12 | my $grf=loadGrf("./fonts/ZX Times.grf");
13 |
14 | my $spriteBank={};
15 | my $dir="./sprites/";
16 | my $scroll="left";
17 |
18 | loadSprites(qw/alien1 alien2 alien3 defender spaceship/);
19 | $spriteBank->{patriot}=[[colour("blue")."↑".colour("reset")]];
20 | $spriteBank->{bomb}=[[colour("red")."↧".colour("reset")]];
21 | $spriteBank->{shield}=[[colour("yellow")."⢕".colour("reset")]];
22 | my (@aliens,@missiles,@shields,@spaceships);
23 | my $defender={sprite=>"defender",x=>40,y=>1,};
24 | my ($maxAlienX,$minAlienX,$alienDx,$alienDy,$alienMoveSkipStart,
25 | $alienSkipAccelerate,$aliensLanded,$stopUpdates,$alienMoveSkip,
26 | $level, $score, $lives, $highscore);
27 |
28 | my $canvas = Term::Graille->new(
29 | width => 150,
30 | height => 60,
31 | top=>4,
32 | left=>4,
33 | borderStyle => "double",
34 | title=>"Space Invaders",
35 | );
36 |
37 | initialise();
38 |
39 | my $io=Term::Graille::Interact->new();
40 | $io->{debugCursor}=[22,45];
41 |
42 | $io->addAction(undef,"[D",{note=>"Move Left ",proc=>sub{
43 | $defender->{x}=$defender->{x}>=1?$defender->{x}-1:1 }} );
44 | $io->addAction(undef,"[C",{note=>"Move Right ",proc=>sub{
45 | $defender->{x}=$defender->{x}<=65?$defender->{x}+1:65 }} );
46 | $io->addAction(undef,"[A",{note=>"Fire ", proc=>sub{
47 | push @missiles,{sprite=>"patriot",x=>$defender->{x}+4,y=>1,dy=>1};;
48 | $beep->playSound(undef,"A#1");}} );
49 | $io->addAction(undef,"p",{note=>"PaUSE ", proc=>sub{
50 | $stopUpdates=$stopUpdates?0:1;}} );
51 |
52 | $io->updateAction(\&update);
53 | $io->run();
54 |
55 | sub update {
56 | victory() unless scalar @aliens;
57 | defeat("Aliens Landed") if $aliensLanded;
58 | return if $stopUpdates;
59 | updateScreen();
60 | updateSprites();
61 | }
62 |
63 | #draw all sprites and redraw screen
64 | sub updateScreen{
65 | $canvas->clear();
66 | @aliens=grep($_->{sprite},@aliens);
67 | @missiles=grep($_->{sprite},@missiles);
68 | @shields=grep($_->{sprite},@shields);
69 | @spaceships=grep($_->{sprite},@spaceships);
70 | foreach (@aliens,@missiles,$defender,@shields,@spaceships){
71 | next unless defined $_->{sprite};
72 | my ($spr,$x,$y)=@$_{qw/sprite x y/};
73 | $canvas->blockBlit($spriteBank->{$spr},$x,$y);
74 | if ($spr=~/^a/){ #collect data for aliens closest to edges
75 | $maxAlienX=$x if $x>$maxAlienX;
76 | $minAlienX=$x if $x<$minAlienX;
77 | }
78 | }
79 | push @missiles,{sprite=>"bomb",x=>2+rand()*70,y=>16,dy=>-1} if rand()<0.01;
80 | push @spaceships,{sprite=>"spaceship",x=>3,y=>15,dx=>1} if rand()<0.005;
81 | $canvas->draw();
82 | printAt(3,40,"Score: $score Level: $level, Lives ".colour("red")."♥ "x$lives.colour("reset") );
83 | printAt(16,0," ");
84 | }
85 |
86 | sub updateSprites{
87 | $alienMoveSkip--;
88 | unless ($alienMoveSkip>=0){
89 | $alienDy=0;
90 | if ($maxAlienX>=67){$alienDx=-1;$alienDy=-1;$maxAlienX=0};
91 | if ($minAlienX<=1){$alienDx=1;$alienDy=-1;$minAlienX=1000};
92 | foreach (@aliens){
93 | $_->{x}+=$alienDx;
94 | $_->{y}+=$alienDy;
95 | $aliensLanded=1 if $_->{y}<=2
96 | }
97 | $alienMoveSkipStart-=0.1;
98 | $alienMoveSkip=$alienMoveSkipStart;
99 | }
100 | foreach (@spaceships){
101 | $_->{x}+=$_->{dx};
102 | $_ ={} if $_->{x} >=67;
103 | push @missiles,{sprite=>"bomb",x=>$_->{x}+2,y=>16,dy=>-1} if ((rand()<0.5) and ($_->{x}==$defender->{x}));
104 | $_ ={} if $_->{x} >=67;
105 | }
106 | foreach my $missile (@missiles){
107 | next unless $missile->{y};
108 | $missile->{y}+=$missile->{dy};
109 | if ($missile->{y}>=16|| $missile->{y}<=1){
110 | $missile={};
111 | };
112 | next unless defined $missile->{sprite};
113 | foreach my $alien (@aliens,@spaceships){
114 | if ($missile->{sprite}&& $missile->{sprite} eq "patriot"&&(collide($missile,$alien))){
115 | $score+=($alien->{sprite} eq "spaceship")?1000:10;
116 | $missile=$alien={};
117 | $beep->playSound(undef,"D#1");
118 | }
119 | }
120 | foreach my $shield (@shields){
121 | if ($missile->{sprite}&&(collide($missile,$shield))){
122 | $missile=$shield={};
123 | $beep->playSound(undef,"c#1");
124 | }
125 | }
126 | if ($missile->{sprite} && $missile->{sprite} eq "bomb"){
127 | defeat("Defender Died") if collide($missile,$defender)
128 | }
129 | }
130 | }
131 |
132 | sub loadSprites{
133 | my @sprites=@_;
134 | foreach my $spr (@sprites){
135 | open my $grf,"<:utf8",$dir.$spr.".spr" or do {
136 | errorMessage( "Unable to load spritefile $spr.spr");
137 | next;
138 | };
139 | my $data="";
140 | $data.=$_ while(<$grf>);
141 | close $grf;
142 | $spriteBank->{$spr}=[@{eval($data)}[0..1]] or return errorMessage("unable to load sprite $spr.spr\n $!");
143 | $_->[0]=colour((qw/red yellow green magenta cyan white blue/)[rand()*7]).$_->[0] foreach (@{$spriteBank->{$spr}})
144 | }
145 | }
146 |
147 | sub collide{
148 | my ($sprA,$sprB) =@_;
149 | return unless $sprA->{sprite} && $sprB->{sprite};
150 | my ($blkA,$blkB)=($spriteBank->{$sprA->{sprite}},$spriteBank->{$sprB->{sprite}});
151 | my ($ax1,$ay1,$bx1,$by1)=($sprA->{x},$sprA->{y},$sprB->{x},$sprB->{y});
152 | my ($ax2,$ay2,$bx2,$by2)=($ax1+@{$blkA->[0]},$ay1+@$blkA-1,$bx1+@{$blkB->[0]},$by1+@$blkB-1);
153 | return (($ax1 <= $bx2) && ($ax2 >= $bx1) && ($ay1 <= $by2) && ($ay2 >= $by1) ) ;
154 | }
155 |
156 | sub errorMessage{die $_[0];}
157 |
158 | sub setupAliens{
159 | # build aliens dataset
160 | @aliens=();
161 | $alienMoveSkip=$alienMoveSkipStart;
162 | $aliensLanded=0;
163 | my $row=15; # start at row 15
164 | for my $alien(keys %$spriteBank){
165 | next unless $alien=~/alien/; # use alien sprites
166 | for (0..5){
167 | push @aliens, {sprite=>$alien,x=>10+10*$_,y=>$row}
168 | }
169 | $row-=2; #next row down
170 | }
171 | }
172 |
173 | sub buildShields{
174 | @shields=();
175 | for my $y (2..3){
176 | for my $x (0..4){
177 | for my $z (0..6){
178 | push @shields, {sprite=>"shield",x=>4+15*$x+$z,y=>$y}
179 | }
180 | }
181 | }
182 | }
183 |
184 | sub initialise{
185 | clearScreen();
186 | ($maxAlienX,$minAlienX,$alienDx,$alienDy,$alienMoveSkipStart,
187 | $alienSkipAccelerate,$aliensLanded,$level, $score, $lives, $highscore)=
188 | (0,200,1,0,8,0.01,0,1,0,3, 0);
189 | $stopUpdates=0;
190 | $alienMoveSkip=$alienMoveSkipStart;
191 | setupAliens();
192 | buildShields();
193 | splash();
194 | sleep 3;
195 | }
196 |
197 | sub splash{
198 | my $mainMessage=shift//"Space Invaders";
199 | my $message=shift//"A Game for The PerlayStation Games Console 1";
200 | my $format=shift//"blue";
201 | $canvas->clear();
202 | fontWrite($canvas,$grf,10,10,$mainMessage);
203 | $canvas->textAt(30,20,$message,$format);
204 | $canvas->textAt(40,12,"Left Right Arrow keys move defender","cyan bold");
205 | $canvas->textAt(40,8,"Up Arrow fires missile, 'p' pauses","cyan bold");
206 | $canvas->draw();
207 |
208 | }
209 |
210 | sub victory{
211 | $level++;$score+=500;
212 | splash("Level clear!!","Lives $lives Score: $score","green");
213 | sleep 3;
214 | setupAliens();
215 | }
216 | sub defeat{
217 | my $fail=shift;
218 | $lives--;
219 | splash($fail,"Lives $lives Score: $score","green");
220 | gameover() unless $lives;
221 | setupAliens();
222 | sleep 4;
223 | }
224 |
225 | sub gameover{
226 | $highscore=$score if $score>$highscore;
227 | splash(" Annihilated!","Score: $score High Score: $highscore ","green");
228 | sleep 4;
229 | initialise();
230 | }
231 |
232 |
233 | sub quit{
234 | splash("Good Bye!!","Score: $score High Score: $highscore ","green");
235 | sleep 4;
236 | exit;
237 | }
238 |
239 |
--------------------------------------------------------------------------------
/examples/lineDemo.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use utf8;
4 | use open ":std", ":encoding(UTF-8)";
5 | use Term::Graille qw/colour paint printAt clearScreen border/;
6 |
7 | my $canvas = Term::Graille->new(
8 | width => 120,
9 | height => 60,
10 | top=>4,
11 | left=>10,
12 | borderStyle => "double",
13 | title=>"Variable Thickness Line Demo",
14 | );
15 | my @colours=qw/red blue green yellow cyan magenta white/;
16 | clearScreen();
17 | $canvas->clear();
18 |
19 | my $squiggles={
20 | sin1=>sub{
21 | my ($arg, $p, $length)=@_;
22 | return abs(4*sin ($p/$arg));
23 | },
24 | sin2=>sub{
25 | my ($arg, $p, $length)=@_;
26 | return abs(4*sin (($p+4)/$arg));
27 | },
28 | zigzag=>sub{
29 | my ($arg, $p, $length)=@_;
30 | return $p % $arg;
31 | },
32 | fixed=>sub{
33 | my ($arg, $p, $length)=@_;
34 | return $arg;
35 | },
36 | linear=>sub{
37 | my ($arg, $p, $length)=@_;
38 | return $arg*$p/$length;
39 | },
40 | };
41 |
42 | #for (2..9){
43 | #$canvas->thick_line(60,30,60+sin($_*45*3.14159267/180)*20,30+cos($_*45*3.14159267/180)*20,3,$colours[$_% 7]);
44 | #}
45 |
46 | my ($x1,$y1,$x2,$y2)=(5,55,115,5);
47 | $canvas->varthick_line($x1,$y1,$x1,$y2,$squiggles->{sin1},3,$squiggles->{sin2},3,"green");
48 | $canvas->varthick_line($x1,$y2,$x2,$y2,$squiggles->{sin1},3,$squiggles->{sin2},3,"green");
49 | $canvas->varthick_line($x2,$y2,$x2,$y1,$squiggles->{sin1},3,$squiggles->{sin2},3,"green");
50 | $canvas->varthick_line($x2,$y1,$x1,$y1,$squiggles->{sin1},3,$squiggles->{sin2},3,"green");
51 |
52 | $canvas->varthick_line(20,12,20,48,$squiggles->{linear},4,$squiggles->{linear},4,"red");
53 |
54 | $canvas->varthick_line(40,12,40,48,$squiggles->{zigzag},4,$squiggles->{fixed},2,"blue");
55 | $canvas->varthick_line(60,12,60,48,$squiggles->{zigzag},4,$squiggles->{zigzag},6,"yellow");
56 | $canvas->varthick_line(80,12,80,48,$squiggles->{sin1},4,$squiggles->{sin1},8,"magenta");
57 | $canvas->varthick_line(100,12,100,48,$squiggles->{sin1},4,$squiggles->{sin1},4,"cyan");
58 |
59 | $canvas->draw();
60 |
--------------------------------------------------------------------------------
/examples/perl2.grl:
--------------------------------------------------------------------------------
1 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
2 | ⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡀⣠⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
3 | ⠀⠀⢀⡴⡤⣲⣾⣿⣗⡀⠀⠀⠀⠀⣠⣾⣿⣿⣽⣿⣟⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
4 | ⠀⠀⠀⠋⢳⣧⣫⣿⣿⣗⠀⠀⣀⣶⣿⣿⣿⣿⣿⡺⢽⣽⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
5 | ⠀⠀⠀⢀⣿⣿⣿⣯⣿⠏⣤⣾⣿⡟⢽⢛⢯⣫⡕⢍⢬⢪⡺⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
6 | ⠀⠀⠀⢰⣿⣶⢟⣿⢟⢰⣿⣿⣯⠃⠄⡢⠹⣓⡭⢯⢧⡝⡷⣛⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
7 | ⠀⠀⠀⠰⣿⣿⣏⡼⡣⢫⣿⣿⣿⠆⡐⡕⣣⠕⡭⡪⡄⣒⣺⣴⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
8 | ⠀⠀⠀⠀⠈⠿⣿⣎⣜⣴⣿⣿⣿⣯⣿⡞⣔⣿⣿⣷⣿⣾⣿⣿⡇⣻⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀
9 | ⠀⠀⠀⠀⠀⠀⠘⠛⠗⢛⣿⣿⣿⢿⣷⣮⣎⣾⣿⣿⣿⢻⣿⣿⠂⣸⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀
10 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠏⢠⣿⣿⡿⠂⣿⣿⠀⠀⢿⣿⡐⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
11 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⣿⡏⠀⣼⢿⠿⠁⠀⣿⣗⠀⠀⠘⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
12 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⣿⠇⠀⠻⣎⠀⠀⠀⠎⠀⠀⠀⠀⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
13 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡟⠀⠀⠀⠀⠣⡐⠊⠀⠀⠀⠀⠀⡕⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
14 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠨⠀⠀⠀⠀⢠⣴⡿⣮⠄⠀⠀⠀⠐⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
15 | ⠀⠀⠀⠀⠀⠀⠀⠰⠖⢕⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠾⠷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
16 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
17 |
--------------------------------------------------------------------------------
/examples/perl2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/perl2.jpg
--------------------------------------------------------------------------------
/examples/pulseaudio.pl:
--------------------------------------------------------------------------------
1 | #!/usr/env perl
2 | ############### PulsAudio Utils #####################
3 | #https://wiki.archlinux.org/title/PulseAudio/Examples#
4 | use strict; use warnings;
5 | use lib "../lib/";
6 |
7 | use Term::Graille qw/colour paint printAt cursorAt clearScreen border blockBlit block2braille pixelAt/;
8 | use Term::Graille::Interact;
9 | use Term::Graille::Menu;
10 | use Term::Graille::Font qw/loadGrf fontWrite/;
11 |
12 | our $VERSION=0.01;
13 |
14 | my $canvas = Term::Graille->new(
15 | width => 140,
16 | height => 60,
17 | top=>4,
18 | left=>4,
19 | borderStyle => "double",
20 | borderColour => "blue",
21 | title => " PulseAudio ",
22 | titleColour => "red",
23 | );
24 |
25 | splashScreen();
26 |
27 | my $paList=paCtl();
28 | my ($listMenu,$itemToObject)=makeListMenu();
29 |
30 | my $io=Term::Graille::Interact->new(); # For interactions menu and keyboard
31 | $io->{debugCursor}=[22,45]; # Put key presses detected ny Interact on the screen
32 |
33 | my $menu=new Term::Graille::Menu(
34 | menu=>[["Global","Reset","Dump","Exit"],
35 | $listMenu,
36 | ["Sound","Record","Playback"],
37 | "About"],
38 | redraw=>\&refreshScreen,
39 | dispatcher=>\&menuActions,
40 | );
41 |
42 | my %actions=(
43 | Reset=>sub{
44 | },
45 | Stop=>sub{
46 | },
47 | About=>sub{
48 | splashScreen($canvas);
49 | }
50 | );
51 |
52 | sub menuActions{
53 | my ($action,$bc)=@_;
54 | return unless $action;
55 | if (exists $actions{$action}){
56 | $actions{$action}->()
57 | }
58 | else{
59 | if ($bc->[0] == 1){ # View Items
60 | my $mGroup=$bc->[1];
61 | my $mIndex=$bc->[2];
62 | #ie "$mGroup $mIndex $itemToObject";
63 | objectDescribe(@{$itemToObject->[$mGroup]->[$mIndex]})
64 | };
65 | }
66 | };
67 |
68 | $io->addObject(object => $menu,trigger=>"m");
69 | $canvas->draw();
70 | $io->run();
71 |
72 | sub splashScreen{
73 | $canvas->clear();
74 | my $grf=loadGrf("./fonts/ZX Times.grf");
75 | fontWrite($canvas,$grf,3,13,"PulseAudio Utils");
76 | fontWrite($canvas,$grf,1,10,"Tool to Play with");
77 | fontWrite($canvas,$grf,13,7,"Linux Audio");
78 | $canvas->textAt(30,20,"An interactive shell for pacat pacmd pactl","green italic");
79 | $canvas->textAt(38,16,"(parec paplay pamon padsp etc)","yellow italic");
80 | $canvas->textAt(40,12,"Version $VERSION (GRAILLE ".$Term::Graille::VERSION.")","yellow italic");
81 | $canvas->textAt(40,8,"(m key brings up the menu)","cyan bold");
82 | $canvas->draw();
83 | }
84 |
85 | sub refreshScreen{
86 | clearScreen() unless (shift);
87 | $canvas->draw();
88 | }
89 |
90 | sub paCtl{
91 | my $paList={};
92 | my $currentType;my $index;my $currentKey;
93 | foreach my $line (`pactl list`){
94 | chomp $line;
95 | if ($line=~/^([A-Z][a-z]+) #(\d+)/){
96 | $currentType=$1; $index=$2;
97 | $paList->{$currentType}//=[];
98 | $paList->{$currentType}->[$index]={};
99 | $currentKey="";
100 | }
101 | next unless defined $index;
102 | if($line=~/^\t([A-Z\sa-z]+): (.+)/){
103 | $currentKey=$1;
104 | $paList->{$currentType}->[$index]->{$1}=$2;
105 | }
106 | elsif($line=~/^\t([A-Z\sa-z]+):(\s)*$/){
107 | $currentKey=$1;
108 | }
109 | elsif($line=~/^\t\t([A-Z\._a-z]+) = "(.+)"/){
110 | $paList->{$currentType}->[$index]->{$currentKey}//={};
111 | $paList->{$currentType}->[$index]->{$currentKey}->{$1}=$2;
112 | }
113 | elsif($line=~/^\t\t([A-Z\sa-z]+): (.+)/){
114 | $paList->{$currentType}->[$index]->{$currentKey}//=[];
115 | push @{$paList->{$currentType}->[$index]->{$currentKey}},{$1=>$2};
116 | }
117 | else{
118 | $paList->{$currentType}->[$index]->{$currentKey}.="\n".$line unless ref $paList->{$currentType}->[$index]->{$currentKey}
119 | }
120 | }
121 | return $paList
122 | }
123 |
124 | sub makeListMenu{
125 | my $lM=["List"];
126 | my $i2O=[];my $menuTypePosition=0;
127 | for my $type (reverse sort keys %$paList){
128 | my @list=@{$paList->{$type}};
129 | my $n=0;my $ind=0; my $splitList=0;my $start=0;my $end=0;my $typeList=[];
130 | while ($ind<=$#list){
131 | $i2O->[$menuTypePosition]//=[];
132 | my $i=object2listItem($type,$ind);
133 | if ($i){
134 | push @$typeList, $i;
135 | push @{$i2O->[$menuTypePosition]},[$type,$ind];
136 | }
137 | if (@$typeList>=10){ # list is full so populate and start new list
138 | $splitList=1;
139 | $end=$ind;
140 | push @$lM, ["$type $start-$end",@$typeList];
141 | $start=$end+1;
142 | $typeList=[];
143 | $menuTypePosition++;
144 | }
145 | $ind++;
146 | }
147 | if ($splitList && @$typeList){ # list is split so needs new list
148 | $end=$ind;
149 | push @$lM, ["$type $start-$end",@$typeList];
150 | }
151 | elsif(@$typeList){ # list is not split so submit as is
152 | push @$lM, [$type,@$typeList];
153 | }
154 | else{ # list is empty so discard
155 | $menuTypePosition--
156 | }
157 | $menuTypePosition++;
158 | }
159 | return $lM,$i2O;
160 | }
161 |
162 | sub object2listItem{
163 | my ($type,$index)=@_;
164 | return undef unless $paList->{$type}->[$index];
165 | return ($type eq "Client") ?
166 | substr($paList->{$type}->[$index]->{Properties}->{'application.name'},0,30):
167 | $paList->{$type}->[$index]->{Name};
168 |
169 | }
170 |
171 | sub objectDescribe{
172 | my ($type,$index)=@_;
173 | my $target= $paList->{$type}->[$index];
174 | my ($x,$y)=(15,56);
175 | $canvas->clear();
176 | $canvas->textAt($x,$y,object2listItem($type,$index),"green bold"); $y-=4;
177 | if ($type =~/^Sink|Source$/){
178 | my @volume =split(/[,\n]\s+/,$target->{'Volume'});
179 | $canvas->textAt($x,$y,"Description : ".$target->{Properties}->{'device.description'},"cyan"); $y-=4;
180 | $canvas->textAt($x,$y,"Device String : ".$target->{Properties}->{'device.string'},"cyan"); $y-=4;
181 | $canvas->textAt($x,$y,"Specification : ".$target->{'Sample Specification'},"cyan"); $y-=4;
182 | for (0..$#volume){
183 | $canvas->textAt($x,$y,"Volume : ".$volume[$_],"cyan"); $y-=4;
184 | }
185 | $canvas->textAt($x,$y,"Card : ".$target->{Properties}->{'alsa.card_name'},"cyan"); $y-=4;
186 | }
187 | elsif ($type =~/^Module$/){
188 | $canvas->textAt($x,$y,"Description : ".$target->{Properties}->{'module.description'},"cyan"); $y-=4;
189 | if ($target->{'Argument'}){
190 | my @argument =split(/\s+/,$target->{'Argument'});
191 | for (0..$#argument){
192 | $canvas->textAt($x,$y,"Argument : ".$argument[$_],"cyan"); $y-=4;
193 | }
194 | }
195 | }
196 | elsif ($type =~/^Client$/){
197 | $canvas->textAt($x,$y,"Driver : ".$target->{'Driver'},"cyan"); $y-=4;
198 | if ($target->{Properties}->{'application.process.id'}){
199 | $canvas->textAt($x,$y,"Binary : ".$target->{Properties}->{'application.process.binary'},"cyan"); $y-=4;
200 | $canvas->textAt($x,$y,"PID : ".$target->{Properties}->{'application.process.id'},"cyan"); $y-=4;
201 | }
202 | }
203 | elsif ($type =~/^Sample$/){
204 | $canvas->textAt($x,$y,"Duration : ".$target->{'Duration'},"cyan"); $y-=4;
205 | $canvas->textAt($x,$y,"Size : ".$target->{'Size'},"cyan"); $y-=4;
206 | $canvas->textAt($x,$y,"Spec : ".$target->{'Sample Specification'},"cyan"); $y-=4;
207 | my $filename=$target->{Properties}->{'media.filename'}//$target->{'Filename'};
208 | if ($filename){
209 | $canvas->textAt($x,$y,"Filename : ".$filename,"cyan"); $y-=4;
210 | }
211 | if ($target->{Properties}->{'application.process.id'}){
212 | $canvas->textAt($x,$y,"Binary : ".$target->{Properties}->{'application.process.binary'},"cyan"); $y-=4;
213 | $canvas->textAt($x,$y,"PID : ".$target->{Properties}->{'application.process.id'},"cyan"); $y-=4;
214 | }
215 | }
216 | elsif ($type =~/^Card$/){
217 |
218 | $canvas->textAt($x,$y,"Active Profile : ".$target->{'Active Profile'},"cyan"); $y-=4;
219 | for (["device.description" ,"Description : "],
220 | ["alsa.long_card_name","Card Name : "],
221 | ["device.bus" ,"Device Bus : "],
222 | ["device.vendor.name" ,"Vendor Name : "],
223 | ["device.product.name","Product Name : "],){
224 | $canvas->textAt($x,$y,$_->[1].$target->{Properties}->{$_->[0]},"cyan"); $y-=4;
225 |
226 | }
227 | }
228 | $canvas->draw();
229 |
230 | }
231 |
--------------------------------------------------------------------------------
/examples/save.grl:
--------------------------------------------------------------------------------
1 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
2 | ⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣠⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
3 | ⠀⠀⢠⡴⠄⣶⣯⡿⣶⡀⠀⠀⠀⠀⢠⣾⣿⣮⣾⣿⣏⠢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
4 | ⠀⠀⠀⠋⢳⣶⣍⣿⣿⡗⠀⠀⣀⣼⣿⣿⣿⣿⣯⡝⢽⣻⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
5 | ⠀⠀⠀⢀⣿⣿⢾⣭⣽⠏⣠⣾⣿⢻⠫⡚⡟⡣⡪⢌⢊⢕⡝⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
6 | ⠀⠀⠀⢰⣿⣲⠟⣿⢟⢠⣿⣻⣻⠁⢐⠑⠋⡟⠺⢺⠷⢪⢻⢫⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
7 | ⠀⠀⠀⠠⣿⣿⡇⣝⡖⢱⣿⣿⣷⡅⠂⡜⡌⣮⢫⢊⢂⢊⣼⢰⣻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
8 | ⠀⠀⠀⠀⠈⠿⣿⡌⡐⣰⣿⣿⣿⣎⢿⠗⢨⣳⣧⣿⣷⣿⣿⣯⡇⣽⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀
9 | ⠀⠀⠀⠀⠀⠀⠉⠛⠟⠛⣿⣿⣿⢿⣿⣮⣎⡽⣯⣿⡟⠹⣿⣿⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
10 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⠇⢠⣿⣿⡿⠀⣿⣿⠁⠀⢿⣿⠈⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
11 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⣿⡏⠀⣼⢿⠿⠁⠀⣟⡟⠀⠀⠘⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
12 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠇⠀⠻⣌⠀⠀⢀⠎⠈⠀⠀⠀⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
13 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡟⠀⠀⠀⠈⠢⡀⠃⠀⠀⠀⠀⠀⠪⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
14 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⡜⠁⠀⠀⠀⣠⢴⡟⣾⡀⠀⠀⠀⠠⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
15 | ⠀⠀⠀⠀⠀⠀⠀⠤⠮⠰⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠾⠷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
16 | ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
17 |
--------------------------------------------------------------------------------
/examples/sprites/File.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⣀","⣖","⣒","⣒","⣒","⡒","⡆"],["⡖","⢓","⣒","⣒","⠒","⡆","⡇","⡇"],["⡇","⠸","⠗","⠂","⠀","⣇","⡧","⠇"],["⠉","⠉","⠉","⠉","⠉","⠁","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/Hash.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⣤","⣤","⣿","⣤","⣤","⣿","⣤","⣤"],["⣤","⣤","⣿","⣤","⣤","⣿","⣤","⣤"],["⠀","⠀","⠛","⠀","⠀","⠛","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/Launcher.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⣠","⠤","⠾","⠀","⠀","⠀"],["⣿","⣿","⣿","⠀","⢸","⢰","⠄","⠀"],["⠉","⠉","⠻","⠤","⣬","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠈","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/bar.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⣴","⠿","⢦","⠀","⠀","⠀"],["⠀","⠀","⣿","⠀","⢸","⠀","⠀","⠀"],["⠀","⠀","⣿","⠀","⢸","⠀","⠀","⠀"],["⠀","⠀","⠻","⣤","⡼","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/boat.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⢀","⠀","⠀","⠀"],["⠀","⠀","⢀","⣴","⣿","⢰","⡀","⠀"],["⣀","⣚","⣛","⣛","⣿","⣘","⣓","⣀"],["⠈","⠛","⠓","⠛","⠚","⠛","⠚","⠁"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/cow.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⢀","⣱","⣁","⡀","⠀","⠀"],["⠀","⡏","⠹","⠤","⡼","⠇","⠀","⠀"],["⡠","⠛","⡍","⠉","⡕","⠢","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/crwoned.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/default.spb:
--------------------------------------------------------------------------------
1 | {
2 | NewSprite=>[["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]],
3 | }
4 |
--------------------------------------------------------------------------------
/examples/sprites/die.spr:
--------------------------------------------------------------------------------
1 | [["⢰","⠪","⣛","⠍","⠩","⣛","⠝","⡆"],["⠈","⠑","⢤","⠰","⠆","⡤","⠋","⠀"],["⠛","⢧","⣀","⠉","⢉","⣡","⠞","⠛"],["⣤","⡴","⠚","⠋","⠙","⠓","⢤","⣤"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/dummy.spb:
--------------------------------------------------------------------------------
1 | {
2 | cow=>[["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⢀","⣱","⣁","⡀","⠀","⠀"],["⠀","⡏","⠹","⠤","⡼","⠇","⠀","⠀"],["⡠","⠛","⡍","⠉","⡕","⠢","⠀","⠀"]],
3 | empty=>[["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]],
4 | man1=>[["⠀","⠀","⣠","⡤","⠤","⡀","⠀","⠀"],["⠀","⠀","⣙","⡳","⣒","⣁","⣤","⠄"],["⠀","⣼","⠃","⣿","⣇","⠀","⠀","⠀"],["⠀","⠀","⣴","⣋","⠈","⢳","⣤","⡀"]],
5 | spiral=>[["⡖","⣒","⣒","⣒","⣒","⣒","⢲","⠀"],["⡇","⡇","⡖","⣒","⢲","⢸","⢸","⠀"],["⡇","⣇","⣓","⣚","⣸","⢸","⢸","⠀"],["⣓","⣒","⣒","⣒","⣒","⣚","⣸","⠀"]],
6 | }
7 |
--------------------------------------------------------------------------------
/examples/sprites/empty.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/forbidden.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⢀","⣀","⣀","⡀","⠀","⠀"],["⢠","⡞","⣉","⣀","⣀","⣉","⢳","⡄"],["⠘","⢧","⣉","⠉","⠉","⣉","⡼","⠃"],["⠀","⠀","⠈","⠉","⠉","⠁","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/game1.spb:
--------------------------------------------------------------------------------
1 | {
2 | manhatwalk2=>[["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⣈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠸","⠀","⣇","⣸","⠑","⠒","⠂","⠀"],["⠰","⠖","⠃","⠘","⣇","⡀","⠀","⠀"]],
3 | manhatwalk4=>[["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⠈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠀","⡎","⣇","⣺","⠒","⠀","⠀","⠀"],["⠀","⢰","⣏","⡈","⠹","⠦","⠄","⠀"]],
4 | manhatwalk1=>[["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⠈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠀","⡎","⣇","⣺","⠒","⠀","⠀","⠀"],["⠀","⢰","⣏","⡈","⠹","⠦","⠄","⠀"]],
5 | manhatwalk3=>[["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⠈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠀","⠪","⣇","⡸","⠑","⠄","⠀","⠀"],["⠀","⠲","⢺","⣟","⠂","⠀","⠀","⠀"]],
6 | }
7 |
--------------------------------------------------------------------------------
/examples/sprites/help.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⣀","⡀","⠀","⠀","⠀"],["⠀","⠀","⠾","⠉","⠉","⣷","⠀","⠀"],["⠀","⠀","⠀","⢠","⡞","⠉","⠀","⠀"],["⠀","⠀","⠀","⢨","⡅","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/info.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠐","⠿","⠿","⠂","⠀","⠀","⠀"],["⠀","⠠","⢶","⣶","⠀","⠀","⠀","⠀"],["⠀","⠀","⢸","⣿","⠀","⠀","⠀","⠀"],["⠀","⠀","⠘","⢿","⣤","⠼","⠃","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/m.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/man1.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⣠","⡤","⠤","⡀","⠀","⠀"],["⠀","⠀","⣙","⡳","⣒","⣁","⣤","⠄"],["⠀","⣼","⠃","⣿","⣇","⠀","⠀","⠀"],["⠀","⠀","⣴","⣋","⠈","⢳","⣤","⡀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/manhatwalk1.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⣈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠪","⠀","⣇","⣸","⠑","⠄","⠀","⠀"],["⠠","⣞","⠁","⠈","⠳","⠔","⠂","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/manhatwalk2.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⣈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠸","⠀","⣇","⣸","⠑","⠒","⠂","⠀"],["⠰","⠖","⠃","⠘","⣇","⡀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/manhatwalk3.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⠈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠀","⠪","⣇","⡸","⠑","⠄","⠀","⠀"],["⠀","⠲","⢺","⣟","⠂","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/manhatwalk4.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⢤","⠿","⡿","⡤","⠀","⠀","⠀"],["⠀","⠈","⣲","⣖","⠋","⠀","⠀","⠀"],["⠀","⠪","⣇","⡸","⠑","⠄","⠀","⠀"],["⠀","⠲","⢺","⣟","⠂","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/mm.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/oyster.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⣀","⣠","⣤","⣀","⠀","⠀"],["⣴","⠋","⢁","⡤","⠤","⣌","⠙","⣦"],["⠻","⣄","⠙","⠦","⠤","⢾","⣥","⠞"],["⢴","⣞","⣓","⣀","⣀","⣒","⣲","⠦"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/perly.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/photos.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⣀","⣖","⣒","⣒","⣒","⡒","⡆"],["⡖","⢓","⣒","⣒","⠒","⡆","⡇","⡇"],["⡇","⢇","⠢","⢂","⠇","⡇","⡇","⡇"],["⠧","⠤","⠭","⠥","⠤","⠗","⠋","⠁"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/rocket.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⡠","⠊","⠲","⣄","⠀","⠀"],["⠀","⠀","⡇","⠀","⠀","⣿","⠀","⠀"],["⠀","⠀","⡧","⡀","⣠","⢿","⡀","⠀"],["⠀","⡾","⠀","⠑","⠋","⠀","⠿","⡄"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/spiral.spr:
--------------------------------------------------------------------------------
1 | [["⡖","⣒","⣒","⣒","⣒","⣒","⢲","⠀"],["⡇","⡇","⡖","⣒","⢲","⢸","⢸","⠀"],["⡇","⣇","⣓","⣚","⣸","⢸","⢸","⠀"],["⣓","⣒","⣒","⣒","⣒","⣚","⣸","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/testmessage.spb:
--------------------------------------------------------------------------------
1 | {
2 | NewSprite=>[["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"],["⠀","⠀","⠀","⠀","⠀","⠀","⠀","⠀"]],
3 | }
4 |
--------------------------------------------------------------------------------
/examples/sprites/warn.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⢀","⡀","⠀","⠀","⠀"],["⠀","⠀","⠸","⣭","⣿","⠇","⠀","⠀"],["⠀","⠀","⠀","⠸","⠇","⠀","⠀","⠀"],["⠀","⠀","⠀","⢴","⡦","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/sprites/warn2.spr:
--------------------------------------------------------------------------------
1 | [["⠀","⠀","⠀","⢀","⡀","⠀","⠀","⠀"],["⠀","⠀","⠸","⣭","⣿","⠇","⠀","⠀"],["⠀","⠀","⠀","⠸","⠇","⠀","⠀","⠀"],["⠀","⠀","⠀","⢴","⡦","⠀","⠀","⠀"]]
2 |
--------------------------------------------------------------------------------
/examples/surmaphoto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saiftynet/Term-Graille/c467644004a72a34c607ebdf6d8ec4c25afbac70/examples/surmaphoto.png
--------------------------------------------------------------------------------
/examples/testanimate.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | #use lib "../lib/";
4 | use Term::Graille qw/colour paint printAt clearScreen border/;
5 | use Image::Magick;
6 | use Time::HiRes "sleep";
7 |
8 | # convert2grl--converts an image to .grv format.
9 |
10 | my $animationFolder=$ARGV[0]||"./animations/cheetah/";
11 | opendir my $dir,$animationFolder or die;
12 | my @files=sort grep !/^(\.|\.\.|.*\.pl)$/,readdir $dir;
13 |
14 | my $canvas = Term::Graille->new(
15 | width => 120,
16 | height => 50,
17 | top=>4,
18 | left=>10,
19 | borderStyle => "double",
20 | borderColour => "yellow",
21 | title=>" Animation test ",
22 | );
23 | my $animation=[];
24 |
25 | my $frame=0;
26 | for my $image (@files){
27 | $canvas->clear();
28 | print "Loading image ",$animationFolder.$image," ",++$frame,"\n";
29 | $animation->[$frame]=[];
30 | loadImage($animationFolder.$image);
31 | #loadImage("./animations/chimp/chimp$frame.png");
32 | foreach my $row (0..$#{$canvas->{grid}}){
33 | foreach my $col(0..$#{$canvas->{grid}->[0]}){
34 | $animation->[$frame]->[$row]->[$col]=$canvas->{grid}->[$row]->[$col];
35 | }
36 | }
37 | }
38 |
39 | sleep 1;
40 | clearScreen();
41 |
42 |
43 | foreach (0..100){
44 | foreach my $frame (1..@$animation){
45 | next unless ref $animation->[$frame];
46 | $canvas->{grid}=$animation->[$frame];
47 | $canvas->draw();
48 | sleep 0.08;
49 | }
50 | }
51 |
52 | sub loadImage{
53 | my $imgfile=shift;
54 | my $image = Image::Magick->new();
55 | my $wh = $image->Read($imgfile);
56 | $image->Resize(geometry => "$canvas->{width}x$canvas->{height}");
57 | die $wh if $wh;
58 | $image->set('monochrome'=>'True');
59 | $image->Negate();
60 | for (my $x =0;$x<$canvas->{width};$x++){
61 | for (my $y=0;$y<$canvas->{height};$y++){
62 | $canvas->set($x,$y) if $image->GetPixel("x"=>$x,"y",$canvas->{height}-$y);
63 | }
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/examples/turtle.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env perl
2 | use strict; use warnings;
3 | use lib "../lib/";
4 | use Term::Graille qw/colour paint printAt clearScreen border/;
5 | use Time::HiRes "sleep";
6 |
7 | my $canvas = Term::Graille->new(
8 | width => 100,
9 | height => 64,
10 | top=>3,
11 | left=>10,
12 | title=>"Interactive Turtle Demo",
13 | borderStyle => "double",
14 | );
15 | my $q="";my @commands;
16 | while ($q ne "quit"){
17 | drawTurtle();
18 | $canvas->draw();
19 | $q=prompt();
20 | push @commands, $q;
21 | clearScreen();
22 | $canvas->clear();
23 | $canvas->logo("ce;dir 0;");
24 | $canvas->logo($_) foreach (@commands);
25 |
26 | printAt (5,70,[@commands])
27 | }
28 |
29 |
30 | sub drawTurtle{
31 | $canvas->logo("bk 2;lt 90;pu;fd 3;pd; pc white;rt 120;fd 6;rt 120;fd 6;rt 120;pu;fd 3;rt 90;pd");
32 | }
33 |
34 |
35 | sub prompt{
36 | printAt(20,0,"");
37 | print">>";
38 | $_=;
39 | chomp;
40 | return $_;
41 | }
42 |
--------------------------------------------------------------------------------
/examples/visualiser.pl:
--------------------------------------------------------------------------------
1 | #!/usr/env perl
2 | ########## Audio Analyser ###########
3 | use strict; use warnings;
4 | use lib "../lib/";
5 |
6 | use Term::Graille qw/colour paint printAt cursorAt clearScreen border blockBlit block2braille pixelAt/;
7 | use Term::Graille::Interact;
8 | use Term::Graille::Menu;
9 | use Term::Graille::Font qw/loadGrf fontWrite/;
10 |
11 | my $io=Term::Graille::Interact->new(); # For interactions menu and keyboard
12 | $io->{debugCursor}=[22,45]; # Put key presses detected ny Interact on the screen
13 |
14 | my ($source,$recorder,$fh,$buffer,@data);
15 |
16 | my $canvas = Term::Graille->new(
17 | width => 120,
18 | height => 60,
19 | top=>4,
20 | left=>10,
21 | borderStyle => "double",
22 | borderColour => "blue",
23 | title => "Audio-Analyser",
24 | titleColour => "red",
25 | );
26 |
27 | # draw the initial screen
28 | my $grf=loadGrf("./fonts/ZX Times.grf");
29 | fontWrite($canvas,$grf,11,13,"Mic Input");
30 | fontWrite($canvas,$grf,13,10,"Waveform");
31 | fontWrite($canvas,$grf,13,7,"Analyser");
32 | $canvas->textAt(15,20,"A not-so-realtime visual audio analyser for","green italic");
33 | $canvas->textAt(40,16,"Microphone inputs","yellow italic");
34 | $canvas->textAt(16,8," ");
35 | $canvas->textAt(24,4," ");
36 |
37 | my @listCaptures=`arecord -l`;
38 | my %devices=map{ /card (\d+):[^\[]+(\[[^\]]+\]), device (\d+)/ ;$2 =>"hw:$1,$3" }
39 | grep /card (\d+):[^\[]+(\[[^\]]+\]), device (\d+)/ , @listCaptures;
40 |
41 | my $menu=new Term::Graille::Menu(
42 | menu=>[["Monitor","Start","Stop"],
43 | ["Source",keys %devices],
44 | ["Play","Raw",["Filters","HiPass","LowPass"]],
45 | "About"],
46 | redraw=>\&refreshScreen,
47 | dispatcher=>\&menuActions,
48 | );
49 |
50 | my %actions=(
51 | Start=>sub{
52 | $io->{refreshRate}=1;
53 | $io->updateAction(sub {recordDisplay() } );
54 | },
55 | Stop=>sub{
56 | $io->{refreshRate}=20;
57 | close $fh if $fh;;
58 | kill $recorder if $recorder;
59 | $io->stopUpdates();
60 | },
61 | );
62 |
63 | sub recordDisplay{
64 | return unless $source;
65 | my ($cmd,$rawData);
66 |
67 | # using arecord...not sure in arecord can record fractional seconds
68 | $cmd = "arecord -D $source -c 1 -d 1 -q";
69 | $rawData = '';
70 | $recorder = open ($fh, '-|:raw', $cmd )or die "Couldn't launch [$cmd] $!";
71 |
72 | while (1) {
73 | my $success = read $fh, $rawData , 100, length($rawData);
74 | die $! if not defined $success;
75 | last if not $success;
76 | }
77 |
78 | @data= unpack 'C*', $rawData ;
79 | close $fh;
80 | kill $recorder;
81 | printAt(2,60,scalar @data);
82 | #$canvas->clear();
83 | $canvas->scroll("l",undef,10);
84 | for my $pt (40..$#data){
85 | next unless $pt%2;
86 | my $d=$data[$pt];
87 | my $c=(qw/white cyan blue green yellow yellow magenta red/)[abs ($d-128)/16];
88 | my $l=60*$d/2**8;$l+=$l>30?-30:30;
89 | $canvas->set(99+(20*$pt/(@data-40)),$l,colour($c));
90 | }
91 | $canvas->draw();
92 | }
93 |
94 |
95 | foreach my $dev(keys %devices){
96 | $actions{$dev}=sub{
97 | kill $recorder if $recorder;
98 | $recorder=undef;
99 | $source=$devices{$dev};
100 | }
101 | }
102 |
103 | sub menuActions{
104 | my ($action)=@_;
105 | if (exists $actions{$action}){
106 | $actions{$action}->($io->{gV})
107 | }
108 | };
109 |
110 | $io->addObject(object => $menu,trigger=>"m");
111 | $canvas->draw();
112 | $io->run();
113 |
114 | sub refreshScreen{
115 | clearScreen() unless (shift);
116 | $canvas->draw();
117 | }
118 |
--------------------------------------------------------------------------------
/lib/Term/Graille/Chart.pm:
--------------------------------------------------------------------------------
1 | package Term::Graille::Chart;
2 | use strict; use warnings;
3 | use utf8;
4 | use Term::Graille qw/colour paint printAt clearScreen border blockBlit block2braille pixelAt/;
5 | use open ":std", ":encoding(UTF-8)";
6 |
7 | our $VERSION="0.09";
8 |
9 | my $chart=new Term::Graille::Chart(
10 | hOffset=>10,
11 | BottomAxis=>{tickSeparation=>7,tickLabels=>[" ",qw/ red green yellow violet indigo blue/," "]},
12 | LeftAxis =>{tickSeparation=>2,tickLabels=>[0..5]},
13 | RightAxis =>{tickSeparation=>3,tickLabels=>[0..3]},
14 | TopAxis=>{tickSeparation=>7,tickLabels=>[" ",qw/ red green yellow violet blue/," "]},
15 | );
16 | print "\n\n", join("\n",@{$chart->mergeAxes()});
17 |
18 | sub new{
19 | my ($class, %params) = @_;
20 | my $self={};
21 | $self->{hOffset}=$params{hOffset}//6;
22 | $self->{vOffset}=$params{vOffset}//6;
23 | $self->{Axes}={};
24 | bless $self,$class;
25 | foreach my $side (qw/BottomAxis TopAxis LeftAxis RightAxis/){
26 | next unless $params{$side};
27 | $self->{Axes}->{$side}->{params}=$params{$side};;
28 | $self->makeAxis($side) ;
29 | }
30 | return $self;
31 |
32 | }
33 |
34 | sub makeAxis{
35 | my ($self,$side)=@_;
36 | my $params=$self->{Axes}->{$side}->{params};
37 | my $tickSeparation=$$params{tickSeparation};
38 | my $tickLabels=$$params{tickLabels};
39 | my $title=$$params{title};
40 | my @axis=();
41 | if ($side=~ /BottomAxis|TopAxis/){
42 | my $gap="─"x( $tickSeparation-1);
43 | my $axis=(" "x$self->{hOffset})."┼".(($gap."┼")x(@{$tickLabels}-2)).$gap."┤";
44 | my $axisWidth=$tickSeparation*$#{$tickLabels}+1;
45 | $self->{chartWidth}=$axisWidth if (!$self->{chartWidth} || $axisWidth >$self->{chartWidth});
46 | my $tickLabelLine=(" "x$self->{hOffset});
47 | foreach my $tick (0..$#{$tickLabels}){
48 | substr ($tickLabelLine, ($self->{hOffset}+$tick*$tickSeparation+1)-length($tickLabels->[$tick])/2,)=$tickLabels->[$tick];
49 | $tickLabelLine.=" "x($tickSeparation-1);
50 | }
51 | $self->{$side}=$side=~/^T/?[$tickLabelLine,$axis]:[$axis,$tickLabelLine];
52 |
53 | }
54 | else{
55 |
56 | my $axisHeight=$tickSeparation*$#{$tickLabels}+1;
57 | $self->{chartHeight}=$axisHeight if (!$self->{chartHeight} || $axisHeight >$self->{chartHeight});
58 | if ($side=~/^L/){
59 | my @gap=(" "x$self->{hOffset}."│")x($tickSeparation-1);
60 | foreach my $tick (0..$#{$tickLabels}){
61 | my $row=" "x$self->{hOffset}."│";
62 | substr ($row,$self->{hOffset}-(1+length $tickLabels->[$tick]),)=$tickLabels->[$tick]." ┼";
63 | unshift @axis,@gap if $tick;
64 | unshift @axis,$row;
65 | }
66 | }
67 | else{
68 | my @gap=("│")x($tickSeparation-1);
69 | foreach my $tick (0..$#{$tickLabels}){
70 | my $row="┼ ".$tickLabels->[$tick];
71 | unshift @axis,@gap if $tick;
72 | unshift @axis,$row;
73 | }
74 | }
75 |
76 | $self->{$side}=[@axis]
77 | }
78 | }
79 |
80 | sub mergeAxes{
81 | my $self=shift;
82 | my @Axes;
83 | if (exists $self->{LeftAxis} && exists $self->{BottomAxis} ){
84 | @Axes=@{$self->{LeftAxis}};
85 | my $bA=$self->{BottomAxis}->[0];
86 | $bA=~s/^ +//;
87 | substr ($Axes[-1],-1,)= $bA;
88 | push @Axes,$self->{BottomAxis}->[1];
89 | }
90 | else {
91 | return ["unable to create axes"];
92 | }
93 | if (exists $self->{RightAxis}){
94 | my @rA=@{$self->{RightAxis}};
95 | substr ($Axes[-2],-1,)= $rA[-1];
96 | for (my $i=2;$i<=@rA;$i++){
97 | $Axes[@Axes-$i-1].=(" "x($self->{chartWidth}-2)).$rA[@rA-$i];
98 | }
99 | }
100 | if (exists $self->{TopAxis}){
101 | my $tA=$self->{TopAxis}->[1];
102 | $tA=~s/^ +//;
103 | substr ($Axes[0],$self->{hOffset},$self->{chartWidth})= $tA;
104 | unshift @Axes,$self->{TopAxis}->[0];
105 |
106 | }
107 | return [@Axes];
108 | }
109 |
110 | sub autoAxis{
111 | my ($self,$side,$data,$nTicks,$axisLength)=@_;
112 |
113 |
114 | }
115 |
116 |
117 |
118 |
119 |
120 | # given a list of numbers determines whether the numbers cross zero;
121 | sub zeroCrossing{
122 | my @list=sort @_;
123 | return ($list[0] <0 && $list[-1] >0)?1:0;
124 | }
125 |
126 | #given a list of data (as an array or arrayref, return minimum and maximum)
127 | sub minmax{
128 | my @list=@_;
129 | @list=@{$list[0]} if (ref $list[0]);
130 | my $max=my $min = shift @list;;
131 | foreach my $v (@list){
132 | $max=$v if $max<$v;
133 | $min=$v if $min>$v;
134 | }
135 | return ($min,$max)
136 | }
137 |
138 | # niceTicks
139 | # takes minimum value, maximum value and number of desired ticks;
140 | # returns list of ticks
141 | sub niceTicks{
142 | my ($axisStart,$axisEnd,$nTicks)=@_;
143 | ($axisStart,$axisEnd,my $tick)=niceAxis($axisStart,$axisEnd,$nTicks);
144 | my @tickList=($axisStart);
145 | push @tickList,$tickList[-1]+$tick while ($tickList[-1]<=$axisEnd);
146 | return @tickList;
147 | }
148 |
149 | # niceAxis
150 | # takes minimum value, maximum value and number of desired ticks;
151 | # returns nice axis start, axis end and gap between ticks
152 | sub niceAxis{
153 | my ($axisStart,$axisEnd,$nTicks)=@_;
154 | $nTicks//=5;
155 | my $axisWidth=$axisEnd-$axisStart;
156 | return undef unless $axisWidth>0; # error is start >= end
157 |
158 | my $niceRange=niceNumber($axisWidth,0);
159 | my $niceTick =niceNumber($niceRange/($nTicks-1) , 1);
160 | $axisStart=floor($axisStart/$niceTick)*$niceTick;
161 | $axisEnd = ceil($axisEnd/$niceTick)*$niceTick;
162 | return ($axisStart,$axisEnd,$niceTick)
163 | }
164 |
165 | #
166 | sub niceNumber{
167 | my ($value,$round)=@_;
168 |
169 | my $exp= floor(log($value)/log(10));
170 | my $fraction=$value/(10**$exp);
171 |
172 | if ($round){
173 | for ($fraction){
174 | $_ < 1.5 && return 1*(10**$exp);
175 | $_ < 3.0 && return 2*(10**$exp);
176 | $_ < 7.0 && return 5*(10**$exp);
177 | return 10*(10**$exp);
178 | }
179 | }
180 | else{
181 | for ($fraction){
182 | $_ < 1 && return 1*(10**$exp);
183 | $_ < 2 && return 2*(10**$exp);
184 | $_ < 4 && return 4*(10**$exp);
185 | return 10*(10**$exp);
186 | }
187 | }
188 | }
189 |
190 |
191 | # saves having to use POSIX
192 | sub floor{
193 | my $v=shift;
194 | return int($v)-($v<0?1:0);
195 | }
196 |
197 | # saves having to use POSIX
198 | sub ceil{
199 | my $v=shift;
200 | return int($v)+ ($v==int($v)?0:1);
201 | }
202 |
203 |
204 |
205 |
206 | 1;
207 |
208 |
209 |
--------------------------------------------------------------------------------
/lib/Term/Graille/Dialog.pm:
--------------------------------------------------------------------------------
1 | package Term::Graille::Dialog;
2 |
3 | use strict;use warnings;
4 | use lib "../../../lib";
5 | use Term::Graille qw/colour printAt clearScreen border cursorAt wrapText/;
6 | use base 'Exporter';
7 | our @EXPORT_OK = qw/deathSentence confirm prompt caution/;
8 | use utf8;
9 |
10 | our $VERSION=0.10;
11 |
12 | =head3 Cnew(%params)>
13 |
14 | Creates a new dialog box; params are
15 | C the possible options that may be selected
16 | C This is a function to redraws the application screen.
17 | The dialog box may overwrite parts of the application screen, and this
18 | function needs to be provided to restore the screen.
19 | C The dialog does not call any functions itself, instead returns the
20 | button value pressed. if the $dialog->{entry} is set this is also sent. In
21 | prompts, the entry is populated by user. It is upto the main application
22 | to use this data (the callback function supplied)
23 | C Optional. The default position is [2,2], but setting this parameter allows
24 | the dialog to be placed elsewhere
25 | C Optional. The selected item is highlighted default "black on_white"
26 | C Optional. The normal colour of text items "white on_black"
27 |
28 |
29 | =cut
30 |
31 | my %icons=(
32 | die=> [[colour("red")."⢰","⠪","⣛","⠍","⠩","⣛","⠝","⡆"],
33 | ["⠈","⠑","⢤","⠰","⠆","⡤","⠋","⠀"],
34 | ["⠛","⢧","⣀","⠉","⢉","⣡","⠞","⠛"],
35 | ["⣤","⡴","⠚","⠋","⠙","⠓","⢤","⣤".colour("reset")]],
36 | info=> [[colour("blue")."⠀","⠐","⠿","⠿","⠂","⠀","⠀","⠀"],
37 | ["⠀","⠠","⢶","⣶","⠀","⠀","⠀","⠀"],
38 | ["⠀","⠀","⢸","⣿","⠀","⠀","⠀","⠀"],
39 | ["⠀","⠀","⠘","⢿","⣤","⠼","⠃","⠀".colour("reset")]],
40 | error=> [[colour("yellow")."⠀","⠀","⠀","⢀","⡀","⠀","⠀","⠀"],
41 | ["⠀","⠀","⠸","⣭","⣿","⠇","⠀","⠀"],
42 | ["⠀","⠀","⠀","⠸","⠇","⠀","⠀","⠀"],
43 | ["⠀","⠀","⠀","⢴","⡦","⠀","⠀","⠀".colour("reset")]],
44 | forbidden=>[[colour("red")."⠀","⠀","⢀","⣀","⣀","⡀","⠀","⠀"],
45 | ["⢠","⡞","⣉","⣀","⣀","⣉","⢳","⡄"],
46 | ["⠘","⢧","⣉","⠉","⠉","⣉","⡼","⠃"],
47 | ["⠀","⠀","⠈","⠉","⠉","⠁","⠀","⠀".colour("reset")]],
48 | query=>[[colour("green")."⠀","⠀","⠀","⣀","⡀","⠀","⠀","⠀"],
49 | ["⠀","⠀","⠾","⠉","⠉","⣷","⠀","⠀"],
50 | ["⠀","⠀","⠀","⢠","⡞","⠉","⠀","⠀"],
51 | ["⠀","⠀","⠀","⢨","⡅","⠀","⠀","⠀".colour("reset")]],
52 | );
53 |
54 |
55 | sub new{
56 | my ($class,%params) = @_;
57 | my $self={};
58 | bless $self,$class;
59 |
60 | $self->{buttons}=$params{buttons}//[];
61 | $self->{selected}=$params{selected}// ""; #if a button is tob pres elected
62 |
63 | $self->{message}=$params{message}// "No Message";
64 |
65 | $self->{redraw}=$params{redraw} if (exists $params{redraw}); # function to redraw application
66 | $self->{callback}=$params{callback} if (exists $params{callback}); # function to call after menu item selected
67 | $self->{transient}=$params{transient}//1;
68 | $self->{title}=$params{title}//"Dialog";
69 | $self->{normalColour}=$params{titleColour}//"yellow";
70 | $self->{pos}=$params{pos}//[2,2];
71 | $self->{geometry}=$params{geometry}//[8,40];
72 | $self->{param}=$params{param}; # optional parameter
73 | $self->{icon}=$params{icon};
74 | $self->{highlightColour}=$params{highlightColour}//"black on_white";
75 | $self->{normalColour}=$params{normalColour}//"white on_black";
76 | $self->{keyAction}={
77 | "[D" =>sub{$self->prevItem()},
78 | "[C" =>sub{$self->nextItem()},
79 | "enter"=>sub{$self->selectItem()},
80 | "esc" =>sub{$self->{close}->()},
81 | others =>sub{my ($obj,$pressed,$gV)=@_;$self->addChar($pressed)},
82 | };
83 | return $self;
84 | }
85 |
86 | sub mode{
87 | my ($self,$mode,@etc)=@_;
88 | for ($mode){
89 | /okc/i && do {$self->{buttons}=[qw/OK Cancel/]; last;};
90 | /ok/i && do {$self->{buttons}=[qw/OK/]; last;};
91 | /ync/i && do {$self->{buttons}=[qw/Yes No Cancel/]; last;};
92 | /input/i && do {$self->{buttons}=[qw/Submit Cancel/];
93 | $self->{entry}="";$self->{entryPos}=0; last};
94 |
95 | }
96 |
97 | }
98 |
99 | sub draw{
100 | my $self=shift;
101 | if (!ref $self->{message}){
102 | $self->{message}=wrapText( $self->{message},$self->{geometry}->[1]-15);
103 | }
104 | my $entryLines=(defined $self->{entry})?2:0;
105 | my $buttons="";
106 | foreach my $button (@{$self->{buttons}}){
107 | $buttons.=" ".colour($self->{selected} && $self->{selected} eq $button?"black on_white":"white")."[$button]".colour("reset");
108 | }
109 | border(@{$self->{pos}},$self->{pos}->[0]+max(($self->{icon}?6:0),@{$self->{message}}+$entryLines+1),
110 | $self->{geometry}->[1]+$self->{pos}->[1],
111 | "double","green",
112 | $self->{title},$self->{titleColour});
113 | printAt($self->{pos}->[0]+1,6,[@{$self->{message}},($entryLines?($self->{entry},"-"x($self->{geometry}->[1]-4)):()),$buttons]);
114 |
115 | printAt($self->{pos}->[0]+2,$self->{geometry}->[1]-5,$icons{$self->{icon}}) if $self->{icon};
116 |
117 | }
118 |
119 |
120 | sub addChar{
121 | my ($self,$ch)=@_;
122 | return unless exists $self->{entry};
123 | $self->{entry}.=$ch if (length $ch ==1 );
124 | chop $self->{entry} if ($ch =~/back/ );
125 | $self->draw();
126 |
127 | }
128 |
129 | sub selectedPos{
130 | my ($self)=@_;
131 | return 0 unless $self->{selected};
132 | for my $p (0..$#{$self->{buttons}}){
133 | return $p if ($self->{selected} eq $self->{buttons}->[$p])
134 | }
135 | return 0;
136 | }
137 |
138 | sub nextItem{
139 | my ($self)=@_;
140 | my $p=$self->selectedPos();
141 | $p+=($p<$#{$self->{buttons}})?1:0;
142 | $self->{selected}= $self->{buttons}->[$p];
143 | #printAt(2,50, " $p $self->{selected} ".$#{$self->{buttons}}." ".join("--",@{$self->{buttons}}));
144 | $self->draw();
145 | }
146 |
147 | sub prevItem{
148 | my ($self)=@_;
149 | my $p=$self->selectedPos();
150 | $self->{selected}= $self->{buttons}->[$p-($p>0)?1:0];
151 | #printAt(2,50, " $p $self->{selected} ".$#{$self->{buttons}}." ".join("--",@{$self->{buttons}}));
152 | $self->draw();
153 | }
154 |
155 | sub selectItem{
156 | my ($self)=@_;
157 | $self->{param}->{button}=$self->{selected};
158 | $self->{param}->{entry}=$self->{entry};
159 | if (exists $self->{callback}) {$self->{callback}->($self->{param})};
160 | }
161 |
162 |
163 | sub close{ # what needs to be done before Interact de-activates widget
164 | my ($self)=@_;
165 | $self->{redraw}->();
166 | }
167 |
168 | sub max{
169 | return (sort{$a <=> $b}@_)[-1]
170 | }
171 |
172 | sub min{
173 | return (sort{$a <=> $b}@_)[0]
174 | }
175 |
176 | sub prompt{
177 |
178 | }
179 |
180 |
181 | sub deathSentence{ # waiting to be exported
182 | my $str=shift;
183 | my @epitaphs=(
184 | "'Forgive him Larry, for he knows not how to code'",
185 | "'I told you I was sick'",
186 | "'It is a far far better code that I do, than you have ever run'",
187 | "'Your references have been counted and found wanting'",
188 | "'Goodbye old friend, may the Schwartz be with you'",
189 | "'she believed she could, but she couldn\'t'",
190 | );
191 | my $message=[@{wrapText(colour("red").$str.colour("reset"),45)},caller(),
192 | @{wrapText(colour("yellow").($epitaphs[rand(@epitaphs)]).colour("reset"),45)}];
193 |
194 | border(10,4,11+@$message,64,"double","green","RIP","yellow");
195 | printAt(11,6,$message);
196 | printAt(12,55,$icons{die});
197 |
198 | printAt(18,0,"");
199 | sleep 10;
200 | exit;
201 | }
202 |
203 | sub fileSelector{
204 | my ($dir,$filter,$callback,$redraw,$parameter)=@_;
205 |
206 |
207 |
208 | }
209 |
210 |
211 | 1;
212 |
--------------------------------------------------------------------------------
/lib/Term/Graille/Font.pm:
--------------------------------------------------------------------------------
1 | package Term::Graille::Font;
2 | use strict; use warnings;
3 | use utf8;
4 | use Data::Dumper;
5 | use Term::Graille qw/block2braille/;
6 | use base 'Exporter';
7 | our @EXPORT_OK = qw/convertDG saveGrf loadGrf fontWrite/;
8 | use open ":std", ":encoding(UTF-8)";
9 |
10 | our $VERSION="0.09";
11 |
12 |
13 | =head1 NAME
14 |
15 | Term::Graille::Font - convert and use ZX Spectrum fonts in Term::Graille
16 |
17 | =head1 SYNOPSIS
18 |
19 | use Term::Graille::Font qw/convertDG saveGrf fontWrite/;
20 | my $grf=convertDG("$fontName.z80.asm");
21 | $canvas->blockBlit($grf->{A},$gridX,$gridY); # old method single character
22 | fontWrite($canvas,$grf,$gridX,$gridY,$text); # new method text string
23 | saveGrf($grf,"$fontName.grf");
24 |
25 | =head1 DESCRIPTION
26 |
27 | This allows the creation, saving and usage of Braille Character to form
28 | Bitmap 8x8 font. It currently only accepts DameinGuards z80.asm files
29 | as found in damieng.com/typography/zx-origins/ where there a couple of
30 | hundred fonts available.
31 |
32 | =begin html
33 |
34 |
35 |
36 | =end html
37 |
38 |
39 | =head1 FUNCTIONS
40 |
41 | =cut
42 |
43 | =head3 C
44 |
45 | Reads an ASM file as on Damien Guard's typography pages and returns a hashref
46 | containing the extracted 8x8 fonts converted into 4x2 Braille characters.
47 |
48 | =cut
49 |
50 | sub convertDG{
51 | my $file=shift;
52 | my $font="";
53 | open my $zxFont,"<:utf8",$file or die "Unable to open fontfile $file $!;\n";
54 | $font.=$_ while(<$zxFont>);
55 | close $zxFont;
56 |
57 | $font=~s/^[\s\t]?;([^\n]+)/{/g;
58 | my $info=$1;
59 | $font=~s/defb &/[[0x/g;
60 | $font=~s/,&/],[0x/g;
61 | $font=~s/ ; /]],# /g;
62 | $font=~s/\s([^#\s]*)#\s(.)/ '$2'=>$1/g;
63 | $font=~s/\'\'\'/\"\'\"/g;
64 | $font=~s/\'\\\'/\'\\\\\'/g;
65 | $font.="\n}\n";
66 | # print $font;
67 | my $binFont=eval($font);
68 | my $grlFont={};
69 | for (keys %$binFont){
70 | use utf8;
71 | $grlFont->{$_}=block2braille($binFont->{$_}) ;
72 | }
73 | $grlFont->{info}=$info||"";
74 | return $grlFont;
75 | }
76 |
77 | =head3 C
78 |
79 | Uses Data::Dumper to produce convert a font hashref into a file that can
80 | be read using loadGrf
81 |
82 | =cut
83 |
84 | sub saveGrf{
85 | my ($grf,$file)=@_;
86 | my $output=Dumper([$grf]);
87 | $output=~ s/\\x\{([0-9a-f]{2,})\}/chr hex $1/ge;
88 | $output=~s/^\$VAR1 = \[\n\s+| \];\n?$//g;
89 | $output=~s/\[\n\s+\[/\[\[/g;
90 | $output=~s/\n\s+([^\s])/$1/g;
91 | $output=~s/\]\],/\]\],\n/g;
92 | die "Conversion failed\n" if (length $output <100);
93 | open my $dat,">:utf8","$file" or die "Unable to save fontfile $file $!;\n";
94 | print $dat $output;
95 | close $dat;
96 | }
97 |
98 |
99 | =head3 C
100 |
101 | Loads a font hashref from a file. The hashRef indexes 4x2 braille character
102 | blocks by character they represent; This may be used to represent any kind of
103 | character block, including tilemaps, sprites etc.
104 |
105 | =cut
106 |
107 | #loads a hashfile representing a 2D Array ref blocks of data
108 | #can be used to load fonts or other graphical blocks
109 | sub loadGrf{
110 | my $file=shift;
111 | open my $grf,"<:utf8",$file or
112 | die "Unable to open file $file $!;\n" ;
113 | my $data="";
114 | $data.=$_ while(<$grf>);
115 | close $grf;
116 | my $g=eval($data) or die "unable to load external data from $file $!";;
117 | return $g;
118 | }
119 |
120 |
121 | =head3 C<$fontWrite($canvas,$font,$gridX,$gridY,$text);>
122 |
123 | Writes a C<$text> string using a loaded font into a particular grid
124 | location in a C<$canvas>
125 |
126 | =cut
127 |
128 | sub fontWrite{
129 | my ($canvas,$font,$gridX,$gridY,$text)=@_;
130 | for my $chPos(0..(length $text)-1){
131 | $canvas->blockBlit($font->{substr($text,$chPos, 1)},$gridX+4*$chPos, $gridY)
132 | }
133 | }
134 |
135 | 1;
136 |
--------------------------------------------------------------------------------
/lib/Term/Graille/Menu.pm:
--------------------------------------------------------------------------------
1 | =head1 NAME
2 | Term::Graille::Menu
3 |
4 | Modal hierarchical Menu system
5 |
6 | =head1 SYNOPSIS
7 |
8 | use Term::Graille::Interact;
9 | use Term::Graille::Menu ; # provides Term::Graille::Menu
10 |
11 | my $menu=new Term::Graille::Menu(
12 | menu=>[["File","New","Save","Load","Quit"],
13 | ["Edit","Clear",["Reformat","2x4","4x4"],["Scroll","left","right","up","down"]],
14 | "About"],
15 | redraw=>\&main::refreshScreen,
16 | dispatcher=>\&main::menuActions,
17 | );
18 |
19 |
20 | =head1 DESCRIPTION
21 |
22 | Developed to allow user interaction using a hierarchical menu in command line
23 | applications. The menu is activated using a key press, and navigated
24 | typically using arrow keys. It does not handle or capture the key presses
25 | directly, and in Graille is used in conjunction with Term::Graille::Interact
26 |
27 |
28 | =begin html
29 |
30 |
31 |
32 | =end html
33 |
34 |
35 | =head1 FUNCTIONS
36 |
37 | =cut
38 |
39 | package Term::Graille::Menu;
40 |
41 | use strict;use warnings;
42 | use Storable qw(dclone);
43 | use Term::Graille qw/colour printAt clearScreen/;
44 | use utf8;
45 |
46 | our $VERSION=0.11;
47 |
48 | =head3 Cnew(%params)>
49 |
50 | Creates a new $menu; params are
51 | C