artlab 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- artlab/__init__.py +3 -0
- artlab/__main__.py +4 -0
- artlab/cli.py +82 -0
- artlab/core.py +334 -0
- artlab-1.0.0.dist-info/METADATA +151 -0
- artlab-1.0.0.dist-info/RECORD +10 -0
- artlab-1.0.0.dist-info/WHEEL +5 -0
- artlab-1.0.0.dist-info/entry_points.txt +2 -0
- artlab-1.0.0.dist-info/licenses/LICENSE +21 -0
- artlab-1.0.0.dist-info/top_level.txt +1 -0
artlab/__init__.py
ADDED
artlab/__main__.py
ADDED
artlab/cli.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""artlab command-line interface."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import random
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from artlab import __version__
|
|
8
|
+
import artlab.core as core
|
|
9
|
+
from artlab.core import ART, list_pieces, show
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def build_parser():
|
|
13
|
+
p = argparse.ArgumentParser(
|
|
14
|
+
prog="artlab",
|
|
15
|
+
description="ASCII art in your terminal. Show bundled art, rainbow text, "
|
|
16
|
+
"or animate it. Zero dependencies.",
|
|
17
|
+
)
|
|
18
|
+
p.add_argument("piece", nargs="?", default=None,
|
|
19
|
+
help="name of a piece to show (see 'artlab list')")
|
|
20
|
+
p.add_argument("-t", "--text", default=None,
|
|
21
|
+
help="render text as block letters (big ASCII)")
|
|
22
|
+
p.add_argument("-l", "--list", action="store_true",
|
|
23
|
+
help="list all available pieces")
|
|
24
|
+
p.add_argument("-r", "--random", action="store_true",
|
|
25
|
+
help="show a random piece")
|
|
26
|
+
p.add_argument("-c", "--color", choices=["rainbow", "green", "cyan",
|
|
27
|
+
"magenta", "none"],
|
|
28
|
+
default="rainbow", help="color palette (default rainbow)")
|
|
29
|
+
p.add_argument("-w", "--width", type=int, default=None,
|
|
30
|
+
help="pad art to a fixed width")
|
|
31
|
+
p.add_argument("--no-center", action="store_true",
|
|
32
|
+
help="don't center the art")
|
|
33
|
+
p.add_argument("--no-color", action="store_true",
|
|
34
|
+
help="don't colorize output")
|
|
35
|
+
p.add_argument("-a", "--animate", action="store_true",
|
|
36
|
+
help="reveal the art with an animation")
|
|
37
|
+
p.add_argument("--version", action="version", version=f"artlab {__version__}")
|
|
38
|
+
return p
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main(argv=None):
|
|
42
|
+
args = build_parser().parse_args(argv)
|
|
43
|
+
|
|
44
|
+
if args.no_color:
|
|
45
|
+
core.NO_COLOR = True
|
|
46
|
+
|
|
47
|
+
if args.list:
|
|
48
|
+
for name in list_pieces():
|
|
49
|
+
print(f" {name}")
|
|
50
|
+
print(f"\n({len(ART)} pieces available)")
|
|
51
|
+
return 0
|
|
52
|
+
|
|
53
|
+
if args.text is not None:
|
|
54
|
+
pieces = args.text if args.text else None
|
|
55
|
+
show(text=args.text, color=args.color, width=args.width,
|
|
56
|
+
center=not args.no_center, animate=args.animate)
|
|
57
|
+
return 0
|
|
58
|
+
|
|
59
|
+
if args.random:
|
|
60
|
+
key, art = random.choice(list(ART.items()))
|
|
61
|
+
show(name=key, color=args.color, width=args.width,
|
|
62
|
+
center=not args.no_center, animate=args.animate)
|
|
63
|
+
return 0
|
|
64
|
+
|
|
65
|
+
if args.piece:
|
|
66
|
+
from artlab.core import pick_piece
|
|
67
|
+
if pick_piece(args.piece)[0] is None:
|
|
68
|
+
print(f"artlab: unknown piece '{args.piece}' (try 'artlab -l')",
|
|
69
|
+
file=sys.stderr)
|
|
70
|
+
return 1
|
|
71
|
+
show(name=args.piece, color=args.color, width=args.width,
|
|
72
|
+
center=not args.no_center, animate=args.animate)
|
|
73
|
+
return 0
|
|
74
|
+
|
|
75
|
+
# default: random piece
|
|
76
|
+
show(color=args.color, width=args.width, center=not args.no_center,
|
|
77
|
+
animate=args.animate)
|
|
78
|
+
return 0
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
sys.exit(main())
|
artlab/core.py
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"""artlab - ASCII art in your terminal.
|
|
2
|
+
|
|
3
|
+
Bundled ASCII art library, a zero-dependency block-letter text renderer,
|
|
4
|
+
color/rainbow helpers, and simple frame animation. Zero dependencies.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import colorsys
|
|
8
|
+
import random
|
|
9
|
+
import shutil
|
|
10
|
+
import sys
|
|
11
|
+
import time
|
|
12
|
+
|
|
13
|
+
# --------------------------------------------------------------------------
|
|
14
|
+
# Bundled ASCII art library
|
|
15
|
+
# --------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
ART = {
|
|
18
|
+
"robot": r""" .-""" + """""" + r""".
|
|
19
|
+
.'_________'.
|
|
20
|
+
/ _ _ \
|
|
21
|
+
| (o) (o) |
|
|
22
|
+
| ___ |
|
|
23
|
+
| \_______/ |
|
|
24
|
+
\ _ _ /
|
|
25
|
+
| [ o ] |
|
|
26
|
+
|___|_|___|
|
|
27
|
+
/ | | | \
|
|
28
|
+
| | | | |
|
|
29
|
+
~~~~~~~~~~~~~""",
|
|
30
|
+
"cat": r""" /\_/\
|
|
31
|
+
( o.o )
|
|
32
|
+
> ^ <
|
|
33
|
+
/ \
|
|
34
|
+
\_____/ meow""",
|
|
35
|
+
"dog": r""" / \__
|
|
36
|
+
( @\___
|
|
37
|
+
/ O
|
|
38
|
+
/ (_____/
|
|
39
|
+
/_____/ U
|
|
40
|
+
dog""",
|
|
41
|
+
"fox": r""" /\_/\
|
|
42
|
+
( o.o )
|
|
43
|
+
> ^ <
|
|
44
|
+
/ _ \
|
|
45
|
+
\__|__/ ring-ding-ding""",
|
|
46
|
+
"dragon": r""" __====-_ _-====___
|
|
47
|
+
_--^^^#####// \\#####^^^--_
|
|
48
|
+
-^##########/ ( ) \##########^-
|
|
49
|
+
############/ ( ) \############
|
|
50
|
+
###########/ ( ) \###########
|
|
51
|
+
#########/ ( ) ( ) \#########
|
|
52
|
+
########( ( ) ( ) )#######
|
|
53
|
+
#########\ ( ) /#########
|
|
54
|
+
#######\ ( ) /#######
|
|
55
|
+
####### \ ( ) /#######
|
|
56
|
+
####### \______/ #######
|
|
57
|
+
d r a g o n""",
|
|
58
|
+
"unicorn": r""" /
|
|
59
|
+
\ /
|
|
60
|
+
\ /____
|
|
61
|
+
( ____\_________
|
|
62
|
+
___/ \____\tttt___
|
|
63
|
+
/ \____( ' ' ) |\
|
|
64
|
+
( o' (o o) ) | )
|
|
65
|
+
\ \ (_,_)\___/ /
|
|
66
|
+
\ \____)___(____ )
|
|
67
|
+
\__(___________\__/
|
|
68
|
+
unicorn ~*~*~""",
|
|
69
|
+
"heart": r""" ****** ******
|
|
70
|
+
********* *********
|
|
71
|
+
*********** ***********
|
|
72
|
+
*********************
|
|
73
|
+
*******************
|
|
74
|
+
*****************
|
|
75
|
+
***************
|
|
76
|
+
*************
|
|
77
|
+
***********
|
|
78
|
+
*********
|
|
79
|
+
*******
|
|
80
|
+
*****
|
|
81
|
+
***
|
|
82
|
+
*""",
|
|
83
|
+
"yoda": r""" ..,
|
|
84
|
+
( o o )
|
|
85
|
+
( > < )
|
|
86
|
+
/A A\
|
|
87
|
+
|+. _ .+|
|
|
88
|
+
\_|_|_/
|
|
89
|
+
v v
|
|
90
|
+
use the source""",
|
|
91
|
+
"octopus": r""" _
|
|
92
|
+
.-( )-.
|
|
93
|
+
/ _ _ \
|
|
94
|
+
( (o)(o)(o) )
|
|
95
|
+
\ \___/ /
|
|
96
|
+
\_______/
|
|
97
|
+
| |
|
|
98
|
+
/| |\
|
|
99
|
+
/ |_____| \
|
|
100
|
+
~~~ ~~~
|
|
101
|
+
octopus""",
|
|
102
|
+
"ghost": r""" .-~~~~-.
|
|
103
|
+
/ ____ \
|
|
104
|
+
| / \ |
|
|
105
|
+
| | o o | |
|
|
106
|
+
| \____/ |
|
|
107
|
+
\ ____ /
|
|
108
|
+
| | | |
|
|
109
|
+
\|__|/
|
|
110
|
+
/ / \ \
|
|
111
|
+
~~ ~~
|
|
112
|
+
boo!""",
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# --------------------------------------------------------------------------
|
|
116
|
+
# Minimal block-letter text renderer (zero-dependency figlet-style)
|
|
117
|
+
# --------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
_FONT = {}
|
|
120
|
+
|
|
121
|
+
_Q = [" ##### ", "## ##", "## ##", "## ##", " ##### "]
|
|
122
|
+
_W = ["## ##", "## ##", "## ## ##", "#### ###", "## ##"]
|
|
123
|
+
_H = ["## ##", "## ##", "#######", "## ##", "## ##"]
|
|
124
|
+
_A = [" ##### ", "## ##", "#######", "## ##", "## ##"]
|
|
125
|
+
_R = [" ##### ", "## ##", "##### ", "## ## ", "## ##"]
|
|
126
|
+
_T = ["#######", " # ", " # ", " # ", " # "]
|
|
127
|
+
_P = ["###### ", "## ##", "###### ", "## ", "## "]
|
|
128
|
+
_L = ["## ", "## ", "## ", "## ", "#######"]
|
|
129
|
+
_I = ["###", " # ", " # ", " # ", "###"]
|
|
130
|
+
_E = ["#######", "## ", "##### ", "## ", "#######"]
|
|
131
|
+
_S = [" ######", "## ", " ##### ", " ##", "###### "]
|
|
132
|
+
_O = [" ##### ", "## ##", "## ##", "## ##", " ##### "]
|
|
133
|
+
_U = ["## ##", "## ##", "## ##", "## ##", " ##### "]
|
|
134
|
+
_N = ["## #", "### #", "## # #", "## # #", "## ##"]
|
|
135
|
+
_Y = ["## ##", "## ##", " ##### ", " ## ", " ## "]
|
|
136
|
+
_G = [" ##### ", "## ", "## ###", "## ##", " ##### "]
|
|
137
|
+
_D = ["###### ", "## ##", "## ##", "## ##", "###### "]
|
|
138
|
+
_K = ["## ## ", "## ## ", "#### ", "## ## ", "## ## "]
|
|
139
|
+
_X = ["## ##", " ## ## ", " ### ", " ## ## ", "## ##"]
|
|
140
|
+
_Z = ["#######", " ## ", " ## ", " ## ", "#######"]
|
|
141
|
+
_V = ["## ##", "## ##", "## ##", " ## ## ", " ### "]
|
|
142
|
+
_J = [" ###", " ##", " ##", "## ##", " ##### "]
|
|
143
|
+
_M = ["## ## ##", "### ### ##", "## # # ##", "## ##", "## ##"]
|
|
144
|
+
_B = ["###### ", "## ##", "###### ", "## ##", "###### "]
|
|
145
|
+
_F = ["#######", "## ", "##### ", "## ", "## "]
|
|
146
|
+
_C = [" ##### ", "## ", "## ", "## ", " ##### "]
|
|
147
|
+
|
|
148
|
+
_FONT = {
|
|
149
|
+
"0": _O, "1": [" ## ", " #### ", " ## ", " ## ", " ## "],
|
|
150
|
+
"2": [" #### ", " ##", " #### ", "## ", "##### "],
|
|
151
|
+
"3": [" #### ", " ##", " #### ", " ##", " #### "],
|
|
152
|
+
"4": ["## ##", "## ##", "#######", " ##", " ##"],
|
|
153
|
+
"5": ["#######", "## ", "##### ", " ##", "##### "],
|
|
154
|
+
"6": [" ##### ", "## ", "###### ", "## ##", " ##### "],
|
|
155
|
+
"7": ["#######", " ## ", " ## ", " ## ", " ## "],
|
|
156
|
+
"8": [" ##### ", "## ##", " ##### ", "## ##", " ##### "],
|
|
157
|
+
"9": [" ##### ", "## ##", " #######", " ##", " ##### "],
|
|
158
|
+
".": [" ", " ", " ", " ", " ## "],
|
|
159
|
+
" ": [" ", " ", " ", " ", " "],
|
|
160
|
+
"!": ["###", "###", "###", " ", " # "],
|
|
161
|
+
"?": ["#### ", " ##", " ## ", " ", " # "],
|
|
162
|
+
"-": [" ", " ", "#####", " ", " "],
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Assign letters to their glyphs
|
|
166
|
+
for _char, _glyph in [
|
|
167
|
+
("A", _A), ("B", _B), ("C", _C), ("D", _D), ("E", _E), ("F", _F),
|
|
168
|
+
("G", _G), ("H", _H), ("I", _I), ("J", _J), ("K", _K), ("L", _L),
|
|
169
|
+
("M", _M), ("N", _N), ("O", _O), ("P", _P), ("Q", _Q), ("R", _R),
|
|
170
|
+
("S", _S), ("T", _T), ("U", _U), ("V", _V), ("W", _W), ("X", _X),
|
|
171
|
+
("Y", _Y), ("Z", _Z),
|
|
172
|
+
]:
|
|
173
|
+
_FONT[_char] = _glyph
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def render_text(text, font="block"):
|
|
177
|
+
"""Render text as block letters (zero dependencies). Returns list of lines."""
|
|
178
|
+
lines = ["" for _ in range(5)]
|
|
179
|
+
for ch in text.upper():
|
|
180
|
+
glyph = _FONT.get(ch, _FONT[" "])
|
|
181
|
+
for i in range(5):
|
|
182
|
+
lines[i] += glyph[i] + " "
|
|
183
|
+
return [line.rstrip() for line in lines]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# --------------------------------------------------------------------------
|
|
187
|
+
# Color helpers
|
|
188
|
+
# --------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
NO_COLOR = False
|
|
191
|
+
FORCE_COLOR = False
|
|
192
|
+
|
|
193
|
+
RESET = "\033[0m"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _should_colorize(palette, out):
|
|
197
|
+
if NO_COLOR or palette[0] == "":
|
|
198
|
+
return False
|
|
199
|
+
if FORCE_COLOR:
|
|
200
|
+
return True
|
|
201
|
+
return bool(getattr(out, "isatty", lambda: False)())
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _rainbow_codes(n):
|
|
205
|
+
codes = []
|
|
206
|
+
for i in range(n):
|
|
207
|
+
h = i / max(1, n) if n > 1 else 0.0
|
|
208
|
+
r, g, b = colorsys.hsv_to_rgb(h, 1.0, 1.0)
|
|
209
|
+
codes.append(f"\033[38;2;{int(r*255)};{int(g*255)};{int(b*255)}m")
|
|
210
|
+
return codes
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _color_lines(lines, palette, cycle=False, out=None):
|
|
214
|
+
if not _should_colorize(palette, out):
|
|
215
|
+
return lines
|
|
216
|
+
res = []
|
|
217
|
+
for idx, line in enumerate(lines):
|
|
218
|
+
code = palette[idx % len(palette)] if cycle else palette[0]
|
|
219
|
+
res.append(code + line + RESET)
|
|
220
|
+
return res
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
RAINBOW_PALETTE = [
|
|
224
|
+
"\033[38;5;196m", "\033[38;5;208m", "\033[38;5;226m", "\033[38;5;46m",
|
|
225
|
+
"\033[38;5;39m", "\033[38;5;93m", "\033[38;5;201m",
|
|
226
|
+
]
|
|
227
|
+
GREEN = "\033[38;5;82m"
|
|
228
|
+
CYAN = "\033[38;5;45m"
|
|
229
|
+
MAGENTA = "\033[38;5;201m"
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _palette(kind):
|
|
233
|
+
return {
|
|
234
|
+
"rainbow": RAINBOW_PALETTE,
|
|
235
|
+
"green": [GREEN],
|
|
236
|
+
"cyan": [CYAN],
|
|
237
|
+
"magenta": [MAGENTA],
|
|
238
|
+
"none": [""],
|
|
239
|
+
}.get(kind, RAINBOW_PALETTE)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# --------------------------------------------------------------------------
|
|
243
|
+
# Art selection and display
|
|
244
|
+
# --------------------------------------------------------------------------
|
|
245
|
+
|
|
246
|
+
def list_pieces():
|
|
247
|
+
return sorted(ART.keys())
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def pick_piece(name=None):
|
|
251
|
+
if name:
|
|
252
|
+
name = name.lower()
|
|
253
|
+
if name in ART:
|
|
254
|
+
return name, ART[name]
|
|
255
|
+
for key in ART:
|
|
256
|
+
if key.startswith(name):
|
|
257
|
+
return key, ART[key]
|
|
258
|
+
return None, None
|
|
259
|
+
return None, None
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def show(name=None, text=None, color="rainbow", width=None, center=True,
|
|
263
|
+
animate=False, frames=20, delay=0.06, out=None, return_lines=False):
|
|
264
|
+
"""Render and (optionally) print art. Returns the rendered lines."""
|
|
265
|
+
if out is None:
|
|
266
|
+
out = sys.stdout
|
|
267
|
+
|
|
268
|
+
def build():
|
|
269
|
+
if text is not None:
|
|
270
|
+
return render_text(text)
|
|
271
|
+
if name:
|
|
272
|
+
key, art = pick_piece(name)
|
|
273
|
+
if not art:
|
|
274
|
+
return None
|
|
275
|
+
return art.splitlines()
|
|
276
|
+
key, art = random.choice(list(ART.items()))
|
|
277
|
+
return art.splitlines()
|
|
278
|
+
|
|
279
|
+
lines = build()
|
|
280
|
+
if lines is None:
|
|
281
|
+
return None
|
|
282
|
+
if return_lines:
|
|
283
|
+
return lines
|
|
284
|
+
|
|
285
|
+
lines = _fit_width(lines, width, center=center)
|
|
286
|
+
lines = _color_lines(lines, _palette(color), cycle=(color == "rainbow"), out=out)
|
|
287
|
+
if animate:
|
|
288
|
+
_animate(lines, out, frames, delay)
|
|
289
|
+
else:
|
|
290
|
+
for line in lines:
|
|
291
|
+
out.write(line + "\n")
|
|
292
|
+
out.flush()
|
|
293
|
+
return lines
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _fit_width(lines, width, center=True):
|
|
297
|
+
if not width:
|
|
298
|
+
maxlen = max((len(line) for line in lines), default=0)
|
|
299
|
+
width = maxlen
|
|
300
|
+
return [_center(line, width) if center else line for line in lines]
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _center(line, width):
|
|
304
|
+
pad = width - len(line)
|
|
305
|
+
if pad <= 0:
|
|
306
|
+
return line
|
|
307
|
+
left = pad // 2
|
|
308
|
+
return " " * left + line
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _animate(lines, out, frames, delay):
|
|
312
|
+
terminal = shutil.get_terminal_size((80, 24)).lines
|
|
313
|
+
height = len(lines)
|
|
314
|
+
for frame in range(frames):
|
|
315
|
+
upto = int((frame + 1) / frames * height)
|
|
316
|
+
view = lines[max(0, upto - min(terminal, height)) : upto]
|
|
317
|
+
out.write("\033[H\033[J")
|
|
318
|
+
for line in view:
|
|
319
|
+
out.write(line + "\n")
|
|
320
|
+
out.flush()
|
|
321
|
+
time.sleep(delay)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def random_piece():
|
|
325
|
+
name, art = random.choice(list(ART.items()))
|
|
326
|
+
return name, art
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def pieces_count():
|
|
330
|
+
return len(ART)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def main_extras():
|
|
334
|
+
return None
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: artlab
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: ASCII art in your terminal. Zero dependencies.
|
|
5
|
+
Author: dsk-dev-ai
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dsk-dev-ai/artlab
|
|
8
|
+
Project-URL: Source, https://github.com/dsk-dev-ai/artlab
|
|
9
|
+
Project-URL: Issues, https://github.com/dsk-dev-ai/artlab/issues
|
|
10
|
+
Project-URL: Funding, https://github.com/sponsors/dsk-dev-ai
|
|
11
|
+
Keywords: ascii,art,terminal,cli,fun,text,rainbow,ascii-art
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Artistic Software
|
|
24
|
+
Classifier: Topic :: Terminals
|
|
25
|
+
Classifier: Topic :: Utilities
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
<div align="center">
|
|
32
|
+
|
|
33
|
+
# 🎨 artlab
|
|
34
|
+
|
|
35
|
+
**ASCII art in your terminal.**
|
|
36
|
+
|
|
37
|
+
Bundled retro art, big block-letter text, rainbow colors, and animation.
|
|
38
|
+
Zero dependencies. Works in Python 3.8+.
|
|
39
|
+
|
|
40
|
+
[](https://pypi.org/project/artlab/)
|
|
41
|
+
[](#)
|
|
42
|
+
[](#)
|
|
43
|
+
[](https://github.com/dsk-dev-ai/artlab/pkgs/container/artlab)
|
|
44
|
+
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Why artlab?
|
|
50
|
+
|
|
51
|
+
Because the terminal deserves a little personality.
|
|
52
|
+
|
|
53
|
+
- **Bundled ASCII art** — robots, cats, dragons, unicorns, yoda, octopuses, hearts and more.
|
|
54
|
+
- **Block-letter text** — print any word big, `figlet`-style, with zero dependencies.
|
|
55
|
+
- **Rainbow & colors** — 256-color palettes, or dims down for your pipelines.
|
|
56
|
+
- **Animation** — reveal art with a slick frame-by-frame intro.
|
|
57
|
+
- **Zero dependencies** — pure Python stdlib. No install drama.
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install artlab
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or run without installing:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pipx run artlab --help
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Via Docker:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
docker run --rm ghcr.io/dsk-dev-ai/artlab --help
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Usage
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Show a random piece
|
|
81
|
+
artlab
|
|
82
|
+
|
|
83
|
+
# Show a specific piece
|
|
84
|
+
artlab robot
|
|
85
|
+
artlab cat
|
|
86
|
+
artlab dragon
|
|
87
|
+
|
|
88
|
+
# List everything
|
|
89
|
+
artlab -l
|
|
90
|
+
|
|
91
|
+
# Print big block text
|
|
92
|
+
artlab --text "SHIP IT"
|
|
93
|
+
artlab -t "artlab" -c cyan
|
|
94
|
+
|
|
95
|
+
# Force a palette
|
|
96
|
+
artlab robot -c green
|
|
97
|
+
artlab dragon -c magenta
|
|
98
|
+
|
|
99
|
+
# Animate the reveal
|
|
100
|
+
artlab unicorn -a
|
|
101
|
+
|
|
102
|
+
# No color (for scripts / piping)
|
|
103
|
+
artlab robot --no-color
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Options
|
|
107
|
+
|
|
108
|
+
| Flag | Description |
|
|
109
|
+
|------|-------------|
|
|
110
|
+
| `-l, --list` | List all available pieces |
|
|
111
|
+
| `-r, --random` | Show a random piece |
|
|
112
|
+
| `-t, --text TEXT` | Render text as big block letters |
|
|
113
|
+
| `-c, --color` | Palette: `rainbow`, `green`, `cyan`, `magenta`, `none` |
|
|
114
|
+
| `-w, --width N` | Pad art to a fixed width |
|
|
115
|
+
| `--no-center` | Don't center the art |
|
|
116
|
+
| `-a, --animate` | Reveal the art with an animation |
|
|
117
|
+
| `--no-color` | Disable color output |
|
|
118
|
+
| `--version` | Print version |
|
|
119
|
+
|
|
120
|
+
## Gallery
|
|
121
|
+
|
|
122
|
+
Run `artlab` to see a random piece, or `artlab -l` to browse the full library.
|
|
123
|
+
Everything is bundled — no API, no network, no nonsense.
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
/\_/\
|
|
127
|
+
( o.o )
|
|
128
|
+
> ^ <
|
|
129
|
+
/ \
|
|
130
|
+
\_____/ meow
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Tests
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
python -m pytest
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Tested on Python 3.8–3.12 via GitHub Actions.
|
|
140
|
+
|
|
141
|
+
## Sponsor
|
|
142
|
+
|
|
143
|
+
Like `artlab`? Keep the terminal artsy for free by [becoming a sponsor](https://github.com/sponsors/dsk-dev-ai) on GitHub 💜.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
<div align="center">
|
|
148
|
+
|
|
149
|
+
**artlab** · because the terminal deserves art.
|
|
150
|
+
|
|
151
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
artlab/__init__.py,sha256=WbUsMzYEirGLjM6yxwN34pqhNYAjQ0HjsViR6wH1mGE,66
|
|
2
|
+
artlab/__main__.py,sha256=zJBxAKu18wg4b_wE0GaiRUplpNLEVZTEBNlz2JUtdwo,67
|
|
3
|
+
artlab/cli.py,sha256=OBygYnY6tXvSkjfD2IhLElcoNS6CFyFl3haTiAXcPUg,2901
|
|
4
|
+
artlab/core.py,sha256=KI6rCZcOHbw_6NmFmg9A5AJAZ9_d85POoEB425ZwHt4,9612
|
|
5
|
+
artlab-1.0.0.dist-info/licenses/LICENSE,sha256=EAxljeOlydi0CA5dhf2z72wEjAtq_9Ig44QyLQ7XWLM,1067
|
|
6
|
+
artlab-1.0.0.dist-info/METADATA,sha256=G6HgvfUPwans2seRs2UW_Lo06Hgg77-_L25967xLFks,3884
|
|
7
|
+
artlab-1.0.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
8
|
+
artlab-1.0.0.dist-info/entry_points.txt,sha256=TADcrd5_LCLJQFJeNL_eI8gKJ5nyLfe1KmJ-yOODgfU,43
|
|
9
|
+
artlab-1.0.0.dist-info/top_level.txt,sha256=oO456VQwkMHu8SEyupOvEwYdXxhHJ-bjn4o_mkxye-k,7
|
|
10
|
+
artlab-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsk-dev-ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
artlab
|