Desktop HTML on a Diet
TL;DR: Just launch a Chromium, it's probably already installed.
Recently a friend talked about making an ANSI banner for his shell's MOTD and asked if I knew the best tool. I did not, but I had messed around with automatically converting images to Unicode half blocks and took this as a sign to turn this code into a usable application.
I decided to use sharp, a Node.js-based image manipulation library. Because sharp has not yet been built for WASM, this was also a perfect opportunity to pursue ideas regarding desktop HTML applications without the gigantic Electron, which bundles both Chromium and Node.js with each application.
Instead, I assume two external dependencies: a Chromium-based browser and Node.js. I launch the Chromium with a shell script, passing in these command line switches:
--app=<url>- This launches the browser window without any browser UI, just a window frame. This is how the "Create application shortcut" feature works.
--user-data-dir=<dir>- This isolates the application data from the user's normal browser windows.
--load-extension=<dir>- This automatically loads an unpacked extension. This extension starts the backend Node.js process and bridges communications between it and the browser app.
--allow-file-access-from-files- Since the launched URL is just an HTML file on the local filesystem, this switch allows the app to use the XMLHttpRequest API to read local files.
I've recently accepted a position specializing in React so chose it to keep my skills sharp. For the user interface I tried a few newer component frameworks and decided to go with Mantine, which has been very nice to work with. I've picked Zustand and Immer for state management and am building the app with Vite.
fftext allows you to open, paste, or drop local images and convert them to ANSI-escaped Unicode half-block text. It includes a bunch of sliders to tweak the image so it works nicely with the chosen palette. The image above is using the 256-color mode, but you can also pick one of three popular 16-color palettes, or even 24-bit ANSI colors for supported terminals. It will also convert to IRC-escaped in 16 or 99 colors.
It is currently alpha-quality but most features can be used (Linux-only). Source code is at Github. The resulting build is a 141K download and installs about 20MB of dependencies - still much smaller than an Electron app would be.
I am tinkering on a reusable framework for building cross-platform apps in this way called Calory. A test app, a simple text editor, is a tiny 59K download. Currently the launcher is written in C++ (fun to play with after 20+ years) but I will revert to shell scripts to reduce the resulting package sizes even more. On Windows, both CMD and PowerShell scripts open a terminal window, so I will use VBScript 😆.
Calory will be backend-agnostic, so anything that can communicate with Chrome via the Native Messaging protocol can be used - Node.js, Bun, C++, etc. I've since found a similar project which has the same perk - NeutralinoJS. This uses a WebSocket and web server to achieve the same result. By sticking with Native Messaging in Calory, however, I aim to have the tiniest possible packages.