[HN Gopher] Clay - UI Layout Library
       ___________________________________________________________________
        
       Clay - UI Layout Library
        
       Author : ivmoreau
       Score  : 357 points
       Date   : 2024-12-19 16:36 UTC (1 days ago)
        
 (HTM) web link (www.nicbarker.com)
 (TXT) w3m dump (www.nicbarker.com)
        
       | mega-tux wrote:
       | Looks very nice, I just watch a great YT video from the developer
       | here https://www.youtube.com/watch?v=DYWTw19_8r4
        
         | rubymamis wrote:
         | It's so rare to see such a clear and intuitive explanation.
         | This video is amazing.
        
           | porjo wrote:
           | This. It is a rare and unique thing for the author to a) have
           | the skills to put together such a presentation and b) take
           | the time to do so. Thankyou.
        
         | riazrizvi wrote:
         | The developer is rediscovering the concept of a GUI library.
         | The modern variant is the mouse-driven GUI developed by Xerox
         | in the 1970s (and later commercialized by them as Xerox Star)
         | which Jobs famously copied to create Apple's Lisa, and Gates
         | famously mimicked to create MS Windows. Since they determine
         | the look and feel of a platform and their design determines the
         | ease with which developers can create apps for the platform,
         | GUI frameworks became pivotal to platform wars across all sorts
         | of products, from OSs to browsers, graphics engines and
         | anything else whose success was determined largely by the
         | interface developer experience.
        
           | keyle wrote:
           | I'm a gray beard like you probably but I disagree with this
           | statement.
           | 
           | This library makes use of modern composable components, is
           | declarative driven and not imperative; and doesn't do
           | immediate rendering in all cases.
           | 
           | It can target incredibly different backends, e.g.
           | DOM/canvas/raylib.
           | 
           | All of this in modern C as a `.h` library alone.
           | 
           | These are great features and not just a 'youngster discovers'
           | project.
        
             | riazrizvi wrote:
             | Maybe a README that shows how it works and what it does
             | would help. As it is it is quite opaque IMO, with just a
             | few high level comments.
        
               | fredrikholm wrote:
               | It's in the repo; landing pages are usually for
               | generating interest.
               | 
               | https://github.com/nicbarker/clay
        
               | contrast wrote:
               | The README for the project is one of the most detailed
               | READMEs I've ever seen. The landing page for the website
               | has as much detail as you can reasonably expect, even
               | including a couple of feature demos. There are clear
               | links to the docs and the code.
               | 
               | The developer has clearly put a lot of thought into this
               | content. Worth taking a second or two to see what's
               | available before criticising it.
        
           | coolgoose wrote:
           | I swear to god, I thought this is AI generated response.
        
       | chromanoid wrote:
       | 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.
        
         | dannyobrien wrote:
         | it's weird to watch it break text selection/copy-and-paste :
         | feels like it might be fixable, though.
         | 
         | I'm a stuck record on this, but I really feel like the
         | regressions in clipboard universality are one of most
         | understated losses of UI shifts in the last few years (along
         | with linkability and embedding)
        
           | __m wrote:
           | Should that be part of a layout engine though? I'd expect to
           | insert a tree of nodes with styling information that affect
           | layout and receive a tree with calculated x, y, width and
           | height for its elements.
        
       | britannio wrote:
       | So cool. I wonder if it'd work for a Raspberry Pi Pico +
       | https://pimoroni.com/picodisplay or similar devices.
        
       | zibzob wrote:
       | 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")))) {
        
       | jasonjmcghee wrote:
       | 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.
        
         | rmac wrote:
         | this happens to me on mobile using all chromium and gecko based
         | browsers
         | 
         | what's also interesting is how much worse Firefox is at
         | rendering this page; example =>
         | 
         | https://imgur.com/a/DNYe2WN
        
           | rmgk wrote:
           | If you mean the text position that overflows, that seems to
           | be computed by the library. The same happens in chromium at
           | some resolutions.
        
         | Reubend wrote:
         | It's probably because it does it a full reset every frame, and
         | there's an animation playing.
        
       | ahmedfromtunis wrote:
       | 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...
        
         | dvt wrote:
         | If you don't use some kind of layouting language (like
         | XML/HTML), this is inevitably what you will _always_ end up
         | with. See: AWT[1], SWT[2], Swing[3], Qt[4]+, Fyne[5], etc.,
         | etc., etc.
         | 
         | [1]
         | https://docs.oracle.com/javase/7/docs/api/java/awt/GridLayou...
         | 
         | [2] https://github.com/eclipse-
         | platform/eclipse.platform.swt/blo...
         | 
         | [3] https://stackoverflow.com/a/12867862/243613
         | 
         | [4]
         | https://stackoverflow.com/questions/37304684/qwidgetsetlayou...
         | 
         | + Qt actually has a (XML-based, I think) layouting system, but
         | you can also just do stuff in code, which is generally
         | discouraged.
         | 
         | [5]
         | https://gist.github.com/ledongthuc/9686787fe51bbe763fa1e5038...
        
           | righthand wrote:
           | Qt has uic xml layout engine which was cumbersome to use, you
           | weren't discouraged from using c++ classes instead. The
           | discouragement came later when Qt shifted towards qml (a bad
           | shift as it's just as unweildly, imo), now they discourage
           | writing qml in c++ because the qml engine can get out of
           | sync. Qt can prevent this but they want you to pay for a
           | premium license for it. Slint is a sister to qt that does not
           | have this restriction afaik.
           | 
           | I wish there would be an elegant c++ class/function based ui
           | framework again.
        
             | OvbiousError wrote:
             | Agreed that a C++ API for qml would be great. qml by itself
             | is great though, I don't see why it is unweildy. If
             | anything it's unpolished, there is stuff that is more
             | difficult than it should be, but it's miles ahead of what
             | there was before imo.
        
           | CyberDildonics wrote:
           | It's not difficult or disorganized to layout GUIs in a
           | programming language. HTML exists as an alternative to having
           | nothing. If you have a programming language you can give the
           | data to the GUI library directly without having to learn a
           | new markup language, have the bloat of a new markup language
           | or learn the quirks a new markup language. You can also put
           | format it and put newlines in there.
        
             | mvc wrote:
             | The thing is, most GUIs by necessity involve fairly deep
             | hierarchies of graphical objects so you're either going to
             | have deeply nested calls like this, or you're going to
             | scatter the fragments across a number of files in a way
             | that they need to be reassembled in the reader's head in
             | order to understand what's going on.
        
               | CyberDildonics wrote:
               | _most GUIs by necessity involve fairly deep hierarchies
               | of graphical objects_
               | 
               | First, this isn't really true. You might typically have a
               | window, a container, a layout object and then your gui
               | components.
               | 
               | Second you don't need nested calls, you just add one
               | component to another.
               | 
               |  _or you 're going to scatter the fragments across a
               | number of files_
               | 
               | Why would that be true?
               | 
               |  _they need to be reassembled in the reader 's head in
               | order to understand what's going on._
               | 
               | This is a bizarre way to make a GUI let alone thinking
               | it's necessary. Where is this idea coming from?
               | 
               | FLTK, JUCE, Tk, ImGUI, Swing and Qt are not like this at
               | all.
        
         | lylejantzi3rd wrote:
         | It's not all that much different than html or even React. You
         | can assign each part to named functions and turn it into
         | something more like this:
         | LandingPageDesktop(landingPageDesktopId,
         | landingPageDesktopProperties) {
         | LandingPage(landingPageId, landingPageProperties) {
         | LeftText() {               etc...             }           }
         | }
         | 
         | The real issue is trying to represent graphical objects, and
         | the relationship between those objects, with text. Graphical
         | builders/RAD tools seem like such an obvious solution, but that
         | approach has largely been abandoned.
        
       | ilrwbwrkhv wrote:
       | 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.
        
         | Diti wrote:
         | > C is also such a good language. If I wasn't doing Rust, I
         | would have gone back to C.
         | 
         | Wouldn't you try Zig instead?
        
           | ilrwbwrkhv wrote:
           | I'm not sure I would have. There is a terseness in C which
           | zig lags. I think. To be fair, I haven't played with Zig that
           | much.
        
       | huhtenberg wrote:
       | 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.
        
       | virtualritz wrote:
       | There is also taffy (Rust) which has WIP C bindings.
       | 
       | https://crates.io/crates/taffy
        
       | fuzzythinker wrote:
       | Press "d" to debug didn't work for me. On Chrome in Mac.
        
       | dgan wrote:
       | 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!
        
         | PittleyDunkin wrote:
         | Hey at least this way other languages can use it
        
       | bee_rider wrote:
       | 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.
        
         | spiderfarmer wrote:
         | Text selection and zoomng is also problematic.
        
           | anonzzzies wrote:
           | Zooming is indeed an issue but selection works fine for me on
           | safari ios.
        
             | Klaster_1 wrote:
             | On Windows/Firefox, text selection doesn't work. Also not
             | working is Home/End and wheel click scrolling. Cool project
             | otherwise.
        
           | red_trumpet wrote:
           | My Firefox on Linux zooms fine with both renderers. Text
           | selection doesn't work though. Also the cursor doesn't adapt
           | when hovering text, a button etc.
        
           | wffurr wrote:
           | It won't help with dark mode, but the canvas-place-element
           | proposal (https://github.com/WICG/canvas-place-element)
           | should allow those interactions on canvas-rendered text
           | backed by a text element placed under the canvas.
        
           | sgt wrote:
           | In Chrome, it selects sometimes but sometimes it seems to
           | unselect itself, probably due to the animation happening
           | somewhere else on the page.
        
         | sgt wrote:
         | The HTML renderer is definitely faster in Chrome. Why is that,
         | I wonder? The Canvas one is also reasonably fast, but noticable
         | in that "High performance" animation and also when scrolling.
        
         | varispeed wrote:
         | It says:
         | 
         | > There's even an HTML renderer - you're looking at it right
         | now!
         | 
         | Jokes on them, I already switched to Canvas renderer when I
         | read it.
        
       | noamchompsit wrote:
       | Cool, so if i look for 'clay', i'll find your lib?
        
         | recursive wrote:
         | You mean, like, using a search engine? I don't think anyone
         | here is in any special position to be able to answer that
         | question.
        
         | esperent wrote:
         | "clay ui" or "clay layout" will find it, which seems ok to me.
        
       | elcritch wrote:
       | 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
        
         | nicoburns wrote:
         | Cool! I also have a standalone implementation of CSS Grid [1].
         | Implemented in Rust in my case (and we also support Flexbox and
         | Block layout). Looks like the licenses are both MIT (although
         | you may want to add a LICENSE file to make that easier to find)
         | so feel free to steal bits if you want. We aim to be fully web
         | compatible, although we're not quite there yet.
         | 
         | One thing we have that you may be particularly interested is a
         | reasonably substantial test suite. The tests are defined as
         | HTML snippets that we run through Chrome using webdriver in
         | order the scrape (hopefully) correct assertions, and then
         | format into pure-code unit tests. If you wanted to you could
         | write your own test generator and reuse our snippets. (this
         | test infrastructure is also partially shared with Yoga [2], the
         | C++ Flexbox implementation that powers React Native)
         | 
         | 1: https://github.com/DioxusLabs/taffy
         | 
         | 2: https://github.com/facebook/yoga
        
           | elcritch wrote:
           | Hey thanks! That's awesome and great to see other
           | implementations. Figuring out test cases is half the battle
           | and I've really only done the basics. I'll definitely look to
           | stealing things. ;)
           | 
           | > Looks like the licenses are both MIT (although you may want
           | to add a LICENSE file to make that easier to find) so feel
           | free to steal bits if you want.
           | 
           | Good call, I'll add the license file.
        
         | c-smile wrote:
         | Correct CSS grid layout calculation is about solving system of
         | equations and constraints. In simple cases, when there are no
         | spanned cells (like in flexbox), it can be done relatively
         | trivially.
         | 
         | Otherwise solving that system is far from being trivial, you
         | will need simplex solver or the like, for example
         | https://constraints.cs.washington.edu/solvers/cassowary-toch...
        
           | nicoburns wrote:
           | You definitely don't need a general constraint solver for CSS
           | Grid. The algorithm (including for cases where there are
           | spanned cells) is well defined in the spec [1], and can be
           | translated directly into code.
           | 
           | 1: https://www.w3.org/TR/css-grid-1/#algo-content
        
       | xhrpost wrote:
       | I'm not proficient in C. Does this "just work" or do you need to
       | provide some sort of rendering environment like SDL?
        
         | thot_experiment wrote:
         | This is just a layout library, it doesn't do any rendering at
         | all.
        
         | nine_k wrote:
         | No, the library is about doing the layout only.
         | 
         | Yes, the repo offers a couple of example renderers.
         | 
         | The idea is that you already have a rendering pipeline (e.g. in
         | your game engine), but want to lay out more complex UIs in it.
         | Then you can use this library to make nice settings / chat /
         | stats / whatever screens, or even render realistic content onto
         | screens of in-game computers, pages of books, etc.
        
       | bvisness wrote:
       | 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.
        
       | wangii wrote:
       | Looks impressive! What are the connection/comparison with imgui
       | though?
        
       | thiht wrote:
       | 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.
        
       | gnarlouse wrote:
       | Highlighting is degraded for me running on Firefox, it's wigging
       | out every time I nudge my cursor
        
       | sgt wrote:
       | This is basically what Flutter web is doing - its own canvas,
       | rendering UI, and leveraging Wasm
        
       | b3orn wrote:
       | Right and middle click on links behaves like a left click on the
       | website.
        
         | 7bit wrote:
         | Instant recycle bin.
        
       | inson wrote:
       | why it's not written in rust?! now every cool kid writes in
       | rust)) Jokes aside this is nice!
        
       | citizenpaul wrote:
       | 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.
        
         | hoppp wrote:
         | Maybe you want the compile some C to wasm and render to canvas.
         | Then it's pretty neat.
        
         | mdarens wrote:
         | This isn't really meant to replace such things an environment
         | where you have a rendering engine that supports CSS-- I think
         | demoing it on the page is more for showing off how portable it
         | is with WASM. Off the top of my head, a few uses for this:
         | 
         | - Mapping components or structured document data with something
         | like MDX or slate on to Clay components to render in different
         | contexts outside the browser reasonably closely to what shows
         | up in a browser preview, for example content for HUDs, in-world
         | display panels or documents in games, or batch rendering
         | printed documents
         | 
         | - Layout for UI where something like Electron or React Native
         | would be overkill, or isn't supported
        
       | wishinghand wrote:
       | 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.
        
       | mendor wrote:
       | 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
        
       | NoZZz wrote:
       | Oh sweet jesus, the preprocessor? Go away.
        
       | erichocean wrote:
       | 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...
        
       ___________________________________________________________________
       (page generated 2024-12-20 23:01 UTC)