Transcript
00:00:00This is Wterm, a web-based terminal emulator by Vasell
00:00:03that renders directly to the DOM instead of on a canvas.
00:00:06So text selection, browser find,
00:00:08and screen readers all just work with it.
00:00:10It's written in Zig, compiles to a 12 kilobyte WASM binary,
00:00:14and there's also an optional backend powered by LibGhosty,
00:00:17the same engine that powers the Ghosty terminal,
00:00:19which gives you full terminal compatibility in the browser.
00:00:22But is a 12 kilobyte WASM binary
00:00:24really enough to replace a native terminal emulator?
00:00:28Probably not, but hit subscribe and let's find out.
00:00:33So web terminals are pretty much everywhere.
00:00:36In cloud IDEs like GitHub Codespaces,
00:00:39infrastructure tools like Portainer or Qualify,
00:00:41and even desktop IDEs like VS Code or Cursor.
00:00:44But they all use Xterm.js to do it
00:00:47because it's been around for a long time
00:00:49and it's basically the default.
00:00:51Xterm has a big problem though.
00:00:52It renders to a canvas element.
00:00:54So doing something like selecting text
00:00:56or finding words in a page
00:00:58all have to be re-implemented from scratch,
00:01:00which doesn't always work that well.
00:01:02Wterm takes a completely different approach
00:01:04by rendering to the DOM,
00:01:05which means the terminal output is just HTML,
00:01:08and the browser basically handles that for free.
00:01:10But Wterm can also do some really cool things
00:01:13with this HTML rendering,
00:01:14like only re-render the row that has updated,
00:01:17instead of re-rendering the whole terminal on each frame.
00:01:20It can also be written in different frameworks
00:01:22like React or Vue.
00:01:23You can change the theme.
00:01:24And there's also a separate Wterm ghosty package,
00:01:27which swaps out the zig call with lib ghosty
00:01:29and works surprisingly better
00:01:31than the other web ghosty project,
00:01:33which we'll talk more about later on in the video.
00:01:35But for now, let's try out Wterm
00:01:37with a simple demo project.
00:01:38So after installing Wterm with React,
00:01:40I've imported the component as well as the CSS,
00:01:43and I'm rendering the component over here.
00:01:45So now if I run the app and then go to the browser,
00:01:48I can see that there is a terminal.
00:01:49But if I press a command like ls,
00:01:51we can see nothing happens.
00:01:52And this is because it's not connected
00:01:53to another computer to read information from.
00:01:56Let me explain.
00:01:57So right now the client isn't connected to a backend,
00:01:59so there's nowhere for it to get information from.
00:02:01But what we have to do is connect it to another machine.
00:02:04So it could be my local machine
00:02:06or a machine on the cloud,
00:02:07and then render a fake terminal or a pseudo terminal
00:02:10inside that machine with the same dimensions
00:02:13as the one from the client.
00:02:14So if we do some keystrokes,
00:02:16that keystroke information gets sent
00:02:18to the other machine,
00:02:20which executes those keystrokes,
00:02:22renders the results,
00:02:23and sends all that information back to the client.
00:02:25And that back and forth needs to happen
00:02:26very quickly with minimal delay.
00:02:28So the best way to connect the client
00:02:30and the other machine together
00:02:31is to use WebSockets.
00:02:32So let's go ahead and do that.
00:02:34So we can use a HETS in the server
00:02:35with Ubuntu I already have set up
00:02:37with Node installed.
00:02:38And I also already have a Wterm server
00:02:40with a server script.
00:02:42So if we look into that,
00:02:43we can see we're creating a WebSocket server
00:02:45on the slash API terminal path.
00:02:48This will make more sense a bit later.
00:02:49And down here,
00:02:49we're spawning a pseudo terminal
00:02:51with a name that matches our terminal type.
00:02:53Here's how you can find yours if you're curious.
00:02:55And down here,
00:02:56we're getting any keystroke from the client,
00:02:58processing it on the server,
00:02:59so inside our fake terminal,
00:03:01and then returning that information
00:03:02to the client over here.
00:03:03So the server returns everything
00:03:05and not just a specific row that's been updated.
00:03:07Now over on the client in the app.tsx file,
00:03:10we're making a WebSocket connection
00:03:11to our server on the slash API slash terminal port.
00:03:14Then we're using the WebSocket transform
00:03:16from Wterm to connect to that URL
00:03:19with automatic reconnects.
00:03:21Then this is what sends keystroke information
00:03:23from here to the server.
00:03:24We handle browser resize here,
00:03:26and then down here,
00:03:27and the handle data function
00:03:28handles all the information
00:03:30that comes from the server.
00:03:31And the cool thing about the ZIG core
00:03:33is that it will pass this information,
00:03:35figures out what's been changed,
00:03:36and only re-renders that part of the HTML.
00:03:39Down here, the column and row size
00:03:41need to match what we had on the server,
00:03:42and everything else is pretty self-explanatory.
00:03:45So now with the client and server running,
00:03:47back in the browser, if I press LS,
00:03:49we can see it lists the files we have available.
00:03:52So I could press LS with the L flag
00:03:53to see more information about the files.
00:03:55I can CD into a file,
00:03:57take a look at the information inside it,
00:03:59and also do things like see the list
00:04:01of containers I have running.
00:04:02I can even open a file with Vim
00:04:03and navigate through it.
00:04:04But even though all of that works,
00:04:06it doesn't do it amazingly well.
00:04:07I mean, if we try to highlight some text,
00:04:09we can see some characters
00:04:10are completely unreadable.
00:04:12So to fix that,
00:04:13we can set up Wterm with Ghosty
00:04:15by loading Ghosty core
00:04:16and adding it as a prop in React.
00:04:18You can see now that if we open the server file
00:04:20and highlight some text,
00:04:22everything is much more readable.
00:04:23It can even do things like
00:04:24render open code correctly,
00:04:26allowing us to change models,
00:04:27and give it a prompt with emoji support.
00:04:29We can even see that Ghosty renders colors
00:04:31slightly better
00:04:31than with the default Wterm core renderer.
00:04:34But the Zig core is only 12 kilobytes
00:04:36compared to the 400 kilobytes from Ghosty.
00:04:39So if you care about size,
00:04:40then maybe stick to the Zig core.
00:04:43Anyway, that's a quick overview of Wterm from Vercel.
00:04:46Of course, there are so many more features
00:04:48I didn't go through,
00:04:49like being able to convert Markdown
00:04:51to a nice terminal output,
00:04:52using just Bash to navigate through fake files
00:04:55if you don't have access to a backend.
00:04:57And there are even examples
00:04:58of how to set up an SSH client
00:05:00through a terminal in the browser.
00:05:02But I didn't find Wterm to be perfect.
00:05:05There were some rendering issues
00:05:06when using the Ghosty version,
00:05:08going back and forth between NeoVim
00:05:10or even OpenCode.
00:05:11And to get the Ghosty renderer to work
00:05:13with my BUN frontend,
00:05:15I had to import the WASM file
00:05:17because BUN wouldn't copy any non-JS files
00:05:19from the Node modules folder.
00:05:21But I do like the DOM rendering approach,
00:05:23which means you do get accessibility
00:05:25and native browser features
00:05:27without doing any extra work,
00:05:29which Xterm has struggled to do,
00:05:31even though it's been around for more than 10 years.
00:05:33But Xterm.js does have a massive ecosystem
00:05:35and is the battle-tested solution,
00:05:38so you won't go wrong if you do end up choosing it.
00:05:40There's also GhostyWeb by Coda,
00:05:42which takes a different approach.
00:05:43It uses the same libGhosty engine
00:05:45used by the actual Ghosty terminal,
00:05:48but it's a drop-in replacement for Xterm,
00:05:50so it still uses the canvas rendering approach
00:05:52and uses the same API,
00:05:54but you do get a better terminal.
Community Posts
No posts yet. Be the first to write about this video!
Write about this video