

Discover more from hrbrmstr's Daily Drop
I'm not sure Tim Berners-Lee truly envisioned where we'd be right now when it comes to what can be done with a modern web browser. No longer just a mere windowed slave to Times New Roman text and cat pictures, browsers are nigh complete, mini-operating systems.
Today, we're going to abuse this tool we all use every day in two distinct ways, and also cover the reason for including the “smu” utility in yesterday's Drop.
seashells
While I no longer use the Warp browser out of privacy concerns, one feature I really liked about it was the ability to share output from Warp terminals with others just by giving them a URL. Thankfully, Warp devs weren't the only ones to figure out that folks might like to share content this way. In fact, there is a decent-sized sub-category of tooling that fits into the “share terminal output over the web” genre.
One such tool is seashells (GH). With it, you can “pipe output from command-line programs to the web in real-time, even without installing any new software on your machine”. A good use case for Seashells is if you want to remotely monitor any long-running process — such as training large language models. Another might be turning a CLI TUI into a read-only web application.
For example, you can monitor your system processes remotely via:
top | nc seashells.io 1337
Or, you can monitor your [Caddy] access log with jq
formatting via:
tail -f thd-access.log | \
jq --unbuffered | \
nc seashells.io 1337
After each command, you get a URL you can hit or share with others.
It uses xterm.js under the hood to handle the browser display component, and does a bit of magic to persist (temporarily) the output for your viewing pleasure.
We're kind of abusing the generosity of the developer when we take advantage of the seashells.io
service (more so when we over-use it). We can be a bit nicer to them, and also gain some control if we run our own instance. This is doable thanks to seashells-server.
Now, the build and run instructions do work, but you'll have to do a bunch of the wiring on your own to get it going.
I've got an instance running on ss.hrbrmstr.de
via a Caddy reverse proxy:
ss.hrbrmstr.de {
reverse_proxy localhost:8888
}
(there’s a a bit more to my config than that, but ^^ is the minimum you need)
If you're as daft as I am and want to run your own instance, I'd — at a minimum — recommend changing this:
const baseUrl = "https://seashells.io/v/"
in main.go
to the domain you're using.
The very minimal web app that surrounds the presentation layer is based on the Gin framework. I also suggest changing this bit that starts up Gin:
r.Run()
in `frontend.go` to:
r.Run("127.0.0.1:8888")
(or some other port) since you don't need to expose the HTTP web interface directly to the internet.
You could bother changing the 1337
port, but it needs to be exposed, so you’re better off using other methods to control what sources can shunt requests to it.
Earlier this year, right after getting sidelined with covid, I threw together a janky Deno-based TUI app for my 😎 Weatherflow Tempest weather station1.
I've got that running live against my instance via https://ss.hrbrmstr.de/v/RkSp9xYZ if you want to see it in action. I’m going to modify the seashells’ server code a bit to have a longer timeout, so it should be up if/when you hit it.
⚠️ The server code does need a bit of “robustification”2 ⚠️ and if I end up using the software for realz, I'll likely contribute some safety and resilience patches to it. Most of the “env file” functionality is not baked in yet, and tons of values that should be configurable are hard-coded. So, don’t try to do anything too fancy.
Blogs Are Really Fun
I suspect “Blogs Are Really Fun” was a backronym vs. something that just happened to spell “barf
”. Regardless of the potential puerility of the name, barf (SH) is a minimalist template-less blogging engine written in pure shell, that uses the “smu” utility we covered yesterday for markdown conversion to HTML. It sports:
automatic, valid RSS generation
handling of both blog posts and normal pages
zero front matter or templating, just plain markdown
automagic dark mode support
The tool was inspired by blog.sh and is easy to get up and running (“easy” is a word I rarely use, too).
CheerpJ
APPLETS ARE BACK, BA-BY!
In fact, full Java apps are also now browserfiable thanks to Leaning Technologies, a team of folks who “make WebAssembly solutions to help businesses transitioning from native to modern Web Applications”.
Their Applet Runner is a browser extension (sorry Safari users, no Java. For. You!) that will run legacy applets that you may still find on web pages, or dredge up from web archives. Back in the day, lots of experimental web datavis were created with Java applets, so it's cool to see those aren't quite in the graveyard — yet.
I'm a bit more excited about CheerpJ-proper, which just had a 3.0 milestone release. I'll let its creators explain what it is (and, skip indents/etc. since this is 100% just copypasta and not my words):
CheerpJ is Leaning Technologies’ solution to run large-scale, unmodified Java applications and applets in the browser. The execution is fully client-side and there is no need for any server-side component beside a standard HTTP server. Over the last few years, it has been our most successful product, not just commercially but also in the community, with over 100,000 users globally.
CheerpJ success stems from being able to efficiently run real-world Java applications with minimal effort, which is very useful to extend the life of legacy client-side Java applications. This is made possible by a few capabilities:
No source code required: CheerpJ does not need access to the source code at all, and operates at the level of Java bytecode in
.class
and.jar
files. Third-party libraries, dependencies and obfuscated code pose no issue.Support for advanced Java features: Any real-world Java application, and the OpenJDK runtime itself, will make use of reflection, multithreading, and runtime generated classes (used to implement lambdas/invokedynamic and proxies). CheerpJ fully supports all of these, requiring no adaptation of the application.
OpenJDK compatibility: CheerpJ is based on an unmodified OpenJDK environment, guaranteeing the same behavior on the browser compared to a native JVM. It includes many emulation layers to ensure Filesystem, Networking, Printing, Clipboard and many other subsystems work seamlessly.
While you cannot install or use this tooling locally, you can play with it in their custom fiddle web app: https://javafiddle.leaningtech.com/.
In theory, this link should take you to a pre-populated fiddle I made with woefully rusty Java skills3. Just in case it doesn't, you can paste the following code into a fresh fiddle to have it draw what's in the section header:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;
import java.awt.image.BufferedImage;
// mandatory class name/setup
public class JavaFiddle implements Runnable {
public void run() {
// these vals and a few hard-coded ones below seemed
// to work best in the fiddle view context. ymmv.
int MAX_ITER = 570;
double ZOOM = 150;
double zx, zy, cX, cY, tmp;
JFrame f = new JFrame("Mandelbrot");
BufferedImage I = new BufferedImage(
400, 400, BufferedImage.TYPE_INT_RGB
);
for (int y = 0; y < 400; y++) {
for (int x = 0; x < 400; x++) {
zx = zy = 0;
cX = (x - 275) / ZOOM;
cY = (y - 200) / ZOOM;
int iter = MAX_ITER;
while (zx * zx + zy * zy < 4 && iter > 0) {
tmp = zx * zx - zy * zy + cX;
zy = 2.0 * zx * zy + cY;
zx = tmp;
iter--;
}
I.setRGB(x, y, iter | (iter << 8));
}
}
JLabel imageLabel = new JLabel(new ImageIcon(I));
f.add(imageLabel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new JavaFiddle());
}
}
I'm glad we have the option to not just toss billions of lines of Java code to the wind, and can bring Java to browsers in a safe, modern way. Hopefully, this helps preserve the utility of the skillsets of the millions of folks who have learned Java, and buys orgs some much-needed time to transition from “old” tech to “shiny” new tech.
FIN
Colin Meloy of The Decemberists has a fun Substack and acquiesced to fan requests to cover Gordon Lightfoot's “The Wreck of the Edmund Fitzgerald”. Colin is one of my fav musicians, and The Decememberists weave around in my top 1-3 fav band positions. Colin's interpretation is def worth checking out: https://substack.com/inbox/post/120134975. ☮
i did this b/c “moving across the room” was akin to running a marathon for a while and I had lots of sedentary + awake time
i.e., think twice before running this on the public internet; if you do want this functionality only for yourself, then host the reverse proxy on your Tailnet.
one of my very first “real” java apps was a Mandelbrot explorer.