Clay – UI Layout Library
Nice! It's pretty cool what you can make in a few thousand lines. Though Flex isn't my favorite as I prefer full CSS Grid. So I ended up making a CSS Grid layout library that I'm proud of in pure Nim (1). Though I'll have to checkout Clay and compare some of the layout algorithms.
It's neat to see boxes resizing themselves using an algorithm you implemented. Wonder if I could expose a C interface?
The reason I like CSS Grid is that I could imitate the formatting like this:
test "compute others":
var gt: GridTemplate
parseGridTemplateColumns gt, ["first"] 40'ux \
["second", "line2"] 50'ux \
["line3"] auto \
["col4-start"] 50'ux \
["five"] 40'ux ["end"]
1: https://github.com/elcritch/cssgridJust a funny note—there’s a button at the end to switch between HTML and Canvas. I think it is neat how little difference it makes… normally.
But with iOS Safari + Dark Reader, at least on my side, the HTML page is turned into dark mode with Dark Reader, while the canvas page is not. So, it basically ruins the wow factor, haha.
But it still looks nice.
Just wanted to drop a note - everything following the animation cannot be selected - seems focus is stolen somehow - whenever I try to select text, it immediately deselects it.
This is a delightful take on a style of UI I really love. Separating the UI logic from drawing with a set of draw commands is an excellent and very versatile idea - I first saw it in microui, and the separation allowed me to easily use the library in the browser using WASM and Canvas2D. (https://rxi.github.io/microui_v2_an_implementation_overview....)
Also, doing layout in WASM and rendering to HTML is a great idea that I can't believe I never thought of before.
Okey i was going to complain about what's the point of doing it in C, when it could be done more safely in Haskell/OCaml
But 2000 lines of C, and no dependencies is pretty cool!
There is also taffy (Rust) which has WIP C bindings.
It's a good first draft. I do find it a shame that the HTML output is only div elements. I think a little accessibility would go a long way. I also can't select text in many places before some re-render de-selects before I can hit control-c.
Serious question: am I the only one who finds writing a webpage like this to be a little too much (even if the concept is cool):
void LandingPageDesktop() { CLAY(CLAY_ID("LandingPage1Desktop"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT({ .min = windowHeight - 70 }) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { .x = 50 } })) { CLAY(CLAY_ID("LandingPage1"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) { CLAY(CLAY_ID("LeftText"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_PERCENT(0.55f) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance."), CLAY_TEXT_CONFIG({ .fontSize = 56, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED })); CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(32) } })) {} CLAY_TEXT(CLAY_STRING("Clay is laying out this webpage right now!"), CLAY_TEXT_CONFIG({ .fontSize = 36, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE })); } CLAY(CLAY_ID("HeroImageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_PERCENT(0.45f) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 })) { LandingPageBlob(1, 32, COLOR_BLOB_BORDER_5, CLAY_STRING("High performance"), CLAY_STRING("/clay/images/check_5.png")); LandingPageBlob(2, 32, COLOR_BLOB_BORDER_4, CLAY_STRING("Flexbox-style responsive layout"), CLAY_STRING("/clay/images/check_4.png")); LandingPageBlob(3, 32, COLOR_BLOB_BORDER_3, CLAY_STRING("Declarative syntax"), CLAY_STRING("/clay/images/check_3.png")); LandingPageBlob(4, 32, COLOR_BLOB_BORDER_2, CLAY_STRING("Single .h file for C/C++"), CLAY_STRING("/clay/images/check_2.png")); LandingPageBlob(5, 32, COLOR_BLOB_BORDER_1, CLAY_STRING("Compile to 15kb .wasm"), CLAY_STRING("/clay/images/check_1.png")); } } } }
Source: https://github.com/nicbarker/clay/blob/35d72e5fba6872be48d15...
cool stuff! selectable text is a MUST in the browser for me. In clients and apps that do not need that or can provide it themselves, this seems to be a very nice and tiny solution.
Right and middle click on links behaves like a left click on the website.
So cool. I wonder if it'd work for a Raspberry Pi Pico + https://pimoroni.com/picodisplay or similar devices.
The d for debugging is so cool. Fantastic library. C is also such a good language. If I wasn't doing Rust, I would have gone back to C.
Would be fun to combine this with the single-file Impeller header from the Flutter people.
The API approach could be implemented extremely cleanly in Clojure and Java, and then the whole thing would be runtime-dynamic, since Clojure generates new Java functions on the fly, and the JVM's JIT makes them fast.
If anyone wants a fun project over the holidays…
This looks pretty cool, but from the page I can't tell if there's any interactivity supported...there's a button example but it seems to have no click handler?
Okay, from the examples there's something like this:
if (isMouseDown && !scrollbarData.mouseDown && Clay_PointerOver(Clay_GetElementId(CLAY_STRING("ScrollBar")))) {
I'm not a frontend person. Can anyone explain why this is better than using CSS directly or a CSS framework/library? Seems like added complexity when there are already hundreds of CSS frameworks available that seem like they do the same thing.
Using CSS translations to place elements on the page is... cursed to say the least. It's probably why text selection works (assuming it qualifies as working) in such a weird way when the cursor goes between blocks.
So cool! For some reason navigating to Github/Discord by clicking the links is slow on my phone (old galaxy s20fe). The click highlight of the button is normal, just going to the sites is slow.
Looks impressive! What are the connection/comparison with imgui though?
My question may be to obvious but, how can you incorporate js to mutate your layout based on user interaction and api calls? Do you have a dynamic website example?
The canvas renderer tried on iPhone feels weird. The scroll is completely different from regular, also no scroll bounce. That alone is a deal breaker
Getting an empty, cream-rose-colored page, followed by a warning that the script on the page is slowing the browser down with an offer to stop the script. Just FYI.
Excellent. If these compiled data structures were the web standard instead of HTML, www would be ridiculously fast.
I'm not proficient in C. Does this "just work" or do you need to provide some sort of rendering environment like SDL?
Highlighting is degraded for me running on Firefox, it's wigging out every time I nudge my cursor
Press "d" to debug didn't work for me. On Chrome in Mac.
the inspector at the end was a neat surprise! I had some issues trying to build the examples on windows but I think it's an opportunity to contribute to the project
This is basically what Flutter web is doing - its own canvas, rendering UI, and leveraging Wasm
Oh sweet jesus, the preprocessor? Go away.
Cool, so if i look for 'clay', i'll find your lib?
why it's not written in rust?! now every cool kid writes in rust)) Jokes aside this is nice!
Looks very nice, I just watch a great YT video from the developer here https://www.youtube.com/watch?v=DYWTw19_8r4