Commit e0aadec964

e0aadec964e4faa14fcad919ab343c08e05512d4

parent: cd22a15611

Verified · cmc

cmc <hello@cleberg.net> · 2026-08-20 16:56 UTC

fix: update glyphs, encoding, commands, and add content to How It Works section

Layout: unified · split

content/blog/2026-08-20-nfogen.org +150 −51
@@ -18,51 +18,56 @@ credits, installation instructions, BBS/contact info, greetz/notes, etc.
18For example, here's the =bonzai.nfo= file for a patched save game for Lemmings 18For example, here's the =bonzai.nfo= file for a patched save game for Lemmings
19III, with credits to those involved and instructions to get in touch. 19III, with credits to those involved and instructions to get in touch.
20 20
21/Note: The [[http://www.textfiles.com/piracy/NFO/bonzai.nfo][original file]] on textfiles.com contains CP437 bytes decoded as
22Cyrillic, so I converted this example correctly to CP437. If you view the online
23version, you'll notice that the box drawing and group logo are incomprehensible,
24which proves my point later on in the CP437 section./
25
21#+begin_src nfo 26#+begin_src nfo
22 К К 27 ║ ║
23 28
24 лллллК К 29 █████║ ║
25 лллллК К 30 █████║ ║
26 лллллпллл лллллпллл лллллпллл лллллпллл лллллпллл ппппп 31 █████▀███ █████▀███ █████▀███ █████▀███ █████▀███ ▀▀▀▀▀
27 лллллКлллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл ллллл 32 █████║████ █████ ████ █████ ████ █████ ████ █████ ████ █████
28 лллллКлллл ллллл лллл ллллл лллл ммммммлллл лллллмлллл лллллл 33 █████║████ █████ ████ █████ ████ ▄▄▄▄▄▄████ █████▄████ ██████
29 лллллКлллл ллллл лллл ллллл лллл ллллл мммм ллллл лллл лллллл 34 █████║████ █████ ████ █████ ████ █████ ▄▄▄▄ █████ ████ ██████
30 ллллл лллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл 35 █████ ████ █████ ████ █████ ████ █████ ████ █████ ████ ██████
31 лллллКлллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл 36 █████║████ █████ ████ █████ ████ █████ ████ █████ ████ ██████
32 лллллКлллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл 37 █████║████ █████ ████ █████ ████ █████ ████ █████ ████ ██████
33 ллллл лллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл 38 █████ ████ █████ ████ █████ ████ █████ ████ █████ ████ ██████
34 пппппппппп пппппппппп ппппп пппп пппппппппп ппппп пппп пппппп 39 ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀
35 К жФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФЗ К 40 ║ ╓────────────────────────────────────────╖ ║
36 К ў BONZAi Ф EVERYTHiNG BUT FRiENDSHiP ў К 41 ║ ■ BONZAi ─ EVERYTHiNG BUT FRiENDSHiP ■ ║
37 К гФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФН К 42 ║ ╙────────────────────────────────────────╜ ║
38 R E L E A S E D : 43 R E L E A S E D :
39 К К 44 ║ ║
40 К 9O BYTES SAVE GAME PATCHER FOR LEMMiNGS III К 45 ║ 9O BYTES SAVE GAME PATCHER FOR LEMMiNGS III ║
41 46
42 К FiLENAME .............. : ........... BNZ-L3T.ZiP К 47 ║ FiLENAME .............. : ........... BNZ-L3T.ZiP ║
43 К TYPE .................. : ............... TRAiNER К 48 ║ TYPE .................. : ............... TRAiNER ║
44 К COMPANY ............... : ............. PSYGNOSiS К 49 ║ COMPANY ............... : ............. PSYGNOSiS ║
45 К CODER .. .............. : ................ SCAMPY К 50 ║ CODER .. .............. : ................ SCAMPY ║
46 К PACKAGER .............. : ................ SCAMPY К 51 ║ PACKAGER .............. : ................ SCAMPY ║
47 К DATE AT RELEASiNG ..... : ............ 11-27-1994 К 52 ║ DATE AT RELEASiNG ..... : ............ 11-27-1994 ║
48 К TiME AT RELEASiNG ..... : .............. 15:OO PM К 53 ║ TiME AT RELEASiNG ..... : .............. 15:OO PM ║
49 К RELEASE NOTES : ..................... READ BELOW! К 54 ║ RELEASE NOTES : ..................... READ BELOW! ║
50 К К 55 ║ ║
51 К !!!*!!! IMPORTANT !!!*!!! К 56 ║ !!!*!!! IMPORTANT !!!*!!! ║
52 К К 57 ║ ║
53 К NiCE PATCHER FOR A NiCE GAME - THiS PATCHER WAS К 58 ║ NiCE PATCHER FOR A NiCE GAME - THiS PATCHER WAS ║
54 К KINDA DiFFiCULT BECAUSE OF THE MANY BYTES TO BE К 59 ║ KINDA DiFFiCULT BECAUSE OF THE MANY BYTES TO BE ║
55 К PATCHED. BUT PROBLEMS WiTH PATCHiNG TiME AND К 60 ║ PATCHED. BUT PROBLEMS WiTH PATCHiNG TiME AND ║
56 К FiLE LENGTH HAVE BEEN SOLVED. К 61 ║ FiLE LENGTH HAVE BEEN SOLVED. ║
57 К К 62 ║ ║
58 К ENJOY PLAYiN' -SCAMPY! К 63 ║ ENJOY PLAYiN' -SCAMPY! ║
59 К К 64 ║ ║
60 К К 65 ║ ║
61 К MEMBERS OF BONZAi ARE . : К 66 ║ MEMBERS OF BONZAi ARE . : ║
62 К MOTiV8- SCAMPY- SUM-1- DEViL К 67 ║ MOTiV8- SCAMPY- SUM-1- DEViL ║
63 К К 68 ║ ║
64 К BULLETiN BOARD SYSTEMS : К 69 ║ BULLETiN BOARD SYSTEMS : ║
65Э Э ЭЭ ЭЭЭМ NONE! SEARCHiNG! ШЭЭЭ ЭЭ Э Э 70═ ═ ══ ═══╝ NONE! SEARCHiNG! ╚═══ ══ ═ ═
66 71
67 GREETiNGS TO: 72 GREETiNGS TO:
68 TOXiC HYBRiD PENTAGRAM PARADOX THHG G.T.A TRSI 73 TOXiC HYBRiD PENTAGRAM PARADOX THHG G.T.A TRSI
@@ -72,7 +77,7 @@ III, with credits to those involved and instructions to get in touch.
72 CURRENTLY WE ARE SEARCHiNG FOR ALL KiND OF MEMBERS.. LiKE TRADERS 77 CURRENTLY WE ARE SEARCHiNG FOR ALL KiND OF MEMBERS.. LiKE TRADERS
73 SUPPLiERS.. SYSOPS.. ETC. 78 SUPPLiERS.. SYSOPS.. ETC.
74 79
75Э Э ЭЭ ЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭ ЭЭ Э Э 80═ ═ ══ ══════════════════════════════════════════════════════════ ══ ═ ═
76#+end_src 81#+end_src
77 82
78If you want to browse an archive of NFO files, head over to [[http://www.textfiles.com/piracy/NFO/][textfiles]]. 83If you want to browse an archive of NFO files, head over to [[http://www.textfiles.com/piracy/NFO/][textfiles]].
@@ -95,7 +100,7 @@ use code blocks, like I did above).
95One such character set was often used for NFO files: IBM's [[https://en.wikipedia.org/wiki/Code_page_437][CP437]] character set, 100One such character set was often used for NFO files: IBM's [[https://en.wikipedia.org/wiki/Code_page_437][CP437]] character set,
96released with the 1981 IBM PC. This set was popular because each character could 101released with the 1981 IBM PC. This set was popular because each character could
97be typed with an alt code in DOS, even if they were not on the user's keyboard. 102be typed with an alt code in DOS, even if they were not on the user's keyboard.
98E.g., =Alt + 2665= would result in the following character: =♥=. 103E.g., =Alt + 3= would result in the following character: =♥=.
99 104
100* Introducing: nfogen 105* Introducing: nfogen
101 106
@@ -104,7 +109,8 @@ recently. As part of this, I started using NFO files for my git repos under my
104new org and wanted a tool that could help me accelerate the generation of these 109new org and wanted a tool that could help me accelerate the generation of these
105files. 110files.
106 111
107Introducing [[https://github.com/krazywarez/nfogen][nfogen]], a small Python utility that can generate NFO files for you based on: 112Introducing [[https://github.com/krazywarez/nfogen][nfogen]], a small Python utility that can generate NFO files for you
113based on:
108- templates 114- templates
109- profiles 115- profiles
110- configuration files 116- configuration files
@@ -172,7 +178,7 @@ generated by nfogen: nfogen.py -c nfogen.toml
172Next, I ran the following command, which produced the NFO file below: 178Next, I ran the following command, which produced the NFO file below:
173 179
174#+begin_src shell 180#+begin_src shell
175nfogen.py -c nfogen.toml -p -o README.nfo 181nfogen.py -c nfogen.toml -o README.nfo
176#+end_src 182#+end_src
177 183
178#+begin_src nfo 184#+begin_src nfo
@@ -230,12 +236,11 @@ For more examples, browse the [[https://github.com/krazywarez/nfogen/tree/main/e
230* Usage 236* Usage
231** Installation 237** Installation
232 238
233The fastest installation method is to clone the repo and use the Python file 239The fastest installation method is to fetch and use the Python file directly:
234directly:
235 240
236#+begin_src shell 241#+begin_src shell
237git clone https://github.com/krazywarez/nfogen.git && cd nfogen 242curl -O https://raw.githubusercontent.com/krazywarez/nfogen/main/nfogen.py
238nfogen.py -i 243python3 nfogen.py -i
239#+end_src 244#+end_src
240 245
241** Generating a File 246** Generating a File
@@ -262,9 +267,103 @@ nfogen itself works by parsing the various inputs, determining a style to use
262for the box-drawing/character sets, and rendering the characters individually by 267for the box-drawing/character sets, and rendering the characters individually by
263rows and columns. 268rows and columns.
264 269
270** Width
271
272The first issue I ran into was determining the width to use. I settled on 79
273characters, with border characters at both ends, because X. This means that my
274script needs to perform some math to calculate wrapping, padding, and centering
275of text throughout.
276
277The math is relatively simple because CP437 is single-byte and single-width,
278which means I can write functions that depend on that one-to-one correlation
279to calculate the spacing properly.
280
281=_Canvas.__init__= defines a few key variables for width:
282
283#+begin_src python
284self.width = width
285self.inner = width - 4 # single-column content width
286self.cl = (width - 7) // 2 # left panel content width
287self.cr = (width - 7) - self.cl
288self.rfill = width - self.cl - 5
289#+end_src
290
291At a width of 79 characters, this breaks down into:
292
293| Variable | Value | What it covers |
294|------------+-------+---------------------------------------------------------|
295| =self.width= | 79 | Total line width, borders included |
296| =self.inner= | 75 | Single-column content, minus two verticals and two pads |
297| =self.cl= | 36 | Left panel content width |
298| =self.cr= | 36 | Right panel content, taking the remainder |
299| =self.rfill= | 38 | Rule segment right of the joint, =cr= plus its two pads |
300
301These combine into a cohesive 79-chararacter-width NFO file with consistent
302padding and alignment.
303
304** Character Sets
305
306=nfogen= currently supports two different character sets as outputs: UTF-8 and
307CP437. For example, there are =╔ ═ ║= characters in the UTF-8 example, but a real
308CP437 file contains the single bytes =0xC9 0xCD 0xBA=.
309
310However, this doesn't really change the core generation of the NFO file. The
311file itself is charset-independent and the charset only comes into play during
312the final encode of the file.
313
314Referring back to the =bonzai.nfo= file above, it was decoded improperly as
315ISO-8859-5, which resulted in Cyrillic characters instead of the proper charset.
316Defining an appropriate charset and encoding/decoding is critical to ensuring
317the longevity of NFO files.
318
319** Banner Generator
320
321The banner generator is a function by itself, which renders independent from the
322rest of the file and separate from the box geometry. This function defines a set
323of glyphs, takes an input text string from the user, and maps each character to
324its glyph. The result is rendered above the box and is centered, so it does not
325depend on the math applied to the canvas.
326
327If an explicity art file is defined, this generator does not run.
328
329#+begin_src python
330# A compact 5-row block font for the banner generator. Each glyph is five
331# rows joined by "/". Uppercase letters, digits, space, and [<35;44;2Ma few symbols.
332_FONT = {
333 "A": " ### /# #/#####/# #/# #", "B": "#### /# #/#### /# #/#### ",
334 "C": " ####/# /# /# / ####", "D": "#### /# #/# #/# #/#### ",
335 # ... through Z, 0-9, space, -, ., !, :
336}
337
338
339def banner(text: str) -> str:
340 """Render text as a 5-row ASCII banner using the built-in block font."""
341 rows = ["", "", "", "", ""]
342 for ch in text.upper():
343 glyph = _FONT.get(ch, _FONT[" "]).split("/")
344 for i in range(5):
345 rows[i] += glyph[i] + " "
346 return "\n".join(r.rstrip() for r in rows)
347#+end_src
348
349** Resolution Order
350
351Finally, I defined a specific order to the inputs. As stated in the README, the
352order of importance is: =template < profile < config file < CLI flags < prompts=.
353
354This was an opinionated design choice, as I felt that if you were to create a
355template, that should take precedence above all. Then, profiles and
356configurations are additional preconfigured files that require effort to create
357and maintain, which earns them the next spots. Finally, the script falls back to
358CLI arguments, if supplied, and then interactive prompt mode if nothing else
359exists.
360
265* The Future 361* The Future
266 362
267I'd love to build this tool out to support more character sets, pre-built 363I'd love to build this tool out to support more character sets, pre-built
268libraries for ASCII art and table layouts, and more customization options. 364libraries for ASCII art and table layouts, and more customization options.
269 365
366For now, the tool works and is sufficient for my personal use cases, so I'm
367content with it.
368
270If you're interested in helping, feel free to reach out! 369If you're interested in helping, feel free to reach out!