Hello! In keeping with my six months blogging cadence, here’s a fresh batch of news on Orca. I mention our new Discord server and my apperance on Zig Showtime, discuss changes in our UI styling API, and report on work in progress such as the Orca debugger or the Zig bindings.
Orca has its own Discord server now! For a while we were kindly hosted by the Handmade Network, but it was about time we got our own space. The server is used to showcase our work-in-progress, help people try out Orca in its early stage, discuss its design and implementation, and organize our efforts with the project’s contributors. If you’d like to chat or get more frequent sneak peeks of what we’re building, see you there!
I’ve recently been invited by Loris Cro on Zig Showtime. I demoed how to write an Orca application from scratch, we discussed about the long-term vision of Orca, and I went into a pretty detailed blackboard session explaning our vector graphics rendering tech. This made for a long chat! It was a blast, and I hope you enjoy it as much as I did.
Following feedback from early testers, I decided to redesign the styling and theming APIs of our UI system. This consists in the following changes:
Previously, some style attributes, like the background color or the font size, where inherited from the parent box in a style stack fashion (and set to default values by a “theme” struct passed at the beginning of the UI frame). This made for some confusion as to which attributes should be inherited (inheritence doesn’t always make sense), and where was a given attribute inherited from. It also didn’t save much typing in the end, as you’d typically end up re-specifying a bunch of inherited attributes for each widget anyway, as they would often be different from their “container” parent.
These are annoyances that plague style stacks and CSS alike, and I wasn’t happy with it, so we just got rid of style inheritence altogether. Each box now starts with default (ie. zeroed) style attributes, and you have to specify those you care about. Note that you can still set the attributes for a bunch of boxes at once, by using style rules. But the targeting of these boxes is explicit, rather than being defined by their ancestors in the UI tree.
Our previous API allowed you to set style attributes through a style struct and style flags: you’d pass a struct containing the values for the attributes you cared about, and the others zeroed out. But since some attributes have legit zero values, you also had to pass a combination of style flags to specify which attributes to apply. This ended up looking like this:
oc_ui_style_next(&(oc_ui_style){
.size.width = {OC_UI_SIZE_PARENT, 1},
.size.height = {OC_UI_SIZE_CHILDREN},
.bgColor = {1, 0, 0, 1},
},
UI_STYLE_SIZE | UI_STYLE_BG_COLOR);
oc_ui_box("styled box")
{
// This box is styled according to the above rule.
}
Not only was it redundant (since the flags you had to specify were essentially repeating the style struct designated initializers), but it also proved cumbersome to make idiomatic bindings for this pattern in other languages.
Note that it was also going through the style rule system,
oc_ui_style_next
only being a helper to create a rule
matching the next box. This made it a bit hard to see where styling was
happening when the oc_ui_style_next
call was made far
before the oc_ui_box
call.
I decided to scratch that and let style attributes be specified by individual calls, as well as put this specification inside the styled box:
oc_ui_box("styled box")
{
oc_ui_set_size(OC_UI_WIDTH, (oc_ui_size){OC_UI_SIZE_PARENT, 1});
oc_ui_set_size(OC_UI_HEIGHT, (oc_ui_size){OC_UI_SIZE_CHILDREN});
oc_ui_set_color(OC_UI_BG_COLOR, (oc_color){1, 0, 0, 1});
}
Specifying style rules was fairly annoying, involving a builder API to create the rule pattern by appending box selectors to a list, and explicitly managing the rules ordering. To simplify this, I wrote a little parser that builds the pattern from a string, and also changed the way in which rules’ styles are specified to mirror that of boxes:
oc_ui_style_rule("foo.hover .button")
{
oc_ui_set_size(OC_UI_WIDTH, (oc_ui_size){OC_UI_SIZE_PARENT, 1});
oc_ui_set_size(OC_UI_HEIGHT, (oc_ui_size){OC_UI_SIZE_CHILDREN});
oc_ui_set_color(OC_UI_BG_COLOR, (oc_color){1, 0, 0, 1});
}
The rule above will match all boxes that have the button
tag, and are a descendent of a box named foo
that is
currently hovered by the mouse.
In order to style a UI with a consistent “theme”, it is useful to define style variables that can contain frequently used values. This is done like so:
oc_ui_var_set_i32("myVar", 16);
You can also create a variable and assign it a default value only if the variable is not already declared:
oc_ui_var_default_i32("myVar", 16);
You can then use the variable to set style attributes:
oc_ui_style_set_var(OC_UI_TEXT_SIZE, "myVar");
Themes are implemented as a set of predefined style variables, which the widgets use to specify their default style. You can tweak the theme by changing the values of those variables.
Added together, these changes made our usage code both shorter and more explicit. It also greatly simplified jumping into the prototyping of our internal debugger’s UI.
Speaking of which, I’m making good progress on the Orca debugger, and in the process I’m probably learning a lot more about the Dwarf file format than is healthy for a living organism. The Dwarf situation is more or less what you’d expect when scope creep meets backwards compatibility. We’ll most likely exfiltrate ourselves from this rat’s nest by translating the bits we need to a saner custom format, but in the meantime I’m neck deep in this tangled mess.
Yet, I’m at a point where we can set breakpoints and line step through the source code. I also have a source tree explorer of sorts, a callstack, and a list of in-scope variables. There’s still some work left to compute the locations of these variables and extract their types, in order to display their values in the watch window.
You can also browse a list of all the symbols found in the app’s WebAssembly module, and see a bytecode view of each function, along with the values of their registers:
We’ve been testing out Reuben’s Zig build script in a development branch for a little while, and it’s great. It takes care of fetching and checking the correct dependencies, driving code generation, caching artifacts, and only rebuilding what’s necessary. It still needs some tweaks and cleanup, but we should be able to switch to it entirely and leave our kludgy python scripts behind soon! This should make it a lot easier to onboard new contributors, so I’m pretty excited about it.
Julian has undertaken a rewrite of the Zig bindings to make them more
idiomatic to Zig, as well as sync them with the latest API changes.
Previously we had a script to generate Zig APIs from our
language-agnostic API definition contained in a api.json
file, but automatic translation only gets you so far. Now the idea is to
target a specific version of the API definition, but manually write
higher quality bindings. This way the bindings maintainers can easily
track changes to the the API file (or even flag them automatically in
CI), and update bindings accordingly. Basing the bindings on the
api.json
(as opposed to the C headers) also helps identify
lacking metadata in the API (e.g. bounds checking or mutability
annotations), which would be useful for other languages as well.
Thanks for reading! I hope this update made you excited about the work we’re doing. If so don’t hesitate to join the Orca Discord server and start a conversation! As a reminder, if you want to support Orca and help me push it forward, you can do so by donating on Github Sponsors. Any help is greatly appreciated!
I wish you a wonderful spring~