CI & WebGL
“What if I want to show people the stuff I’m working on, like, quickly?”
So, over the weekend I connected some Godot code to a CI Pipeline: whenever I push a build, it builds a WASM+OpenGL build to a Wasabi (cheap S3 clone) bucket, at which point I can just serve the bucket from a web endpoint.
That’s a first step in a more complete build pipeline: asking people to fish through an empty indexed directory is not a Final Product kind of thing, but from here I can kick off an Eleventy (think jekyll) build or something to build the rest of the website around the engine. (in fact, I’m also thinking of replacing THIS blog with “Github Actions” + “Eleventy”, because who trusts substack? Not me!)
Now instead of showing people short videos, I can literally pass around the entire game as an example. Still… still probably going to use short videos, though.
This CI/Web process has turned out to be fraught with danger.
First of all: I’ve been doing all of my learning in Godot 4.0, which is blisteringly new. A new beta or RC has been shipping week after week; It’s a fairly large rewrite of Godot, and while it has all the new features it’s also rich with jank.
While the web build ran on my computer when I first tried it, the compiled WASM took up 45MB, which is hardly heartening for a web project where sizes over 1MB for a website are still considered a little rude.
It wasn’t until I had the whole web pipeline was up and running, though, that I got to see how the 4.0 web build would perform on an iPhone or a mac desktop: very, very poorly. I think something about the interaction between WASM, OpenGL3, and ARM has gone very wrong, here, because while it loads sluggishly (a few seconds) on a PC, it takes something like 90 seconds to load on a Mac (technically that’s not broken, but it’s broken), and doesn’t load at all on an iPhone.
I spent many hours poking at this in forums, documentation, GitHub issues, but the whole system is so new in Godot 4.0 that finding any information about it is difficult. Godot 4.0 supports multiple renderer backends, but OpenGL 3.0 is one of its most limited, and for pressed as to why Godot’s web experience is terrible the developers have long responded with “it’s not really for that”. Godot-for-web is a bit of a second-class experience, so Godot 4.0 not working quite right on the web doesn’t feel like it’s going to be a huge priority.
That being said, I never bothered to file an actual bug: maybe I should! I’m an awful open source citizen, you guys: I tend to interact with projects in read-only fashion like they are unmaintained wastelands and fork-and-patch if I need something changed rather than attempt to communicate with a human.
Anyways, I decided to try a Plan B: how does the web build work with the previous major version of Godot? I remember I’d tried it before and it worked okay! (In fact, at Godot 4.0 beta 1 there was no web build at all, they kinda “remembered” and it’s been jumping in and out of the product in various states of half-broken ever since, whereas Godot 3.4.1 has been stably chugging along for months.)
When I’m starting new projects, I like to chase the bleeding edge of the tech somewhat - it makes learning harder because everything is actively on fire, but it also means that I’m slightly less obsolete in a few years.
Anyways: it works pretty well. Godot 3.4.1 offers the ability to compile for OpenGL 2.0, which is an older standard that’s more well-supported across browsers.
The compiled output is much smaller, too: about half of the size of Godot 4.0’s web build. Still 14Mb, but after applying aggressive gzip compression at the CDN level it ends up shipping to the browser in a relatively svelte 4.5MB. That’s still a big boy, but it loads quickly enough that I wouldn’t be embarrassed to ship it to production (I believe that weighs in smaller than our compiled VRChat Web Application build, although this 4.5MB is without any external assets)
It runs seamlessly on my computer, on my mac, even on my iPhone:
https://cardchapter.com/v2/web-2023-02-15T07%3A59%3A23.393Z/
That’s a surprise, too: the Godot developers rightfully warn you from trying to get any kind of web game running on an iPhone, because WebKit’s WebGL support is complete and utter horsetrash. On purpose. Apple wants you to run iOS applications. Their support for running in-browser WebGL is described as, uh, experimental/janky. But, at least for the basic tests I’m running right now, 3.4.1 compiles and runs a web build that boots up.
Converting this batch of code to run on 3.4.1 does take some effort, though. A lot of changes have been made since 4.0 and projects do not backport cleanly. For one thing, I have to go back to the awkward python-inspired yield
instead of the much nicer async/await
.
On top of that, I lost some viewport flexibility.
But overall, it seems to work! And while I was here, I got the oh-hai HiDPI settings working - this looks crisp on an iPhone or my UHD screen.
And, hey, now that I’m back in a well-supported version of Godot, there’s a much more comprehensive community of working plugins.
I still have the whole pipeline available for 4.0, so I can keep the possibility of porting forward on the table for now.
Tirelessly Reinventing the Wheel
(this title is a pun, because a tire is a kind of wheel)
Okay, so, what’s actually happening in these demos? It seems to be just a bunch of camera moves. That’s barely anything!
Well, yes! I’m trying to figure out the camera.
The current build has three targets, which it moves between with the camera:
There’s both “code” and “no code” - the whole thing is held together by these modular command nodes in Series, like “Delay”, “Appear”, “Play”, and “CameraMove” - so I can build out the entire scene with clicks and drags, rather than having to fuss around with code.
It works pretty well! The plan at the moment is to add Dialogue nodes (folding in all of the work I’ve been doing recently on that ) - and “Nav” nodes (to build a navigational structure so that the player can move back and forth within the story), and “Lock” nodes (with challenges that the player has to overcome to continue), and so on and so forth.
Ultimately where that puts the system makes it feel almost closer to being a … Visual Novel Engine. Huh. Maybe I should tool around a bit with Ren’Py or VN Maker and see what they have to offer.
I kinda realized that what I was building here was kind of an updated version of my CardChapter tree-based narrative/presentation system so the engine is being rebranded as CardChapter 2, until I … you know, change my mind again, two weeks from now.
So that’s one way in which I’m reinventing the wheel: CardChapter is literally a wheel I’ve already invented!
I don’t talk about it that much any more, but it was built to be a mobile-friendly long-form narrative engine supporting modular node-based content. It’s totally static - CardChapter documents contain both their own data and all of the code necessary to interpret that data - and the tools for modifying CardChapter documents are all contained within the CardChapter engine itself, so every CardChapter page is just the entire engine, which means that any document can be used as the locus for a new project.
And… like, CardChapter is weird! I get it! I rebuilt my entire comic website to use it, and people mostly just complain about how it’s “unsearchable” and “hard to find things in” and “awkward” and “weird” and “doesn’t support RSS”.
I mean, it would require a complete ground-up rewrite - modern search engines are Not Your Friend anyways.
(my glory days of actually running a comic website were with Django: my custom Django engine was actually very usable, IMO)
I got at least some of the way through a story using CardChapter: northwestica - but the story was built using an older build that still had pretty bad “flicker” issues. That being said: I’m pretty proud of the work I did there. Nobody read it, but northwestica was funnier than cube drone IMO.
I built a christmas quiz for my family to run over Zoom for a very sad 2020 family gathering with it, and a sequel, Family Day Quiz.
Mostly, though - and I partially blame its idiosyncratic quine-based structure and single-document architecture for this - it never really crawled all the way out of jank valley. Do you know what presenters want? It’s not tree-shaped documents and functional quines.
But this story about reinventing the wheel, while it could be about my tireless and almost entirely cursed attempts to re-build comic hosting a full decade after webcomics have ceased to be a relevant medium wasn’t even what I came here to talk about!
Tirelessly Reinventing the Wheel pt 2: Learning What a Tween Is
Instead: when I was working on those camera moves, I made a little node called AnimationHelper to help run all of the interpolation math required to do animation properly. It’ll do a nice little bounce for me if I want. It’s got three entire easings, "linear"
, "cubic"
, and "bounce"
.
Then, while I was watching YouTube videos about popular Godot plugins, it talked about Anima, a more powerful plugin replacement for the built-in Godot Tween class.
The fuck is Godot’s Tween class?
… oh, look, a little helper function to run interpolation for me.
I guess, on one hand, I feel like a schmuck for building this myself out of code when a tool already existed. Obviously a game engine is going to have a built-in interpolation library, right? In retrospect I should have looked for it rather than building my own. In my defense, though, I am really, really not a video game programmer.
On the other hand, like that one time a decade ago that I built my own little command-line tool to automate the creation and synchronization of local development virtual machines, only to discover a recently-developed tool that did that exact same thing, but way better: initial feeling, frustration, but after not too much introspection, not only am I delighted that this much more well-developed toolchain exists, I’m also happy that I understand it way, way better now. Fuck yeah, gonna go learn Anima.
“Build it yourself by accident, then discover the tool that does it way better and makes your job 1000% easier” is, in my experience, one of the better ways to learn things.