Clay (short for C Layout) is a high performance 2D UI layout library
github.com
github.com
...And the three nav links are made via empty, transparent <a> containers absolutely positioned over <div> text. Focusing, therefore, has nothing to read.
N.b both left- and right-clicking activates these anchors, because navigation is implemented as a delegated `mousedown` event on the document.
The demo should at least have a noscript tag, to tell me why I can't read the page.
What I meant to say was: The lack of a11y doesn't seem to be a deficiency of the library itself but rather of a hastily written demo application/renderer.
It allows you to add ping to various obstacles, has both TTS and STT, and so on and... I could actually play it, whilst blind [1]. I could play a shooter, and not suck, without my sight.
A lot of what they did with the engine was really simple, but I so wish that there was a wider adoption of those kinds of techniques.
[1] My blindness comes and goes. Some days I have 0% vision, other days 75%.
EDIT: It does work in Firefox for Android!
MacOS 11 Firefox 129
For instance, being able to set the constraint "element.[x,y] = other.[x,y]+other.[width,height]/2;", instead of working with "attachment" objects.
btw, gtk is based on tcl/tk which i believe is the, or one of the, original auto layout engines
it's awesome for small things (like mobile-style app GUIs), but not usable for full-scale desktop apps (e.g. a DAW).
but that's a question of performance. 'maintainability' would be removing the code that adds the row to the list, which is trivial with cassowary
It's powerful but not trivial to adopt. In particular, the design experience in Interface Builder has gone backwards in usability. The old system of resizing rules visualized as "springs and struts" was easier to understand in a visual design tool.
One might argue that's the cost of progress, and that designers using Interface Builder become better UI engineers when they have to figure out how to express themselves in constraints. But it seems to me that the reality is that a lot of people just stopped using IB.
IB used to be a crown jewel of NeXT's development suite in the 1990s. It was simple and focused, and allowed you to build surprisingly powerful UIs that connected to high-performance native code (unlike its mainstream competitor Visual Basic).
I don't think a lot of people have such fond feelings about Apple's current IB. Something was lost along the way.
I wonder how we can stimulate "expert" tools and systems for those who don't want to take the greedy path of least resistance, and are tired of painting themselves into corners that way.
My learning path went something like this:
(The dark ages of data processing for personal use)
- Use a text file: Fine, you have to write your own read & write logic, but for small amounts of data this works.
- Use a CSV file: less custom logic than plaintext
- Use a JSON file: really nice to have structured data!
- Use a Python pickle file: the idea is you can “pick up where you left off”, but it’s slow, clunky, and inflexible
(Finally learning to use a database)
- Use Google Sheets: oh, it’s nice to be able to index things without needing to read/write the entire dataset! You can also do searches and stuff, it’s great.
- Django ORM + MongoDB: Oh my god, so horrible. MongoDB was supposed to be simple. This set up was slow and complicated. Migrations were a constant pain. And we didn’t even have any users.
- Postgres: It all makes sense. SQL is great. You can think about and query your data in reasonable ways. And it’s fast.
- DynamoDB: Yeah whatever, as long as you do validation on every read/write you’ll probably be fine.
I always thought that Apple should have really pushed the whole "Applescript Studio" thing so as to create something even better and more approachable than Visual Basic --- it could have been a true HyperCard replacement.
First, expectations and requirements went up. Laying stuff out with a mouse and snap-to alignment guides is ok for simple UI, but the more complex the design, the more I would end up fighting the vector-art style design interface. I remember staying up late fixing pixel alignment errors in nib files. Often you would need to move objects around to inspect another underneath and then play undo games to get things back exactly where they were.
The interesting parallel here is that the designers were doing all the designs in vector art apps, and were also frequently missing dynamic aspects of the design requirements.
It was one thing to design complex dialog boxes for desktop; think of a photoshop filter control pane. You target a minimum size screen, and then work with a fixed pane and lay things out. When the iPhone came out, IB worked ok for early versions and stock components. Screens were crowded but fixed width.
Once bigger screens came out, more designs started needing variable width layout computation. The APIs for dynamic layout were (as I recall now) more subtle than they sounded in the docs, and I recall joining several teams that misused them. “sizeToFit” and “sizeThatFits” were two culprits. Perhaps it made more sense in the simpler NeXT days, and perhaps the docs degraded. If you didn’t read Apple’s “Programming Guide” docs, it was hard to know how these things were supposed to work together, and those were like mini books. The guides got increasingly ignored as the iPhone’s UIKit took center stage. I was always a fan of NSAutoresizingMaskOptions but rarely saw others use them.
Second, modern version control made the binary nib files unmanageable, and merging the xml xib files was also awful.
Third, and to the parent comment’s point, there were quality problems with Interface Builder. New stuff got heaped on every year. The data model was proprietary but looking at the xml clearly just got more complicated and version-encumbered over time.
In summary, it is tempting to glorify the original NeXT tools, but I never used them. I started toying with IB in 2004. It never felt like a brilliant system because I couldn’t express the underlying logic of designs in the visual box dragging paradigm. Ironically auto layout pushed me further towards UI in code. But to each their own.
Did you make any progress on this for macOS or iOS/iPadOS?
Out of total hatred of Xcode and Interface Builder I started experimenting with writing Apple UI stuff in C (calling Cocoa methods through libobjc), but there's precious few resources on doing so-called "Nibless/Xibless" development beyond the basics.
I'd love to find a decent-sized open-source macOS app written in [Objective-]C/C++ but with a good assortment of common UI paradigms, all done in code. I shudder whenever I see that dreaded .xcodeproj directory...
I suspect that this is because the average Mac window/view nib file is a great deal less complex than its counterpart view nib on iOS and still manageable to edit in Interface Builder, and so a lot of Mac devs still use nibs.
I've toyed with code-only Mac AppKit stuff but generally have found that it's not quite as clean as code only iOS UIKit. For example if I recall correctly, there's no initializer for NSWindow that sets all of the flags that make it behave like a normal window because it's assumed that you'll be using nibs. It's not difficult to write an extension to NSWindow to fix this, but it has to be done for reasonable productivity, and these papercuts are strewn throughout AppKit. In contrast, most UIKit controls can be initialized with few or no arguments and still behave as expected.
Thanks for the suggestion! Any others you can think of?
This seems to have originated in something called Visix Galaxy, and supposedly done better there than in Interface Builder. See here: https://wiki.c2.com/?SpringsAndStruts
I tried finding any documentation on this tool/SDK, but no luck. Any one else has any more information on what this Galaxy looked like?
I'd love something like this:
red-box {
width: 100
height: 100
top: 10
left: 10
}
blue-box {
width: 50
height: 50
top: $red-box.bottom * 2
left: $red-box.right + 100
}I think flexbox and grid handle a good chunk of what you'd want here, but having to handle constraints at the "group" level. Either flexbox, so the browser finds the best way to place elements into a line based on your rules, or grid for 2 dimensions:
boxes {
display: grid;
/* there are only 2 columns, 100px each */
grid-template-columns: 100px 100px;
/* all rows are 100px tall */
grid-auto-rows: 100px;
> * {
/* All children take up 1 col, and 1 row */
grid-column-end: span 1;
grid-row-end: span 1;
}
}
blue-box {
/* blue-box must start at col #2 and row #2 */
grid-column-start: 2;
grid-row-start: 2;
}The problem with this specific API is that it depends on source order. To have element-b anchored to element-a, element-a must come first in source. I'm not really sure if it was designed that way or just implemented that way in Chrome, but it's the behavior I experienced when I played around with it.
Currently we are detecting mobile based on a JS library and branching the template based on that, which I abhor. Using Tailwind’s media prefixes and some data- group selectors, I’ve gotten a rough version working with just two small JS listeners to toggle the open state.
I think you could apply group rules to target a specific child or sibling in such a way that you can apply specific rulesets, and maybe CSS variables to dynamically base those on sibling values.
What I really want is something like the old Flash/ActionScript display list. Just a 2d scene graph with the option to output draw commands, text or sprites. Things like containers (with things like border/backgrounds/etc.) and layouts can be built on top of that, so you could have two separate header files, one for the display list and another for a layout library.
One thing you have to do for reasonable accessibility is maintain a retained model behind the scenes even if you have an immediate mode API, so that's what I did. The immediate mode API does a bunch of caching in order to construct and maintain an appropriate retained mode tree across frames, which makes it possible to cleanly handle things like focus, selection and narration for invisible controls, etc. You also have to bake accessibility into the API from the start, for example by making certain every single widget has a description or a reasonable approximation of one, and by making sure there is an approximation of roles for every widget too.
A simple 'read a text description of the focused/clicked control' also doesn't get you far enough for narration - for example if there's a slider or textarea, you don't want to read the description and then the new value every time it changes, your narration has to be 'smart' and know to only read the description initially.
I'm hoping eventually AccessKit (https://github.com/AccessKit/accesskit) will be mature enough to use though.
(For embedded and/or touch first UI, LVGL is pretty nice, but probably lacking any semblance of accessibility features apart from keyboard navigation, but you could hook that yourself).
The style in the screenshots reminds me of KDX[0] from Haxial.
There was some news feed web app that used <canvas /> for better scrolling performance.
If layouts change during interaction (e.g., orientation swap), then you will have a roundtrip to the server to recalculate. I assume this would cost more time than letting the browser css engine do their thing.
Very curious train of thought.
> Fast enough to recompute your entire UI every frame
Yet, when I scroll the front page, made with Clay, it stutters and feels like it can barely handle smooth scrolling, even on a modern Apple Silicon laptop.
Also, poor accessibility as well.
(otoh when i try to load the web page it doesn't work at all, not even jankily, if we're talking about https://www.nicbarker.com/clay)
> River is an experimental assembly-like programming language.
- Text selection isn't possible, except on the final slide when I change to HTML Renderer and then it works very strangely (randomly selects all texts sometimes)
- The page crashed: "Error code: STATUS_ACCESS_VIOLATION"
- Also rounded corners look very strange
I would look closer at this library too, if it wasn't for:
"Clay UI hierarchies are built using C macros"
Yikes :S