New Features
Replace Element Macros with a Single Configuration Struct
We've removed the majority of the configuration macros in favour of a large config struct that you pass to CLAY
.
You can find exhaustive documentation of this struct and its fields in the README.
// Before - macros
CLAY(
CLAY_ID("FloatingContainer"),
CLAY_LAYOUT({
.sizing = {
.width = CLAY_SIZING_FIXED(300),
.height = CLAY_SIZING_FIXED(300)
},
.padding = { 16, 16, 16, 16 }
}),
CLAY_FLOATING({
.zIndex = 1,
.attachment = {
CLAY_ATTACH_POINT_CENTER_TOP,
CLAY_ATTACH_POINT_CENTER_TOP
},
.offset = { 0, 0 }
}),
CLAY_BORDER_OUTSIDE({ .color = {80, 80, 80, 255}, .width = 2 }),
CLAY_RECTANGLE({ .color = {140,80, 200, 200 }}
) {
// children
}
// After - single struct
CLAY({
.id = CLAY_ID("FloatingContainer"),
.layout = {
.sizing = {
.width = CLAY_SIZING_FIXED(300),
.height = CLAY_SIZING_FIXED(300)
},
.padding = { 16, 16, 16, 16 }
},
.backgroundColor = { 140, 80, 200, 200 },
.floating = {
.attachTo = CLAY_ATTACH_TO_PARENT,
.zIndex = 1,
.attachPoints = {
CLAY_ATTACH_POINT_CENTER_TOP,
CLAY_ATTACH_POINT_CENTER_TOP
},
.offset = { 0, 0 }
},
.border = {
.width = { 2, 2, 2, 2 },
.color = { 80, 80, 80, 255 }
},
}) {
// children
}
The two main benefits we get from this approach are:
- The available configuration options are naturally discoverable for those using intellisense just by pressing
.
insideCLAY({ })
, whereas previously you had to look up the macros in the documentation. - You can define the configuration for an entire element and save it as a struct:
Clay_ElementDeclaration buttonStyle = (Clay_ElementDeclaration) {
.layout = { .padding = { .left = 16, .right = 16 } },
.backgroundColor = COLOR_RED,
.cornerRadius = { 16, 16, 16, 16 }
}
// later
CLAY(buttonStyle) {
// button contents
}
// Or return a declaration from a function
Clay_ElementDeclaration GetButtonStyle(bool hovered) {
return (Clay_ElementDeclaration) {
.layout = { ... },
.backgroundColor = hovered ? BLUE : RED
};
}
// Generate element style from template
CLAY(GetButtonStyle(Clay_Hovered())) {
// button contents
}
"Context" support (i.e. Multiple independent Clay instances & groundwork for multithreading support)
Thanks to some great discussions in the Clay discord and great work by @monodop here: #174 Clay now supports creation and management of multiple "instances" which are separate from one another. This is not only useful for systems with separate internal "windows" requiring different layout trees, but also paves the way for us to support running these instances on separate threads.
An example of the same layout rendered twice by two separate Clay instances
For more information, see the Multi Context Example
Error Handler
Clay now requires that you bind an error handler callback function when calling Clay_Initialize
. This allows us to catch and report some common mistakes such as forgetting to bind a text measurement function with Clay_SetMeasureText
.
Clay_GetElementData
for querying bounding box data
A new function, Clay_GetElementData(Clay_ElementId id)
is available for directly looking up the final calculated bounding box of an element by ID.
.textAlignment
support for CLAY_TEXT_CONFIG
Wrapped text can now be aligned to LEFT, CENTER or RIGHT using the .textAlignment
field of CLAY_TEXT_CONFIG
.
MSVC Support & C99 Compliance
Thanks to some tireless work from @FintasticMan, Clay can now be compiled using MSVC with C11, 17, and 23, has much closer strict C99 compliance, and compiles with -Wextra
and -Wpedantic
.
New Renderers
Thanks to some hard work from our contributors, there are a number of new example renderers in 0.13, including:
- SDL2
- SDL3
- Cairo
New Language Bindings
Thanks to some hard work from our contributors, there are a number of new language bindings in 0.13, including:
Zig
https://codeberg.org/Zettexe/clay-zig
https://github.com/johan0A/clay-zig-bindings
Rust
https://github.com/clay-ui-rs/clay
https://crates.io/crates/clay-layout
C#
https://github.com/Orcolom/clay-cs
C++
https://github.com/TimothyHoytBSME/ClayMan
Deprecations
The preprocessor defines used for adding additional fields to element configuration structs such as CLAY_EXTEND_CONFIG_RECTANGLE
have been removed in favour of the new .userData
pointer field of Clay_ElementDeclaration
. This was out of necessity and can be explained in more detail upon request π
Migration Guide
- Wrap the inside of the
CLAY(...)
macro in braces for the new formCLAY({ ... })
- CLAY(
+ CLAY({
CLAY_ID(...),
CLAY_RECTANGLE({ ... }),
CLAY_BORDER({ ... }),
CLAY_FLOATING({ ... })
- )
+ })
- Mass rename the following macros:
CLAY_BORDER({ ... })
CLAY_IMAGE({ ... })
CLAY_SCROLL({ ... })
CLAY_FLOATING({ ... })
CLAY_CUSTOM({ ... })
into struct fields of the form .border = { ... }
, .floating = { ... }
etc
CLAY({
CLAY_ID(...),
CLAY_RECTANGLE({ ... }),
- CLAY_BORDER({ ... }),
+ .border = { ... },
- CLAY_FLOATING({ ... })
+ .floating = { ... },
})
- Replace the
CLAY_ID
macro with the struct field.id = CLAY_ID
CLAY({
- CLAY_ID(...),
+ .id = CLAY_ID(...),
CLAY_RECTANGLE({ ... }),
.border = { ... },
.floating = { ... }
})
- Replace
CLAY_RECTANGLE
macros with two struct fields,.backgroundColor
and.cornerRadius
Previous, fields like .cornerRadius
would need to be repeated for rectangle, image, and border configuration macros. .backgroundColor
and .cornerRadius
are now shared fields that affect multiple render commands, and are declared once at the top level.
CLAY({
.id = CLAY_ID(...),
- CLAY_RECTANGLE({ .color = COLOR_RED, .cornerRadius = { 10, 10, 10, 10 } }),
+ .backgroundColor = COLOR_RED,
+ .cornerRadius = { 10, 10, 10, 10 },
.border = { ... },
.floating = { ... }
})
- Padding is now represented by four values, not just two
Padding in 0.12 was represented as a mirrored .x, .y
pair. It's been changed in 0.13 to a more standard .left, .right, .top, .bottom
.
You'll need to update your padding to match the new structure.
- CLAY({ .layout = { .padding = { 8, 12 } });
+ CLAY({ .layout = { .padding = { 8, 8, 12, 12 } });
// Designated initializers
- CLAY({ .layout = { .padding = { .x = 8, .y = 12 } });
+ CLAY({ .layout = { .padding = { .left = 8, .right = 8, .top = 12, .bottom = 12 } });
- Depending on your language and compiler,
CLAY_SIZING_GROW
might need to be passed0
when you don't specify min and max size:
- CLAY({ .layout = { .width = CLAY_SIZING_GROW() } });
+ CLAY({ .layout = { .width = CLAY_SIZING_GROW(0) } });
- Update border declarations
Borders now share a single color, and use the shared .cornerRadius
from the outer declaration.
- CLAY_BORDER({ .left = { 20, COLOR_BLUE }, .right = { 20, COLOR_BLUE }, .bottom = { 20, COLOR_BLUE }, .cornerRadius = { 10, 10, 10, 10 } })
+ .cornerRadius = { 10, 10, 10, 10 },
+ .border = { .width = { .left = 20, .right = 20, .bottom = 20 }, .color = COLOR_BLUE }
- Changes to Floating Elements
Replacing CLAY_FLOATING
, The .floating
config of the declaration struct now has a new field, .attachTo
, which can be one of several values:
CLAY_ATTACH_TO_NONE (default)
CLAY_ATTACH_TO_PARENT
CLAY_ATTACH_TO_ELEMENT_ID
CLAY_ATTACH_TO_ROOT
Unlike previously where just calling CLAY_FLOATING
was enough to switch an element to floating mode, now .attachTo
has to be set to some value other than the default NONE
. CLAY_ATTACH_TO_PARENT
is the old default behaviour, CLAY_ATTACH_TO_ELEMENT_ID
requires that you set a parentId
to attach the floating element to, and the new CLAY_ATTACH_TO_ROOT
option allows you to position the element relative to the root of the layout (i.e. the entire screen), by using the .offset
field.
// Attach to parent
- CLAY_FLOATING({ .offset = { 12, 12 } });
+ .floating = { .attachTo = CLAY_ATTACH_TO_PARENT, .offset = { 12, 12 } };
// Attach to specific ID
- CLAY_FLOATING({ .parentId = CLAY_ID("targetElement") });
+ .floating = { .attachTo = CLAY_ATTACH_TO_ELEMENT_ID, .parentId = CLAY_ID("targetElement") };
-
Clay_SetMeasureTextFunction
must now be called afterClay_Initialize
-
Clay_Initialize
now requires an error handler callback.
void HandleClayErrors(Clay_ErrorData errorData) {
// See the Clay_ErrorData struct for more information
printf("%s", errorData.errorText.chars);
switch(errorData.errorType) {
// etc
}
}
- Clay_Initialize(arena, (Clay_Dimensions) { screenWidth, screenHeight });
+ Clay_Initialize(arena, (Clay_Dimensions) { screenWidth, screenHeight }, (Clay_ErrorHandler) { HandleClayErrors });
- Update to new
Clay_MeasureTextFunction
signature
Since 0.12, the function signature of the user providedClay_MeasureText
has changed for consistency and additional features.
- Clay_Dimensions Raylib_MeasureText(Clay_String *text, Clay_TextElementConfig *config) {
+ Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) {
- Update custom renderer implementations
The structure ofClay_RenderCommand
has changed significantly, and should offer better performance and convenience. Custom renderers will need to be updated to handle the new structure.
The easiest way to get started would be to look at the diff of the updated Raylib Renderer, and the new README documentation for Clay_RenderCommand
Bug Fixes
0.13 contains a large number of bug fixes both to edge case handling and the core layout algorithm, but it's worth specifically highlighting that elements now shrink much more gracefully & sensibly than they did in 0.12:
Special Thanks
Special thanks to @emoon, @FintasticMan, @monodop, @bullno1 and @TimothyHoytBSME for their significant contributions to this release, not just from a code perspective but also for their tireless work helping people in the Discord and on Github issues. Couldn't have done it without you!
New Contributors
- @27justin made their first contribution in #47
- @OleksiiBulba made their first contribution in #55
- @AMurkin made their first contribution in #59
- @mrneo240 made their first contribution in #78
- @CrackedPixel made their first contribution in #109
- @FintasticMan made their first contribution in #81
- @juniorrantila made their first contribution in #130
- @SuperOptimizer made their first contribution in #123
- @St0wy made their first contribution in #134
- @peter15914 made their first contribution in #153
- @bullyingteen made their first contribution in #162
- @davidstyrbjorn made their first contribution in #167
- @monodop made their first contribution in #174
- @Funto made their first contribution in #178
- @Mathys-Gasnier made their first contribution in #125
- @ppebb made their first contribution in #208
- @Zettexe made their first contribution in #210
- @LiquidityC made their first contribution in #107
- @emoon made their first contribution in #212
- @TimothyHoytBSME made their first contribution in #205
- @ArnauNau made their first contribution in #219
- @CJFEdu made their first contribution in #216
- @noflashbang made their first contribution in #233
- @radiant64 made their first contribution in #232
- @steviegt6 made their first contribution in #245
- @nadako made their first contribution in #252
- @Orcolom made their first contribution in #247
- @FelixBreitweiser made their first contribution in #255
Full List of Changes
- [Documentation] docs: remove some inconsistencies with current API by @27justin in #47
- [Core] Forward declare Clay__OpenTextElement by @bullno1 in #49
- [Renderers/Cairo] Include new cairo renderer by @27justin in #48
- [Core] Fix text cache overflow by @nicbarker in #51
- [Core] Improve overflow handling / CLAY_MAX_ELEMENT_COUNT exceeded by @nicbarker in #52
- [Core] Fix: moved CLAY__MIN and CLAY__MAX to public macros by @OleksiiBulba in #55
- [Renderers/HTML] Implement native scroll containers in HTML renderer by @nicbarker in #54
- [Renderers/Raylib] Added window dimensions and title to Clay_Raylib_Initialize function by @OleksiiBulba in #56
- [Documentation] Fix variable name in README.md by @AMurkin in #59
- [Core] Allow floating configuration to capture pointer by @nicbarker in #66
- [Core] fix: move internal types to stdint specific. by @mrneo240 in #78
- [Core] Implement Error Handler / Callback by @nicbarker in #105
- [Renderers/raylib] Update files for v5.5 by @CrackedPixel in #109
- [Core] Fix a couple of standards-compliance issues with C99 by @FintasticMan in #81
- [Renderers/SDL2] Create initial SDL2 renderer by @nicbarker in #115
- [Examples/Intro] Fix NULL pointer deref due to huuge malloc by @FintasticMan in #120
- [Core] Add Clay_IsDebugModeEnabled() by @juniorrantila in #130
- [Core] Fix more C99 compliance issues by @FintasticMan in #118
- [Compilers] C projects should use C flags rather than CXX flags by @SuperOptimizer in #123
- [Compilers] C++ projects should use CXX flags by @SuperOptimizer in #136
- [Renderers/Cairo] Add FindCairo.cmake by @SuperOptimizer in #122
- [Compilers] Fixed compilation when using Clang on Windows by @St0wy in #134
- [Bindings/Odin] Update Odin bindings to latest by @nicbarker in #151
- [Core] Simplify CLAY macro by @FintasticMan in #119
- [Core] Standardise number types to int32_t for array indices, lengths and capacities by @nicbarker in #152
- [Core] Fix NULL pointer dereference when parent of floating container is invalid ID by @peter15914 in #153
- [Renderers/Web] treat RenderCommand.commandType as uint8_t instead of uint32_t by @bullyingteen in #162
- [Core] Bug in text wrapping at very narrow widths by @bullyingteen in #163
- [Core] Fix local id calculation by @bullno1 in #50
- [Core] Fix errors due to cast to same non-trivial type by @FintasticMan in #155
- [Core] Fix default struct initialiser in C++ by @FintasticMan in #143
- [Documentation] Updated example for
Clay_SetPointerState
by @davidstyrbjorn in #167 - [Layout] Improve shrink size distribution by @nicbarker in #173
- [Documentation] Updated example for Clay_SetPointerState by @davidstyrbjorn in #169
- [Core] Add check for supported C/C++ versions by @FintasticMan in #144
- [Core] Multi instance support by @monodop in #174
- [Core] Remove
##__VA_ARGS__
by @FintasticMan in #150 - [Compilers] Fix MSVC compilation with CMake by @Funto in #178
- [Documentation] Summary & Readability improvement by @Mathys-Gasnier in #125
- [Core] Fix text wrapping handling with explicit newline characters by @nicbarker in #192
- [Core] Add a function to reset text measurement cache by @monodop in #181
- [Core] [Breaking] Split padding values into left, right, top, bottom by @nicbarker in #195
- [Core] Add API to query element bounding boxes by @nicbarker in #199
- [Core] Don't divide zero by zero by @mikejsavage in #200
- [Renderers/SDL2] Extend SDL2 Renderer and SDL2-video-demo by @ppebb in #208
- [Bindings/Zig] Add external link to zig bindings by @Zettexe in #210
- [Renderers/SDL3] Adds an example using SDL3 as a renderer by @LiquidityC in #107
- [Core] SetMeasureText and SetQueryScrollOffset takes userData by @emoon in #212
- [Core] Convert measureText pointer to value string slice by @nicbarker in #214
- [Examples/clay-video-demo] fixed video demo padding by @TimothyHoytBSME in #205
- [Renderers/SDL3] Add rounded corners rectangle functionality by @ArnauNau in #219
- [Bindings/C++] Link and information for ClayMan, a C++ wrapper library for clay by @TimothyHoytBSME in #218
- [Renderers/SDL3] Add borders and rounded borders functionality. by @ArnauNau in #220
- [CMake] Make Examples Optional in CMAKE by @CJFEdu in #216
- [Core] Add z-index and string base to Render Commands by @nicbarker in #227
- [Core] Fix: Clay_MinMemorySize() and Clay_Initialize() now report same memory size when using non-default MaxElementCount by @noflashbang in #233
- [Renderers/SDL2] Don't take addresses of temporaries. by @radiant64 in #232
- [Core] Replace generated arrays with macro declarations, align cache lines to 64 bytes by @nicbarker in #235
- [Core] Add option to hash text contents to text config by @nicbarker in #238
- [Core] Copy elementId in Clay__AddHashMapItem() in case underlying stringId has changed by @monodop in #239
- [Core] Fix int conversion errors in msvc by @monodop in #242
- [Core] Replace config macros with a single unified configuration struct by @nicbarker in #240
- [Core] add CLAY_DISABLE_SIMD flag to conditionally disable SIMD includes by @johan0A in #251
- [Renderers/SDL2] Add rounded rectangle support to sdl2 renderer; feature-completes sdl2 renderer by @steviegt6 in #245
- [Bindings/Odin] Add get/set current context method to Odin bindings by @nadako in #252
- [Bindings/csharp] Create csharp bindings README by @Orcolom in #247
- [Core] Fix a bug when trying to enable debug view with too many elements in the layout. by @FelixBreitweiser in #255