Clay – UI Layout Library

ivmoreau | 420 points

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/cssgrid
elcritch | 2 days ago

Just 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.

bee_rider | 2 days ago

Looks very nice, I just watch a great YT video from the developer here https://www.youtube.com/watch?v=DYWTw19_8r4

mega-tux | 2 days ago

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.

jasonjmcghee | 2 days ago

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.

bvisness | 2 days ago

Excellent. If these compiled data structures were the web standard instead of HTML, www would be ridiculously fast.

Naru41 | 2 hours ago

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?

isagues | 3 hours ago

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!

dgan | 2 days ago

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.

wishinghand | a day ago

There is also taffy (Rust) which has WIP C bindings.

https://crates.io/crates/taffy

virtualritz | 2 days ago

Right and middle click on links behaves like a left click on the website.

b3orn | a day ago

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...

ahmedfromtunis | 2 days ago

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.

chromanoid | 2 days ago

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.

steve-chavez | 15 hours ago

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.

citizenpaul | a day ago

So cool. I wonder if it'd work for a Raspberry Pi Pico + https://pimoroni.com/picodisplay or similar devices.

britannio | 2 days ago

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.

thiht | a day ago

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")))) {
zibzob | 2 days ago

Looks impressive! What are the connection/comparison with imgui though?

wangii | a day ago

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

m3kw9 | 4 hours ago

Highlighting is degraded for me running on Firefox, it's wigging out every time I nudge my cursor

gnarlouse | a day ago

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.

huhtenberg | 2 days ago

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

mendor | a day ago

I'm not proficient in C. Does this "just work" or do you need to provide some sort of rendering environment like SDL?

xhrpost | 2 days ago

Press "d" to debug didn't work for me. On Chrome in Mac.

fuzzythinker | 2 days ago

This is basically what Flutter web is doing - its own canvas, rendering UI, and leveraging Wasm

sgt | a day ago

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…

erichocean | 21 hours ago

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.

ilrwbwrkhv | 2 days ago

Oh sweet jesus, the preprocessor? Go away.

NoZZz | a day ago

Cool, so if i look for 'clay', i'll find your lib?

noamchompsit | 2 days ago

why it's not written in rust?! now every cool kid writes in rust)) Jokes aside this is nice!

inson | a day ago