How to Install and Use Clay: A Guide to High-Performance UI Design 🚀
Monday, Dec 23, 2024 | 8 minute read
Revolutionizing UI Design with Speed and Simplicity! 🚀 This innovative layout library for C language boasts microsecond-level performance, flexibility, and web compatibility, enabling developers to create complex user interfaces effortlessly while enjoying a clean coding experience. 🖥️✨
“Creating limitless user interface experiences is the dream of every developer, and Clay provides powerful support to make that dream a reality!” 🌈
In the fast-paced digital age, User Interface (UI) design has become one of the key factors in enhancing software experiences. As users’ demands for applications continue to rise, developers urgently need a tool that allows for the rapid, reliable, and flexible construction of complex interfaces. Enter Clay! 🌟
Clay is a high-performance UI layout library specifically developed for C language, focusing on providing low-latency, high-efficiency layout solutions. 🛠️ Its design philosophy balances flexibility in development with efficiency in execution, enabling developers to thrive as they easily meet various innovative interface requirements! 💪
-
Clay: A Groundbreaking UI Layout Library 🚀
Clay is a high-performance, dependency-free UI layout library tailored for C language. 🌟 This library aims to help developers quickly create complex user interfaces, offering microsecond-level layout performance that excels in low-latency applications. 🥇 As an open-source tool, Clay emphasizes its dependency-free design, allowing developers to work with this straightforward library without standard library support. 🎨 -
Core Features of Clay: The Perfect Blend of Performance and Flexibility ⚡️
- High Performance: Clay provides microsecond-level layout processing, making it extremely suitable for latency-sensitive applications, such as games and real-time interactive websites. 🎮
- Compact Design: Clay consists of just one header file, with a total code volume roughly around 2000 lines, completely independent of any standard libraries, providing you with a clean programming experience. 📂
- WebAssembly Support: By compiling Clay to WebAssembly, developers can use this library in web environments while maintaining its lightweight and high-performance nature. 🖥️
- Declarative Syntax: Clay adopts a declarative syntax similar to React, making UI construction more intuitive and approachable for developers. 📝
- Renderer Agnosticism: The rendered command list output by Clay is compatible with multiple rendering engines, making it easy to apply for HTML rendering and other interface constructions. 🌍
- Memory Efficient: To enhance resource management, Clay uses an arena memory allocation model, optimizing memory usage, allowing developers to focus fully on their tasks. 💾
- Reasons Developers Choose Clay: The Union of Advanced Technology and User Experience 🛠️
Developers using Clay can experience real-time layout capabilities, enabling their applications to respond quickly to viewport changes and adapt to dynamic requirements, thereby creating truly dynamic user interfaces. 🔄 This library also provides a range of debugging tools to help developers better understand their layout structures, further enhancing development efficiency. 📈 In the C language environment, Clay’s flexibility and innovation open a door to countless possibilities for developers, supporting complex UI designs and providing immense creative freedom. 💡 Although Clay faces challenges in accessibility, developers must still strive to overcome these issues to enhance user experience. 🙌
As a tool for achieving high-performance layouts, Clay not only provides developers with an elegant API but also offers rich possibilities for modern application interface creation, increasingly favored by developers in recent years.✨
- How to Install Clay 🛠️
Before using Clay, we need to install it. Here are the detailed steps and code examples to help you get started quickly.
- Download or clone the clay.h file 📥 and define
CLAY_IMPLEMENTATION
in one file before including it. This approach ensures that Clay is compiled correctly.
// Example code to include the Clay file
#define CLAY_IMPLEMENTATION
#include "clay.h"
Note: Here, the #define CLAY_IMPLEMENTATION
statement is defined before including the Clay header file to instruct the compiler that this is an implementation file where all functionalities are defined. Next, we load all functionalities of Clay with #include "clay.h"
.
- Determine the static memory size required by Clay and initialize it 💾. Use the
Clay_MinMemorySize()
method to retrieve the required memory size and initialize it.
uint64_t totalMemorySize = Clay_MinMemorySize(); // Get the required memory size
Clay_Arena arena = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize)); // Create memory arena
Clay_Initialize(arena, (Clay_Dimensions) { screenWidth, screenHeight }); // Initialize Clay
Note: First, we call Clay_MinMemorySize()
to calculate the memory size needed to create Clay. Then, we allocate memory using Clay_CreateArenaWithCapacityAndMemory()
and call Clay_Initialize()
to initialize, specifying screen width and height to set up the user interface.
- Provide the
MeasureText(text, config)
function for text measurement functionality 📝. This feature is crucial for dynamic text layout.
// Example text measurement function
static inline Clay_Dimensions MeasureText(Clay_String *text, Clay_TextElementConfig *config) {
// Clay_TextElementConfig contains members like fontId, fontSize, letterSpacing, etc.
}
// Register the text measurement function
Clay_SetMeasureTextFunction(MeasureText);
Note: The functionality to measure text is essential since it can affect layout accuracy. In this example, we define a function to measure text and register this function using Clay_SetMeasureTextFunction()
so that Clay can call it for text measurement.
- (Optional) Call the interface to update layout dimensions 📏 if necessary.
Clay_SetLayoutDimensions((Clay_Dimensions) { screenWidth, screenHeight }); // Update layout dimensions
Note: You can use this function to update layout dimensions when adjusting window sizes or during initialization, ensuring that UI elements adapt to the new dimensions.
- (Optional) Handle mouse interaction operations 🖱️.
Clay_SetPointerState((Clay_Vector2) { mousePositionX, mousePositionY }, isMouseDown); // Set the mouse state
Note: By setting the mouse state, we inform Clay of the user’s current mouse position and whether the mouse button is pressed, which is crucial for handling user interactions.
- (Optional) Utilize the built-in scroll container 🌀.
Clay_UpdateScrollContainers(true, (Clay_Vector2) { mouseWheelX, mouseWheelY }, deltaTime); // Update scroll containers
Note: This line of code updates the built-in scroll container in Clay, allowing us to respond to mouse wheel actions so that the user interface can scroll, offering a better user experience.
- Code Examples and Usage Scenarios 💻
After grasping the basic installation steps, we can explore the usage of Clay through some practical code examples.
Example 1: Building a Sidebar Component 📋
This code demonstrates how to create a simple sidebar layout.
const Clay_Color COLOR_ORANGE = {225, 138, 50, 255};
// Declare layout configuration
Clay_LayoutConfig sidebarItemLayout = {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(50) },
};
void SidebarItemComponent() {
CLAY(CLAY_LAYOUT(sidebarItemLayout), CLAY_RECTANGLE({ .color = COLOR_ORANGE })) {} // Sidebar item component
}
Note: In this example, we defined a color constant COLOR_ORANGE
to color the background of the sidebar items. We then created a sidebarItemLayout
configuration that specifies a flexible width and a fixed height layout. In the SidebarItemComponent
, we created a rectangular element using the CLAY
macro to represent the sidebar item.
Example 2: Creating a Complete Layout 🏗️
This example shows how to create a layout with Clay that includes a sidebar and a main content area.
Clay_RenderCommandArray CreateLayout() {
Clay_BeginLayout(); // Start layout
// Outer container
CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(), CLAY_SIZING_GROW()}, .padding = {16, 16}, .childGap = 16 }),
CLAY_RECTANGLE({ .color = {250,250,255,255} })) {
// Sidebar
CLAY(CLAY_ID("SideBar"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16 }),
CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {
// Left picture and text
CLAY(CLAY_ID("ProfilePictureOuter"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }}),
CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("ProfilePicture"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}),
CLAY_IMAGE({ .imageData = &profilePicture, .height = 60, .width = 60 })) {}
CLAY_TEXT(CLAY_STRING("Clay - UI Library"), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {255, 255, 255, 255} })); // Display text
}
// Create five sidebar items
for (int i = 0; i < 5; i++) {
SidebarItemComponent(); // Call sidebar component
}
}
// Main content area
CLAY(CLAY_ID("MainContent"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() }}),
CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {}
}
}
Note: We start a new layout by calling Clay_BeginLayout()
. In the outer container, we create a fixed-width sidebar and a main content area. Using the CLAY
macro, we define various UI elements and insert five sidebar items within the sidebar section. This showcases the flexibility and powerful features of Clay.
Example 3: Ending the Layout and Rendering 🎨
After completing the layout, you need to finish the layout process and handle rendering commands.
Clay_RenderCommandArray renderCommands = Clay_EndLayout(); // End layout
for (int i = 0; i < renderCommands.length; i++) { // Iterate through command array
Clay_RenderCommand *renderCommand = &renderCommands.internalArray[i];
// Process commands based on their type
switch (renderCommand->commandType) {
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
DrawRectangle(renderCommand->boundingBox, renderCommand->config.rectangleElementConfig->color); // Draw based on rectangle command
}
// You can add other command types as needed
}
}
Note: Using Clay_EndLayout()
ends the layout and returns a rendering command array. In this array, we iterate through each command and handle it based on its type. In this example, we draw rectangles based on the rectangle commands.
Example 4: Responding to User Interactions 👆
Utilize Clay to handle user mouse interactions.
// Example mouse interaction
CLAY(CLAY_RECTANGLE(.color = Clay_Hovered() ? COLOR_BLUE : COLOR_ORANGE)) {
bool buttonHovered = Clay_Hovered(); // Check if the button is hovered
CLAY_TEXT(buttonHovered ? CLAY_STRING("Hovered") : CLAY_STRING("Hover me!"), headerTextConfig); // Show different texts
}
Note: This code example shows how to handle user hover events. By using the Clay_Hovered()
function, we can determine if the mouse is currently hovering over the interactive element and display different text based on the status.
With these steps and examples, you can easily dive into Clay and create expressive 2D user interfaces. ✨