mirror of
				https://github.com/nicbarker/clay.git
				synced 2025-11-03 16:16:18 +00:00 
			
		
		
		
	[Examples/clay-official-website] Update web renderer example to latest API
This commit is contained in:
		
							parent
							
								
									dcd6feda86
								
							
						
					
					
						commit
						76c8e1f115
					
				
							
								
								
									
										12
									
								
								clay.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								clay.h
									
									
									
									
									
								
							| 
						 | 
					@ -424,6 +424,11 @@ typedef struct {
 | 
				
			||||||
    void* customData;
 | 
					    void* customData;
 | 
				
			||||||
} Clay_CustomRenderData;
 | 
					} Clay_CustomRenderData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    bool horizontal;
 | 
				
			||||||
 | 
					    bool vertical;
 | 
				
			||||||
 | 
					} Clay_ScrollRenderData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    Clay_Color color;
 | 
					    Clay_Color color;
 | 
				
			||||||
    Clay_CornerRadius cornerRadius;
 | 
					    Clay_CornerRadius cornerRadius;
 | 
				
			||||||
| 
						 | 
					@ -436,6 +441,7 @@ typedef union {
 | 
				
			||||||
    Clay_ImageRenderData image;
 | 
					    Clay_ImageRenderData image;
 | 
				
			||||||
    Clay_CustomRenderData custom;
 | 
					    Clay_CustomRenderData custom;
 | 
				
			||||||
    Clay_BorderRenderData border;
 | 
					    Clay_BorderRenderData border;
 | 
				
			||||||
 | 
					    Clay_ScrollRenderData scroll;
 | 
				
			||||||
} Clay_RenderData;
 | 
					} Clay_RenderData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Miscellaneous Structs & Enums ---------------------------------
 | 
					// Miscellaneous Structs & Enums ---------------------------------
 | 
				
			||||||
| 
						 | 
					@ -2249,6 +2255,12 @@ void Clay__CalculateFinalLayout(void) {
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case CLAY__ELEMENT_CONFIG_TYPE_SCROLL: {
 | 
					                        case CLAY__ELEMENT_CONFIG_TYPE_SCROLL: {
 | 
				
			||||||
                            renderCommand.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START;
 | 
					                            renderCommand.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START;
 | 
				
			||||||
 | 
					                            renderCommand.renderData = CLAY__INIT(Clay_RenderData) {
 | 
				
			||||||
 | 
					                                .scroll = {
 | 
				
			||||||
 | 
					                                    .horizontal = elementConfig->config.scrollElementConfig->horizontal,
 | 
				
			||||||
 | 
					                                    .vertical = elementConfig->config.scrollElementConfig->vertical,
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: {
 | 
					                        case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,10 @@
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
    let elementCache = {};
 | 
					    let elementCache = {};
 | 
				
			||||||
    let imageCache = {};
 | 
					    let imageCache = {};
 | 
				
			||||||
 | 
					    let dimensionsDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        {name: 'width', type: 'float'},
 | 
				
			||||||
 | 
					        {name: 'height', type: 'float'},
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
    let colorDefinition = { type: 'struct', members: [
 | 
					    let colorDefinition = { type: 'struct', members: [
 | 
				
			||||||
        {name: 'r', type: 'float' },
 | 
					        {name: 'r', type: 'float' },
 | 
				
			||||||
        {name: 'g', type: 'float' },
 | 
					        {name: 'g', type: 'float' },
 | 
				
			||||||
| 
						 | 
					@ -101,9 +105,12 @@
 | 
				
			||||||
        {name: 'chars', type: 'uint32_t' },
 | 
					        {name: 'chars', type: 'uint32_t' },
 | 
				
			||||||
        {name: 'baseChars', type: 'uint32_t' },
 | 
					        {name: 'baseChars', type: 'uint32_t' },
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let borderDefinition = { type: 'struct', members: [
 | 
					    let borderWidthDefinition = { type: 'struct', members: [
 | 
				
			||||||
        {name: 'width', type: 'uint32_t'},
 | 
					        {name: 'left', type: 'uint16_t'},
 | 
				
			||||||
        {name: 'color', ...colorDefinition},
 | 
					        {name: 'right', type: 'uint16_t'},
 | 
				
			||||||
 | 
					        {name: 'top', type: 'uint16_t'},
 | 
				
			||||||
 | 
					        {name: 'bottom', type: 'uint16_t'},
 | 
				
			||||||
 | 
					        {name: 'betweenChildren', type: 'uint16_t'},
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let cornerRadiusDefinition = { type: 'struct', members: [
 | 
					    let cornerRadiusDefinition = { type: 'struct', members: [
 | 
				
			||||||
        {name: 'topLeft', type: 'float'},
 | 
					        {name: 'topLeft', type: 'float'},
 | 
				
			||||||
| 
						 | 
					@ -111,44 +118,53 @@
 | 
				
			||||||
        {name: 'bottomLeft', type: 'float'},
 | 
					        {name: 'bottomLeft', type: 'float'},
 | 
				
			||||||
        {name: 'bottomRight', type: 'float'},
 | 
					        {name: 'bottomRight', type: 'float'},
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let rectangleConfigDefinition = { name: 'rectangle', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'color', ...colorDefinition },
 | 
					 | 
				
			||||||
        { name: 'link', ...stringDefinition },
 | 
					 | 
				
			||||||
        { name: 'cursorPointer', type: 'uint8_t' },
 | 
					 | 
				
			||||||
    ]};
 | 
					 | 
				
			||||||
    let borderConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'left', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'right', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'top', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'bottom', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'betweenChildren', ...borderDefinition },
 | 
					 | 
				
			||||||
    ]};
 | 
					 | 
				
			||||||
    let textConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
					    let textConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
				
			||||||
       { name: 'textColor', ...colorDefinition },
 | 
					        { name: 'textColor', ...colorDefinition },
 | 
				
			||||||
       { name: 'fontId', type: 'uint16_t' },
 | 
					        { name: 'fontId', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'fontSize', type: 'uint16_t' },
 | 
					        { name: 'fontSize', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'letterSpacing', type: 'uint16_t' },
 | 
					        { name: 'letterSpacing', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'lineSpacing', type: 'uint16_t' },
 | 
					        { name: 'lineSpacing', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'wrapMode', type: 'uint32_t' },
 | 
					        { name: 'wrapMode', type: 'uint8_t' },
 | 
				
			||||||
       { name: 'disablePointerEvents', type: 'uint8_t' }
 | 
					        { name: 'disablePointerEvents', type: 'uint8_t' },
 | 
				
			||||||
 | 
					        { name: '_padding', type: 'uint16_t' },
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let scrollConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
					    let textRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'stringContents', ...stringSliceDefinition },
 | 
				
			||||||
 | 
					        { name: 'textColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'fontId', type: 'uint16_t' },
 | 
				
			||||||
 | 
					        { name: 'fontSize', type: 'uint16_t' },
 | 
				
			||||||
 | 
					        { name: 'letterSpacing', type: 'uint16_t' },
 | 
				
			||||||
 | 
					        { name: 'lineHeight', type: 'uint16_t' },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let rectangleRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'backgroundColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let imageRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'backgroundColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					        { name: 'sourceDimensions', ...dimensionsDefinition },
 | 
				
			||||||
 | 
					        { name: 'imageData', type: 'uint32_t' },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let customRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'backgroundColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					        { name: 'customData', type: 'uint32_t' },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let borderRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'color', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					        { name: 'width', ...borderWidthDefinition },
 | 
				
			||||||
 | 
					        { name: 'padding', type: 'uint16_t'}
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let scrollRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
        { name: 'horizontal', type: 'bool' },
 | 
					        { name: 'horizontal', type: 'bool' },
 | 
				
			||||||
        { name: 'vertical', type: 'bool' },
 | 
					        { name: 'vertical', type: 'bool' },
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let imageConfigDefinition = { name: 'image', type: 'struct', members: [
 | 
					    let customHTMLDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
        { name: 'imageData', type: 'uint32_t' },
 | 
					        { name: 'link', ...stringDefinition },
 | 
				
			||||||
        { name: 'sourceDimensions', type: 'struct', members: [
 | 
					        { name: 'cursorPointer', type: 'uint8_t' },
 | 
				
			||||||
            { name: 'width', type: 'float' },
 | 
					        { name: 'disablePointerEvents', type: 'uint8_t' },
 | 
				
			||||||
            { name: 'height', type: 'float' },
 | 
					 | 
				
			||||||
        ]},
 | 
					 | 
				
			||||||
        { name: 'sourceURL', ...stringDefinition }
 | 
					 | 
				
			||||||
    ]};
 | 
					 | 
				
			||||||
    let customConfigDefinition = { name: 'custom', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'customData', type: 'uint32_t' },
 | 
					 | 
				
			||||||
    ]}
 | 
					 | 
				
			||||||
    let sharedConfigDefinition = { name: 'shared', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
					 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let renderCommandDefinition = {
 | 
					    let renderCommandDefinition = {
 | 
				
			||||||
        name: 'CLay_RenderCommand',
 | 
					        name: 'CLay_RenderCommand',
 | 
				
			||||||
| 
						 | 
					@ -160,14 +176,19 @@
 | 
				
			||||||
                { name: 'width', type: 'float' },
 | 
					                { name: 'width', type: 'float' },
 | 
				
			||||||
                { name: 'height', type: 'float' },
 | 
					                { name: 'height', type: 'float' },
 | 
				
			||||||
            ]},
 | 
					            ]},
 | 
				
			||||||
            { name: 'config', type: 'uint32_t'},
 | 
					            { name: 'renderData', type: 'union', members: [
 | 
				
			||||||
            { name: 'textOrSharedConfig', type: 'union', members: [
 | 
					                { name: 'rectangle', ...rectangleRenderDataDefinition },
 | 
				
			||||||
                { name: 'text', ...stringSliceDefinition },
 | 
					                { name: 'text', ...textRenderDataDefinition },
 | 
				
			||||||
                { name: 'sharedConfig', type: 'uint32_t' }
 | 
					                { name: 'image', ...imageRenderDataDefinition },
 | 
				
			||||||
 | 
					                { name: 'custom', ...customRenderDataDefinition },
 | 
				
			||||||
 | 
					                { name: 'border', ...borderRenderDataDefinition },
 | 
				
			||||||
 | 
					                { name: 'scroll', ...scrollRenderDataDefinition },
 | 
				
			||||||
            ]},
 | 
					            ]},
 | 
				
			||||||
            { name: 'zIndex', type: 'int32_t' },
 | 
					            { name: 'userData', type: 'uint32_t'},
 | 
				
			||||||
            { name: 'id', type: 'uint32_t' },
 | 
					            { name: 'id', type: 'uint32_t' },
 | 
				
			||||||
            { name: 'commandType', type: 'uint32_t', },
 | 
					            { name: 'zIndex', type: 'int16_t' },
 | 
				
			||||||
 | 
					            { name: 'commandType', type: 'uint8_t' },
 | 
				
			||||||
 | 
					            { name: '_padding', type: 'uint8_t' },
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,6 +211,7 @@
 | 
				
			||||||
            case 'uint32_t': return 4;
 | 
					            case 'uint32_t': return 4;
 | 
				
			||||||
            case 'int32_t': return 4;
 | 
					            case 'int32_t': return 4;
 | 
				
			||||||
            case 'uint16_t': return 2;
 | 
					            case 'uint16_t': return 2;
 | 
				
			||||||
 | 
					            case 'int16_t': return 2;
 | 
				
			||||||
            case 'uint8_t': return 1;
 | 
					            case 'uint8_t': return 1;
 | 
				
			||||||
            case 'bool': return 1;
 | 
					            case 'bool': return 1;
 | 
				
			||||||
            default: {
 | 
					            default: {
 | 
				
			||||||
| 
						 | 
					@ -219,6 +241,7 @@
 | 
				
			||||||
            case 'uint32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
					            case 'uint32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
				
			||||||
            case 'int32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
					            case 'int32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
				
			||||||
            case 'uint16_t': return { value: memoryDataView.getUint16(address, true), __size: 2 };
 | 
					            case 'uint16_t': return { value: memoryDataView.getUint16(address, true), __size: 2 };
 | 
				
			||||||
 | 
					            case 'int16_t': return { value: memoryDataView.getInt16(address, true), __size: 2 };
 | 
				
			||||||
            case 'uint8_t': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
					            case 'uint8_t': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
				
			||||||
            case 'bool': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
					            case 'bool': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
				
			||||||
            default: {
 | 
					            default: {
 | 
				
			||||||
| 
						 | 
					@ -340,7 +363,7 @@
 | 
				
			||||||
                        memoryDataView.setFloat32(addressOfOffset, -container.scrollLeft, true);
 | 
					                        memoryDataView.setFloat32(addressOfOffset, -container.scrollLeft, true);
 | 
				
			||||||
                        memoryDataView.setFloat32(addressOfOffset + 4, -container.scrollTop, true);
 | 
					                        memoryDataView.setFloat32(addressOfOffset + 4, -container.scrollTop, true);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        const { instance } = await WebAssembly.instantiateStreaming(
 | 
					        const { instance } = await WebAssembly.instantiateStreaming(
 | 
				
			||||||
| 
						 | 
					@ -348,13 +371,15 @@
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        memoryDataView = new DataView(new Uint8Array(instance.exports.memory.buffer).buffer);
 | 
					        memoryDataView = new DataView(new Uint8Array(instance.exports.memory.buffer).buffer);
 | 
				
			||||||
        scratchSpaceAddress = instance.exports.__heap_base.value;
 | 
					        scratchSpaceAddress = instance.exports.__heap_base.value;
 | 
				
			||||||
        heapSpaceAddress = instance.exports.__heap_base.value + 1024;
 | 
					        let clayScratchSpaceAddress = instance.exports.__heap_base.value + 1024;
 | 
				
			||||||
 | 
					        heapSpaceAddress = instance.exports.__heap_base.value + 2048;
 | 
				
			||||||
        let arenaAddress = scratchSpaceAddress + 8;
 | 
					        let arenaAddress = scratchSpaceAddress + 8;
 | 
				
			||||||
        window.instance = instance;
 | 
					        window.instance = instance;
 | 
				
			||||||
        createMainArena(arenaAddress, heapSpaceAddress);
 | 
					        createMainArena(arenaAddress, heapSpaceAddress);
 | 
				
			||||||
        memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
 | 
					        memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
 | 
				
			||||||
        memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
 | 
					        memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
 | 
				
			||||||
        instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
 | 
					        instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
 | 
				
			||||||
 | 
					        instance.exports.SetScratchMemory(arenaAddress, clayScratchSpaceAddress);
 | 
				
			||||||
        renderCommandSize = getStructTotalSize(renderCommandDefinition);
 | 
					        renderCommandSize = getStructTotalSize(renderCommandDefinition);
 | 
				
			||||||
        renderLoop();
 | 
					        renderLoop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -368,6 +393,22 @@
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function SetElementBackgroundColorAndRadius(element, cornerRadius, backgroundColor) {
 | 
				
			||||||
 | 
					        element.style.backgroundColor = `rgba(${backgroundColor.r.value}, ${backgroundColor.g.value}, ${backgroundColor.b.value}, ${backgroundColor.a.value / 255})`;
 | 
				
			||||||
 | 
					        if (cornerRadius.topLeft.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderTopLeftRadius = cornerRadius.topLeft.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (cornerRadius.topRight.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderTopRightRadius = cornerRadius.topRight.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (cornerRadius.bottomLeft.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderBottomLeftRadius = cornerRadius.bottomLeft.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (cornerRadius.bottomRight.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderBottomRightRadius = cornerRadius.bottomRight.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function renderLoopHTML() {
 | 
					    function renderLoopHTML() {
 | 
				
			||||||
        let capacity = memoryDataView.getInt32(scratchSpaceAddress, true);
 | 
					        let capacity = memoryDataView.getInt32(scratchSpaceAddress, true);
 | 
				
			||||||
        let length = memoryDataView.getInt32(scratchSpaceAddress + 4, true);
 | 
					        let length = memoryDataView.getInt32(scratchSpaceAddress + 4, true);
 | 
				
			||||||
| 
						 | 
					@ -375,7 +416,7 @@
 | 
				
			||||||
        let scissorStack = [{ nextAllocation: { x: 0, y: 0 }, element: htmlRoot, nextElementIndex: 0 }];
 | 
					        let scissorStack = [{ nextAllocation: { x: 0, y: 0 }, element: htmlRoot, nextElementIndex: 0 }];
 | 
				
			||||||
        let previousId = 0;
 | 
					        let previousId = 0;
 | 
				
			||||||
        for (let i = 0; i < length; i++, arrayOffset += renderCommandSize) {
 | 
					        for (let i = 0; i < length; i++, arrayOffset += renderCommandSize) {
 | 
				
			||||||
            let entireRenderCommandMemory = new Uint32Array(memoryDataView.buffer.slice(arrayOffset, arrayOffset + renderCommandSize));
 | 
					            let entireRenderCommandMemory = new Uint8Array(memoryDataView.buffer.slice(arrayOffset, arrayOffset + renderCommandSize));
 | 
				
			||||||
            let renderCommand = readStructAtAddress(arrayOffset, renderCommandDefinition);
 | 
					            let renderCommand = readStructAtAddress(arrayOffset, renderCommandDefinition);
 | 
				
			||||||
            let parentElement = scissorStack[scissorStack.length - 1];
 | 
					            let parentElement = scissorStack[scissorStack.length - 1];
 | 
				
			||||||
            let element = null;
 | 
					            let element = null;
 | 
				
			||||||
| 
						 | 
					@ -384,13 +425,12 @@
 | 
				
			||||||
                let elementType = 'div';
 | 
					                let elementType = 'div';
 | 
				
			||||||
                switch (renderCommand.commandType.value & 0xff) {
 | 
					                switch (renderCommand.commandType.value & 0xff) {
 | 
				
			||||||
                    case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
 | 
					                    case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
 | 
				
			||||||
                        if (readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition).link.length.value > 0) {
 | 
					                        // if (readStructAtAddress(renderCommand.renderData.rectangle.value, rectangleRenderDataDefinition).link.length.value > 0) { TODO reimplement links
 | 
				
			||||||
                            elementType = 'a';
 | 
					                        //     elementType = 'a';
 | 
				
			||||||
                        }
 | 
					                        // }
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
 | 
					                    case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
 | 
				
			||||||
                        console.log('test5');
 | 
					 | 
				
			||||||
                        elementType = 'img'; break;
 | 
					                        elementType = 'img'; break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    default: break;
 | 
					                    default: break;
 | 
				
			||||||
| 
						 | 
					@ -443,93 +483,82 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition);
 | 
					                    let config = renderCommand.renderData.rectangle;
 | 
				
			||||||
                    let sharedConfig = readStructAtAddress( renderCommand.textOrSharedConfig.sharedConfig.value, sharedConfigDefinition);
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
                    let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
 | 
					                    if (configMemory === elementData.previousMemoryConfig) {
 | 
				
			||||||
                    let linkContents = config.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.link.chars.value, config.link.chars.value + config.link.length.value))) : 0;
 | 
					 | 
				
			||||||
                    memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
					 | 
				
			||||||
                    if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
					 | 
				
			||||||
                        window.location.href = linkContents;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (!dirty && !MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
 | 
					 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (linkContents.length > 0) {
 | 
					
 | 
				
			||||||
                        element.href = linkContents;
 | 
					                    SetElementBackgroundColorAndRadius(element, config.cornerRadius, config.backgroundColor);
 | 
				
			||||||
 | 
					                    if (renderCommand.userData.value !== 0) {
 | 
				
			||||||
 | 
					                        let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        let linkContents = customData.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(customData.link.chars.value, customData.link.chars.value + customData.link.length.value))) : 0;
 | 
				
			||||||
 | 
					                        memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
				
			||||||
 | 
					                            window.location.href = linkContents;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0) {
 | 
				
			||||||
 | 
					                            element.href = linkContents;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0 || customData.cursorPointer.value) {
 | 
				
			||||||
 | 
					                            element.style.pointerEvents = 'all';
 | 
				
			||||||
 | 
					                            element.style.cursor = 'pointer';
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (linkContents.length > 0 || config.cursorPointer.value) {
 | 
					 | 
				
			||||||
                        element.style.pointerEvents = 'all';
 | 
					 | 
				
			||||||
                        element.style.cursor = 'pointer';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    elementData.previousMemoryConfig = configMemory;
 | 
					                    elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    let color = config.color;
 | 
					
 | 
				
			||||||
                    element.style.backgroundColor = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topLeft.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderTopLeftRadius = sharedConfig.cornerRadius.topLeft.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topRight.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderTopRightRadius = sharedConfig.cornerRadius.topRight.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomLeft.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderBottomLeftRadius = sharedConfig.cornerRadius.bottomLeft.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomRight.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderBottomRightRadius = sharedConfig.cornerRadius.bottomRight.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, borderConfigDefinition);
 | 
					                    let config = renderCommand.renderData.border;
 | 
				
			||||||
                    let sharedConfig = readStructAtAddress( renderCommand.textOrSharedConfig.sharedConfig.value, sharedConfigDefinition);
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
                    let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
 | 
					                    if (configMemory === elementData.previousMemoryConfig) {
 | 
				
			||||||
                    if (!dirty && !MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
 | 
					 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    let color = config.color;
 | 
				
			||||||
                    elementData.previousMemoryConfig = configMemory;
 | 
					                    elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    if (config.left.width.value > 0) {
 | 
					                    if (config.width.left.value > 0) {
 | 
				
			||||||
                        let color = config.left.color;
 | 
					                        element.style.borderLeft = `${config.width.left.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderLeft = `${config.left.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (config.right.width.value > 0) {
 | 
					                    if (config.width.right.value > 0) {
 | 
				
			||||||
                        let color = config.right.color;
 | 
					                        element.style.borderRight = `${config.width.right.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderRight = `${config.right.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (config.top.width.value > 0) {
 | 
					                    if (config.width.top.value > 0) {
 | 
				
			||||||
                        let color = config.top.color;
 | 
					                        element.style.borderTop = `${config.width.top.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderTop = `${config.top.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (config.bottom.width.value > 0) {
 | 
					                    if (config.width.bottom.value > 0) {
 | 
				
			||||||
                        let color = config.bottom.color;
 | 
					                        element.style.borderBottom = `${config.width.bottom.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderBottom = `${config.bottom.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topLeft.value > 0) {
 | 
					                    if (config.cornerRadius.topLeft.value > 0) {
 | 
				
			||||||
                        element.style.borderTopLeftRadius = sharedConfig.cornerRadius.topLeft.value + 'px';
 | 
					                        element.style.borderTopLeftRadius = config.cornerRadius.topLeft.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topRight.value > 0) {
 | 
					                    if (config.cornerRadius.topRight.value > 0) {
 | 
				
			||||||
                        element.style.borderTopRightRadius = sharedConfig.cornerRadius.topRight.value + 'px';
 | 
					                        element.style.borderTopRightRadius = config.cornerRadius.topRight.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomLeft.value > 0) {
 | 
					                    if (config.cornerRadius.bottomLeft.value > 0) {
 | 
				
			||||||
                        element.style.borderBottomLeftRadius = sharedConfig.cornerRadius.bottomLeft.value + 'px';
 | 
					                        element.style.borderBottomLeftRadius = config.cornerRadius.bottomLeft.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomRight.value > 0) {
 | 
					                    if (config.cornerRadius.bottomRight.value > 0) {
 | 
				
			||||||
                        element.style.borderBottomRightRadius = sharedConfig.cornerRadius.bottomRight.value + 'px';
 | 
					                        element.style.borderBottomRightRadius = config.cornerRadius.bottomRight.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, textConfigDefinition);
 | 
					                    let config = renderCommand.renderData.text;
 | 
				
			||||||
                    let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
 | 
					                    let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
 | 
				
			||||||
                    let textContents = renderCommand.textOrSharedConfig.text;
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
 | 
					                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(config.stringContents.chars.value, config.stringContents.chars.value + config.stringContents.length.value));
 | 
				
			||||||
                    if (MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
 | 
					                    if (configMemory !== elementData.previousMemoryConfig) {
 | 
				
			||||||
                        element.className = 'text';
 | 
					                        element.className = 'text';
 | 
				
			||||||
                        let textColor = config.textColor;
 | 
					                        let textColor = config.textColor;
 | 
				
			||||||
                        let fontSize = Math.round(config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR);
 | 
					                        let fontSize = Math.round(config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR);
 | 
				
			||||||
                        element.style.color = `rgba(${textColor.r.value}, ${textColor.g.value}, ${textColor.b.value}, ${textColor.a.value})`;
 | 
					                        element.style.color = `rgba(${textColor.r.value}, ${textColor.g.value}, ${textColor.b.value}, ${textColor.a.value})`;
 | 
				
			||||||
                        element.style.fontFamily = fontsById[config.fontId.value];
 | 
					                        element.style.fontFamily = fontsById[config.fontId.value];
 | 
				
			||||||
                        element.style.fontSize = fontSize + 'px';
 | 
					                        element.style.fontSize = fontSize + 'px';
 | 
				
			||||||
                        element.style.pointerEvents = config.disablePointerEvents.value ? 'none' : 'all';
 | 
					                        element.style.pointerEvents = customData.disablePointerEvents.value ? 'none' : 'all';
 | 
				
			||||||
                        elementData.previousMemoryConfig = configMemory;
 | 
					                        elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (stringContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(stringContents, elementData.previousMemoryText, stringContents.length)) {
 | 
					                    if (stringContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(stringContents, elementData.previousMemoryText, stringContents.length)) {
 | 
				
			||||||
| 
						 | 
					@ -540,7 +569,11 @@
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
 | 
				
			||||||
                    scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
 | 
					                    scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, scrollConfigDefinition);
 | 
					                    let config = renderCommand.renderData.scroll;
 | 
				
			||||||
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
 | 
					                    if (configMemory === elementData.previousMemoryConfig) {
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                    if (config.horizontal.value) {
 | 
					                    if (config.horizontal.value) {
 | 
				
			||||||
                        element.style.overflowX = 'scroll';
 | 
					                        element.style.overflowX = 'scroll';
 | 
				
			||||||
                        element.style.pointerEvents = 'auto';
 | 
					                        element.style.pointerEvents = 'auto';
 | 
				
			||||||
| 
						 | 
					@ -549,6 +582,7 @@
 | 
				
			||||||
                        element.style.overflowY = 'scroll';
 | 
					                        element.style.overflowY = 'scroll';
 | 
				
			||||||
                        element.style.pointerEvents = 'auto';
 | 
					                        element.style.pointerEvents = 'auto';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_END): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_END): {
 | 
				
			||||||
| 
						 | 
					@ -556,9 +590,9 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
				
			||||||
                    console.log('test1');
 | 
					                    let config = renderCommand.renderData.image;
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, imageConfigDefinition);
 | 
					                    let imageURL = readStructAtAddress(config.imageData.value, stringDefinition);
 | 
				
			||||||
                    let srcContents = new Uint8Array(memoryDataView.buffer.slice(config.sourceURL.chars.value, config.sourceURL.chars.value + config.sourceURL.length.value));
 | 
					                    let srcContents = new Uint8Array(memoryDataView.buffer.slice(imageURL.chars.value, imageURL.chars.value + imageURL.length.value));
 | 
				
			||||||
                    if (srcContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(srcContents, elementData.previousMemoryText, srcContents.length)) {
 | 
					                    if (srcContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(srcContents, elementData.previousMemoryText, srcContents.length)) {
 | 
				
			||||||
                        element.src = textDecoder.decode(srcContents);
 | 
					                        element.src = textDecoder.decode(srcContents);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -566,6 +600,9 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_CUSTOM): break;
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_CUSTOM): break;
 | 
				
			||||||
 | 
					                default: {
 | 
				
			||||||
 | 
					                    console.log("Error: unhandled render command");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -602,8 +639,8 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition);
 | 
					                    let config = renderCommand.renderData.rectangle;
 | 
				
			||||||
                    let color = config.color;
 | 
					                    let color = config.backgroundColor;
 | 
				
			||||||
                    ctx.beginPath();
 | 
					                    ctx.beginPath();
 | 
				
			||||||
                    window.canvasContext.fillStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                    window.canvasContext.fillStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                    window.canvasContext.roundRect(
 | 
					                    window.canvasContext.roundRect(
 | 
				
			||||||
| 
						 | 
					@ -615,33 +652,35 @@
 | 
				
			||||||
                    ctx.fill();
 | 
					                    ctx.fill();
 | 
				
			||||||
                    ctx.closePath();
 | 
					                    ctx.closePath();
 | 
				
			||||||
                    // Handle link clicks
 | 
					                    // Handle link clicks
 | 
				
			||||||
                    let linkContents = config.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.link.chars.value, config.link.chars.value + config.link.length.value))) : 0;
 | 
					                    if (renderCommand.userData.value !== 0) {
 | 
				
			||||||
                    memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
					                        let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
 | 
				
			||||||
                    if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
					                        let linkContents = customData.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(customData.link.chars.value, customData.link.chars.value + customData.link.length.value))) : 0;
 | 
				
			||||||
                        window.location.href = linkContents;
 | 
					                        memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
				
			||||||
 | 
					                            window.location.href = linkContents;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, borderConfigDefinition);
 | 
					                    let config = renderCommand.renderData.border;
 | 
				
			||||||
 | 
					                    let color = config.color;
 | 
				
			||||||
                    ctx.beginPath();
 | 
					                    ctx.beginPath();
 | 
				
			||||||
                    ctx.moveTo(boundingBox.x.value * scale, boundingBox.y.value * scale);
 | 
					                    ctx.moveTo(boundingBox.x.value * scale, boundingBox.y.value * scale);
 | 
				
			||||||
                    // Top Left Corner
 | 
					                    // Top Left Corner
 | 
				
			||||||
                    if (config.cornerRadius.topLeft.value > 0) {
 | 
					                    if (config.cornerRadius.topLeft.value > 0) {
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale);
 | 
				
			||||||
                        let color = config.top.color;
 | 
					 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                        ctx.arcTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, config.cornerRadius.topLeft.value * scale);
 | 
					                        ctx.arcTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, config.cornerRadius.topLeft.value * scale);
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Top border
 | 
					                    // Top border
 | 
				
			||||||
                    if (config.top.width.value > 0) {
 | 
					                    if (config.width.top.value > 0) {
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        let color = config.top.color;
 | 
					 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
				
			||||||
| 
						 | 
					@ -650,19 +689,17 @@
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Top Right Corner
 | 
					                    // Top Right Corner
 | 
				
			||||||
                    if (config.cornerRadius.topRight.value > 0) {
 | 
					                    if (config.cornerRadius.topRight.value > 0) {
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - config.cornerRadius.topRight.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - config.cornerRadius.topRight.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
				
			||||||
                        let color = config.top.color;
 | 
					 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                        ctx.arcTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topRight.value + halfLineWidth) * scale, config.cornerRadius.topRight.value * scale);
 | 
					                        ctx.arcTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topRight.value + halfLineWidth) * scale, config.cornerRadius.topRight.value * scale);
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Right border
 | 
					                    // Right border
 | 
				
			||||||
                    if (config.right.width.value > 0) {
 | 
					                    if (config.width.right.value > 0) {
 | 
				
			||||||
                        let color = config.right.color;
 | 
					                        let lineWidth = config.width.right.value;
 | 
				
			||||||
                        let lineWidth = config.right.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
| 
						 | 
					@ -672,8 +709,7 @@
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Bottom Right Corner
 | 
					                    // Bottom Right Corner
 | 
				
			||||||
                    if (config.cornerRadius.bottomRight.value > 0) {
 | 
					                    if (config.cornerRadius.bottomRight.value > 0) {
 | 
				
			||||||
                        let color = config.top.color;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.bottomRight.value - halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.bottomRight.value - halfLineWidth) * scale);
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
| 
						 | 
					@ -682,9 +718,8 @@
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Bottom Border
 | 
					                    // Bottom Border
 | 
				
			||||||
                    if (config.bottom.width.value > 0) {
 | 
					                    if (config.width.bottom.value > 0) {
 | 
				
			||||||
                        let color = config.bottom.color;
 | 
					                        let lineWidth = config.width.bottom.value;
 | 
				
			||||||
                        let lineWidth = config.bottom.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
| 
						 | 
					@ -694,8 +729,7 @@
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Bottom Left Corner
 | 
					                    // Bottom Left Corner
 | 
				
			||||||
                    if (config.cornerRadius.bottomLeft.value > 0) {
 | 
					                    if (config.cornerRadius.bottomLeft.value > 0) {
 | 
				
			||||||
                        let color = config.bottom.color;
 | 
					                        let lineWidth = config.width.bottom.value;
 | 
				
			||||||
                        let lineWidth = config.bottom.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.bottomLeft.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.bottomLeft.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale);
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
| 
						 | 
					@ -704,9 +738,8 @@
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Left Border
 | 
					                    // Left Border
 | 
				
			||||||
                    if (config.left.width.value > 0) {
 | 
					                    if (config.width.left.value > 0) {
 | 
				
			||||||
                        let color = config.left.color;
 | 
					                        let lineWidth = config.width.left.value;
 | 
				
			||||||
                        let lineWidth = config.left.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
| 
						 | 
					@ -718,8 +751,8 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, textConfigDefinition);
 | 
					                    let config = renderCommand.renderData.text;
 | 
				
			||||||
                    let textContents = renderCommand.text;
 | 
					                    let textContents = config.stringContents;
 | 
				
			||||||
                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
 | 
					                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
 | 
				
			||||||
                    let fontSize = config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR * scale;
 | 
					                    let fontSize = config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR * scale;
 | 
				
			||||||
                    ctx.font = `${fontSize}px ${fontsById[config.fontId.value]}`;
 | 
					                    ctx.font = `${fontSize}px ${fontsById[config.fontId.value]}`;
 | 
				
			||||||
| 
						 | 
					@ -742,8 +775,9 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, imageConfigDefinition);
 | 
					                    let config = renderCommand.renderData.image;
 | 
				
			||||||
                    let src = textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.sourceURL.chars.value, config.sourceURL.chars.value + config.sourceURL.length.value)));
 | 
					                    let imageURL = readStructAtAddress(config.imageData.value, stringDefinition);
 | 
				
			||||||
 | 
					                    let src = textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(imageURL.chars.value, imageURL.chars.value + imageURL.length.value)));
 | 
				
			||||||
                    if (!imageCache[src]) {
 | 
					                    if (!imageCache[src]) {
 | 
				
			||||||
                        imageCache[src] = {
 | 
					                        imageCache[src] = {
 | 
				
			||||||
                            image: new Image(),
 | 
					                            image: new Image(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -86,6 +86,10 @@
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
    let elementCache = {};
 | 
					    let elementCache = {};
 | 
				
			||||||
    let imageCache = {};
 | 
					    let imageCache = {};
 | 
				
			||||||
 | 
					    let dimensionsDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        {name: 'width', type: 'float'},
 | 
				
			||||||
 | 
					        {name: 'height', type: 'float'},
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
    let colorDefinition = { type: 'struct', members: [
 | 
					    let colorDefinition = { type: 'struct', members: [
 | 
				
			||||||
        {name: 'r', type: 'float' },
 | 
					        {name: 'r', type: 'float' },
 | 
				
			||||||
        {name: 'g', type: 'float' },
 | 
					        {name: 'g', type: 'float' },
 | 
				
			||||||
| 
						 | 
					@ -101,9 +105,12 @@
 | 
				
			||||||
        {name: 'chars', type: 'uint32_t' },
 | 
					        {name: 'chars', type: 'uint32_t' },
 | 
				
			||||||
        {name: 'baseChars', type: 'uint32_t' },
 | 
					        {name: 'baseChars', type: 'uint32_t' },
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let borderDefinition = { type: 'struct', members: [
 | 
					    let borderWidthDefinition = { type: 'struct', members: [
 | 
				
			||||||
        {name: 'width', type: 'uint32_t'},
 | 
					        {name: 'left', type: 'uint16_t'},
 | 
				
			||||||
        {name: 'color', ...colorDefinition},
 | 
					        {name: 'right', type: 'uint16_t'},
 | 
				
			||||||
 | 
					        {name: 'top', type: 'uint16_t'},
 | 
				
			||||||
 | 
					        {name: 'bottom', type: 'uint16_t'},
 | 
				
			||||||
 | 
					        {name: 'betweenChildren', type: 'uint16_t'},
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let cornerRadiusDefinition = { type: 'struct', members: [
 | 
					    let cornerRadiusDefinition = { type: 'struct', members: [
 | 
				
			||||||
        {name: 'topLeft', type: 'float'},
 | 
					        {name: 'topLeft', type: 'float'},
 | 
				
			||||||
| 
						 | 
					@ -111,44 +118,53 @@
 | 
				
			||||||
        {name: 'bottomLeft', type: 'float'},
 | 
					        {name: 'bottomLeft', type: 'float'},
 | 
				
			||||||
        {name: 'bottomRight', type: 'float'},
 | 
					        {name: 'bottomRight', type: 'float'},
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let rectangleConfigDefinition = { name: 'rectangle', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'color', ...colorDefinition },
 | 
					 | 
				
			||||||
        { name: 'link', ...stringDefinition },
 | 
					 | 
				
			||||||
        { name: 'cursorPointer', type: 'uint8_t' },
 | 
					 | 
				
			||||||
    ]};
 | 
					 | 
				
			||||||
    let borderConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'left', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'right', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'top', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'bottom', ...borderDefinition },
 | 
					 | 
				
			||||||
        { name: 'betweenChildren', ...borderDefinition },
 | 
					 | 
				
			||||||
    ]};
 | 
					 | 
				
			||||||
    let textConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
					    let textConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
				
			||||||
       { name: 'textColor', ...colorDefinition },
 | 
					        { name: 'textColor', ...colorDefinition },
 | 
				
			||||||
       { name: 'fontId', type: 'uint16_t' },
 | 
					        { name: 'fontId', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'fontSize', type: 'uint16_t' },
 | 
					        { name: 'fontSize', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'letterSpacing', type: 'uint16_t' },
 | 
					        { name: 'letterSpacing', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'lineSpacing', type: 'uint16_t' },
 | 
					        { name: 'lineSpacing', type: 'uint16_t' },
 | 
				
			||||||
       { name: 'wrapMode', type: 'uint32_t' },
 | 
					        { name: 'wrapMode', type: 'uint8_t' },
 | 
				
			||||||
       { name: 'disablePointerEvents', type: 'uint8_t' }
 | 
					        { name: 'disablePointerEvents', type: 'uint8_t' },
 | 
				
			||||||
 | 
					        { name: '_padding', type: 'uint16_t' },
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let scrollConfigDefinition = { name: 'text', type: 'struct', members: [
 | 
					    let textRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'stringContents', ...stringSliceDefinition },
 | 
				
			||||||
 | 
					        { name: 'textColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'fontId', type: 'uint16_t' },
 | 
				
			||||||
 | 
					        { name: 'fontSize', type: 'uint16_t' },
 | 
				
			||||||
 | 
					        { name: 'letterSpacing', type: 'uint16_t' },
 | 
				
			||||||
 | 
					        { name: 'lineHeight', type: 'uint16_t' },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let rectangleRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'backgroundColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let imageRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'backgroundColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					        { name: 'sourceDimensions', ...dimensionsDefinition },
 | 
				
			||||||
 | 
					        { name: 'imageData', type: 'uint32_t' },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let customRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'backgroundColor', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					        { name: 'customData', type: 'uint32_t' },
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let borderRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
 | 
					        { name: 'color', ...colorDefinition },
 | 
				
			||||||
 | 
					        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
				
			||||||
 | 
					        { name: 'width', ...borderWidthDefinition },
 | 
				
			||||||
 | 
					        { name: 'padding', type: 'uint16_t'}
 | 
				
			||||||
 | 
					    ]};
 | 
				
			||||||
 | 
					    let scrollRenderDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
        { name: 'horizontal', type: 'bool' },
 | 
					        { name: 'horizontal', type: 'bool' },
 | 
				
			||||||
        { name: 'vertical', type: 'bool' },
 | 
					        { name: 'vertical', type: 'bool' },
 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let imageConfigDefinition = { name: 'image', type: 'struct', members: [
 | 
					    let customHTMLDataDefinition = { type: 'struct', members: [
 | 
				
			||||||
        { name: 'imageData', type: 'uint32_t' },
 | 
					        { name: 'link', ...stringDefinition },
 | 
				
			||||||
        { name: 'sourceDimensions', type: 'struct', members: [
 | 
					        { name: 'cursorPointer', type: 'uint8_t' },
 | 
				
			||||||
            { name: 'width', type: 'float' },
 | 
					        { name: 'disablePointerEvents', type: 'uint8_t' },
 | 
				
			||||||
            { name: 'height', type: 'float' },
 | 
					 | 
				
			||||||
        ]},
 | 
					 | 
				
			||||||
        { name: 'sourceURL', ...stringDefinition }
 | 
					 | 
				
			||||||
    ]};
 | 
					 | 
				
			||||||
    let customConfigDefinition = { name: 'custom', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'customData', type: 'uint32_t' },
 | 
					 | 
				
			||||||
    ]}
 | 
					 | 
				
			||||||
    let sharedConfigDefinition = { name: 'shared', type: 'struct', members: [
 | 
					 | 
				
			||||||
        { name: 'cornerRadius', ...cornerRadiusDefinition },
 | 
					 | 
				
			||||||
    ]};
 | 
					    ]};
 | 
				
			||||||
    let renderCommandDefinition = {
 | 
					    let renderCommandDefinition = {
 | 
				
			||||||
        name: 'CLay_RenderCommand',
 | 
					        name: 'CLay_RenderCommand',
 | 
				
			||||||
| 
						 | 
					@ -160,14 +176,19 @@
 | 
				
			||||||
                { name: 'width', type: 'float' },
 | 
					                { name: 'width', type: 'float' },
 | 
				
			||||||
                { name: 'height', type: 'float' },
 | 
					                { name: 'height', type: 'float' },
 | 
				
			||||||
            ]},
 | 
					            ]},
 | 
				
			||||||
            { name: 'config', type: 'uint32_t'},
 | 
					            { name: 'renderData', type: 'union', members: [
 | 
				
			||||||
            { name: 'textOrSharedConfig', type: 'union', members: [
 | 
					                { name: 'rectangle', ...rectangleRenderDataDefinition },
 | 
				
			||||||
                { name: 'text', ...stringSliceDefinition },
 | 
					                { name: 'text', ...textRenderDataDefinition },
 | 
				
			||||||
                { name: 'sharedConfig', type: 'uint32_t' }
 | 
					                { name: 'image', ...imageRenderDataDefinition },
 | 
				
			||||||
 | 
					                { name: 'custom', ...customRenderDataDefinition },
 | 
				
			||||||
 | 
					                { name: 'border', ...borderRenderDataDefinition },
 | 
				
			||||||
 | 
					                { name: 'scroll', ...scrollRenderDataDefinition },
 | 
				
			||||||
            ]},
 | 
					            ]},
 | 
				
			||||||
            { name: 'zIndex', type: 'int32_t' },
 | 
					            { name: 'userData', type: 'uint32_t'},
 | 
				
			||||||
            { name: 'id', type: 'uint32_t' },
 | 
					            { name: 'id', type: 'uint32_t' },
 | 
				
			||||||
            { name: 'commandType', type: 'uint32_t', },
 | 
					            { name: 'zIndex', type: 'int16_t' },
 | 
				
			||||||
 | 
					            { name: 'commandType', type: 'uint8_t' },
 | 
				
			||||||
 | 
					            { name: '_padding', type: 'uint8_t' },
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,6 +211,7 @@
 | 
				
			||||||
            case 'uint32_t': return 4;
 | 
					            case 'uint32_t': return 4;
 | 
				
			||||||
            case 'int32_t': return 4;
 | 
					            case 'int32_t': return 4;
 | 
				
			||||||
            case 'uint16_t': return 2;
 | 
					            case 'uint16_t': return 2;
 | 
				
			||||||
 | 
					            case 'int16_t': return 2;
 | 
				
			||||||
            case 'uint8_t': return 1;
 | 
					            case 'uint8_t': return 1;
 | 
				
			||||||
            case 'bool': return 1;
 | 
					            case 'bool': return 1;
 | 
				
			||||||
            default: {
 | 
					            default: {
 | 
				
			||||||
| 
						 | 
					@ -219,6 +241,7 @@
 | 
				
			||||||
            case 'uint32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
					            case 'uint32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
				
			||||||
            case 'int32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
					            case 'int32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
 | 
				
			||||||
            case 'uint16_t': return { value: memoryDataView.getUint16(address, true), __size: 2 };
 | 
					            case 'uint16_t': return { value: memoryDataView.getUint16(address, true), __size: 2 };
 | 
				
			||||||
 | 
					            case 'int16_t': return { value: memoryDataView.getInt16(address, true), __size: 2 };
 | 
				
			||||||
            case 'uint8_t': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
					            case 'uint8_t': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
				
			||||||
            case 'bool': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
					            case 'bool': return { value: memoryDataView.getUint8(address, true), __size: 1 };
 | 
				
			||||||
            default: {
 | 
					            default: {
 | 
				
			||||||
| 
						 | 
					@ -340,7 +363,7 @@
 | 
				
			||||||
                        memoryDataView.setFloat32(addressOfOffset, -container.scrollLeft, true);
 | 
					                        memoryDataView.setFloat32(addressOfOffset, -container.scrollLeft, true);
 | 
				
			||||||
                        memoryDataView.setFloat32(addressOfOffset + 4, -container.scrollTop, true);
 | 
					                        memoryDataView.setFloat32(addressOfOffset + 4, -container.scrollTop, true);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        const { instance } = await WebAssembly.instantiateStreaming(
 | 
					        const { instance } = await WebAssembly.instantiateStreaming(
 | 
				
			||||||
| 
						 | 
					@ -348,13 +371,15 @@
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        memoryDataView = new DataView(new Uint8Array(instance.exports.memory.buffer).buffer);
 | 
					        memoryDataView = new DataView(new Uint8Array(instance.exports.memory.buffer).buffer);
 | 
				
			||||||
        scratchSpaceAddress = instance.exports.__heap_base.value;
 | 
					        scratchSpaceAddress = instance.exports.__heap_base.value;
 | 
				
			||||||
        heapSpaceAddress = instance.exports.__heap_base.value + 1024;
 | 
					        let clayScratchSpaceAddress = instance.exports.__heap_base.value + 1024;
 | 
				
			||||||
 | 
					        heapSpaceAddress = instance.exports.__heap_base.value + 2048;
 | 
				
			||||||
        let arenaAddress = scratchSpaceAddress + 8;
 | 
					        let arenaAddress = scratchSpaceAddress + 8;
 | 
				
			||||||
        window.instance = instance;
 | 
					        window.instance = instance;
 | 
				
			||||||
        createMainArena(arenaAddress, heapSpaceAddress);
 | 
					        createMainArena(arenaAddress, heapSpaceAddress);
 | 
				
			||||||
        memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
 | 
					        memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
 | 
				
			||||||
        memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
 | 
					        memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
 | 
				
			||||||
        instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
 | 
					        instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
 | 
				
			||||||
 | 
					        instance.exports.SetScratchMemory(arenaAddress, clayScratchSpaceAddress);
 | 
				
			||||||
        renderCommandSize = getStructTotalSize(renderCommandDefinition);
 | 
					        renderCommandSize = getStructTotalSize(renderCommandDefinition);
 | 
				
			||||||
        renderLoop();
 | 
					        renderLoop();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -368,6 +393,22 @@
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function SetElementBackgroundColorAndRadius(element, cornerRadius, backgroundColor) {
 | 
				
			||||||
 | 
					        element.style.backgroundColor = `rgba(${backgroundColor.r.value}, ${backgroundColor.g.value}, ${backgroundColor.b.value}, ${backgroundColor.a.value / 255})`;
 | 
				
			||||||
 | 
					        if (cornerRadius.topLeft.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderTopLeftRadius = cornerRadius.topLeft.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (cornerRadius.topRight.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderTopRightRadius = cornerRadius.topRight.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (cornerRadius.bottomLeft.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderBottomLeftRadius = cornerRadius.bottomLeft.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (cornerRadius.bottomRight.value > 0) {
 | 
				
			||||||
 | 
					            element.style.borderBottomRightRadius = cornerRadius.bottomRight.value + 'px';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    function renderLoopHTML() {
 | 
					    function renderLoopHTML() {
 | 
				
			||||||
        let capacity = memoryDataView.getInt32(scratchSpaceAddress, true);
 | 
					        let capacity = memoryDataView.getInt32(scratchSpaceAddress, true);
 | 
				
			||||||
        let length = memoryDataView.getInt32(scratchSpaceAddress + 4, true);
 | 
					        let length = memoryDataView.getInt32(scratchSpaceAddress + 4, true);
 | 
				
			||||||
| 
						 | 
					@ -375,7 +416,7 @@
 | 
				
			||||||
        let scissorStack = [{ nextAllocation: { x: 0, y: 0 }, element: htmlRoot, nextElementIndex: 0 }];
 | 
					        let scissorStack = [{ nextAllocation: { x: 0, y: 0 }, element: htmlRoot, nextElementIndex: 0 }];
 | 
				
			||||||
        let previousId = 0;
 | 
					        let previousId = 0;
 | 
				
			||||||
        for (let i = 0; i < length; i++, arrayOffset += renderCommandSize) {
 | 
					        for (let i = 0; i < length; i++, arrayOffset += renderCommandSize) {
 | 
				
			||||||
            let entireRenderCommandMemory = new Uint32Array(memoryDataView.buffer.slice(arrayOffset, arrayOffset + renderCommandSize));
 | 
					            let entireRenderCommandMemory = new Uint8Array(memoryDataView.buffer.slice(arrayOffset, arrayOffset + renderCommandSize));
 | 
				
			||||||
            let renderCommand = readStructAtAddress(arrayOffset, renderCommandDefinition);
 | 
					            let renderCommand = readStructAtAddress(arrayOffset, renderCommandDefinition);
 | 
				
			||||||
            let parentElement = scissorStack[scissorStack.length - 1];
 | 
					            let parentElement = scissorStack[scissorStack.length - 1];
 | 
				
			||||||
            let element = null;
 | 
					            let element = null;
 | 
				
			||||||
| 
						 | 
					@ -384,13 +425,12 @@
 | 
				
			||||||
                let elementType = 'div';
 | 
					                let elementType = 'div';
 | 
				
			||||||
                switch (renderCommand.commandType.value & 0xff) {
 | 
					                switch (renderCommand.commandType.value & 0xff) {
 | 
				
			||||||
                    case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
 | 
					                    case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
 | 
				
			||||||
                        if (readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition).link.length.value > 0) {
 | 
					                        // if (readStructAtAddress(renderCommand.renderData.rectangle.value, rectangleRenderDataDefinition).link.length.value > 0) { TODO reimplement links
 | 
				
			||||||
                            elementType = 'a';
 | 
					                        //     elementType = 'a';
 | 
				
			||||||
                        }
 | 
					                        // }
 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
 | 
					                    case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
 | 
				
			||||||
                        console.log('test5');
 | 
					 | 
				
			||||||
                        elementType = 'img'; break;
 | 
					                        elementType = 'img'; break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    default: break;
 | 
					                    default: break;
 | 
				
			||||||
| 
						 | 
					@ -443,93 +483,82 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition);
 | 
					                    let config = renderCommand.renderData.rectangle;
 | 
				
			||||||
                    let sharedConfig = readStructAtAddress( renderCommand.textOrSharedConfig.sharedConfig.value, sharedConfigDefinition);
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
                    let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
 | 
					                    if (configMemory === elementData.previousMemoryConfig) {
 | 
				
			||||||
                    let linkContents = config.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.link.chars.value, config.link.chars.value + config.link.length.value))) : 0;
 | 
					 | 
				
			||||||
                    memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
					 | 
				
			||||||
                    if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
					 | 
				
			||||||
                        window.location.href = linkContents;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (!dirty && !MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
 | 
					 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (linkContents.length > 0) {
 | 
					
 | 
				
			||||||
                        element.href = linkContents;
 | 
					                    SetElementBackgroundColorAndRadius(element, config.cornerRadius, config.backgroundColor);
 | 
				
			||||||
 | 
					                    if (renderCommand.userData.value !== 0) {
 | 
				
			||||||
 | 
					                        let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        let linkContents = customData.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(customData.link.chars.value, customData.link.chars.value + customData.link.length.value))) : 0;
 | 
				
			||||||
 | 
					                        memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
				
			||||||
 | 
					                            window.location.href = linkContents;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0) {
 | 
				
			||||||
 | 
					                            element.href = linkContents;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0 || customData.cursorPointer.value) {
 | 
				
			||||||
 | 
					                            element.style.pointerEvents = 'all';
 | 
				
			||||||
 | 
					                            element.style.cursor = 'pointer';
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (linkContents.length > 0 || config.cursorPointer.value) {
 | 
					 | 
				
			||||||
                        element.style.pointerEvents = 'all';
 | 
					 | 
				
			||||||
                        element.style.cursor = 'pointer';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    elementData.previousMemoryConfig = configMemory;
 | 
					                    elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    let color = config.color;
 | 
					
 | 
				
			||||||
                    element.style.backgroundColor = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topLeft.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderTopLeftRadius = sharedConfig.cornerRadius.topLeft.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topRight.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderTopRightRadius = sharedConfig.cornerRadius.topRight.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomLeft.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderBottomLeftRadius = sharedConfig.cornerRadius.bottomLeft.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomRight.value > 0) {
 | 
					 | 
				
			||||||
                        element.style.borderBottomRightRadius = sharedConfig.cornerRadius.bottomRight.value + 'px';
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, borderConfigDefinition);
 | 
					                    let config = renderCommand.renderData.border;
 | 
				
			||||||
                    let sharedConfig = readStructAtAddress( renderCommand.textOrSharedConfig.sharedConfig.value, sharedConfigDefinition);
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
                    let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
 | 
					                    if (configMemory === elementData.previousMemoryConfig) {
 | 
				
			||||||
                    if (!dirty && !MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
 | 
					 | 
				
			||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    let color = config.color;
 | 
				
			||||||
                    elementData.previousMemoryConfig = configMemory;
 | 
					                    elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    if (config.left.width.value > 0) {
 | 
					                    if (config.width.left.value > 0) {
 | 
				
			||||||
                        let color = config.left.color;
 | 
					                        element.style.borderLeft = `${config.width.left.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderLeft = `${config.left.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (config.right.width.value > 0) {
 | 
					                    if (config.width.right.value > 0) {
 | 
				
			||||||
                        let color = config.right.color;
 | 
					                        element.style.borderRight = `${config.width.right.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderRight = `${config.right.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (config.top.width.value > 0) {
 | 
					                    if (config.width.top.value > 0) {
 | 
				
			||||||
                        let color = config.top.color;
 | 
					                        element.style.borderTop = `${config.width.top.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderTop = `${config.top.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (config.bottom.width.value > 0) {
 | 
					                    if (config.width.bottom.value > 0) {
 | 
				
			||||||
                        let color = config.bottom.color;
 | 
					                        element.style.borderBottom = `${config.width.bottom.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
				
			||||||
                        element.style.borderBottom = `${config.bottom.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topLeft.value > 0) {
 | 
					                    if (config.cornerRadius.topLeft.value > 0) {
 | 
				
			||||||
                        element.style.borderTopLeftRadius = sharedConfig.cornerRadius.topLeft.value + 'px';
 | 
					                        element.style.borderTopLeftRadius = config.cornerRadius.topLeft.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.topRight.value > 0) {
 | 
					                    if (config.cornerRadius.topRight.value > 0) {
 | 
				
			||||||
                        element.style.borderTopRightRadius = sharedConfig.cornerRadius.topRight.value + 'px';
 | 
					                        element.style.borderTopRightRadius = config.cornerRadius.topRight.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomLeft.value > 0) {
 | 
					                    if (config.cornerRadius.bottomLeft.value > 0) {
 | 
				
			||||||
                        element.style.borderBottomLeftRadius = sharedConfig.cornerRadius.bottomLeft.value + 'px';
 | 
					                        element.style.borderBottomLeftRadius = config.cornerRadius.bottomLeft.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (sharedConfig.cornerRadius.bottomRight.value > 0) {
 | 
					                    if (config.cornerRadius.bottomRight.value > 0) {
 | 
				
			||||||
                        element.style.borderBottomRightRadius = sharedConfig.cornerRadius.bottomRight.value + 'px';
 | 
					                        element.style.borderBottomRightRadius = config.cornerRadius.bottomRight.value + 'px';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, textConfigDefinition);
 | 
					                    let config = renderCommand.renderData.text;
 | 
				
			||||||
                    let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
 | 
					                    let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
 | 
				
			||||||
                    let textContents = renderCommand.textOrSharedConfig.text;
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
 | 
					                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(config.stringContents.chars.value, config.stringContents.chars.value + config.stringContents.length.value));
 | 
				
			||||||
                    if (MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
 | 
					                    if (configMemory !== elementData.previousMemoryConfig) {
 | 
				
			||||||
                        element.className = 'text';
 | 
					                        element.className = 'text';
 | 
				
			||||||
                        let textColor = config.textColor;
 | 
					                        let textColor = config.textColor;
 | 
				
			||||||
                        let fontSize = Math.round(config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR);
 | 
					                        let fontSize = Math.round(config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR);
 | 
				
			||||||
                        element.style.color = `rgba(${textColor.r.value}, ${textColor.g.value}, ${textColor.b.value}, ${textColor.a.value})`;
 | 
					                        element.style.color = `rgba(${textColor.r.value}, ${textColor.g.value}, ${textColor.b.value}, ${textColor.a.value})`;
 | 
				
			||||||
                        element.style.fontFamily = fontsById[config.fontId.value];
 | 
					                        element.style.fontFamily = fontsById[config.fontId.value];
 | 
				
			||||||
                        element.style.fontSize = fontSize + 'px';
 | 
					                        element.style.fontSize = fontSize + 'px';
 | 
				
			||||||
                        element.style.pointerEvents = config.disablePointerEvents.value ? 'none' : 'all';
 | 
					                        element.style.pointerEvents = customData.disablePointerEvents.value ? 'none' : 'all';
 | 
				
			||||||
                        elementData.previousMemoryConfig = configMemory;
 | 
					                        elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (stringContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(stringContents, elementData.previousMemoryText, stringContents.length)) {
 | 
					                    if (stringContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(stringContents, elementData.previousMemoryText, stringContents.length)) {
 | 
				
			||||||
| 
						 | 
					@ -540,7 +569,11 @@
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
 | 
				
			||||||
                    scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
 | 
					                    scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, scrollConfigDefinition);
 | 
					                    let config = renderCommand.renderData.scroll;
 | 
				
			||||||
 | 
					                    let configMemory = JSON.stringify(config);
 | 
				
			||||||
 | 
					                    if (configMemory === elementData.previousMemoryConfig) {
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                    if (config.horizontal.value) {
 | 
					                    if (config.horizontal.value) {
 | 
				
			||||||
                        element.style.overflowX = 'scroll';
 | 
					                        element.style.overflowX = 'scroll';
 | 
				
			||||||
                        element.style.pointerEvents = 'auto';
 | 
					                        element.style.pointerEvents = 'auto';
 | 
				
			||||||
| 
						 | 
					@ -549,6 +582,7 @@
 | 
				
			||||||
                        element.style.overflowY = 'scroll';
 | 
					                        element.style.overflowY = 'scroll';
 | 
				
			||||||
                        element.style.pointerEvents = 'auto';
 | 
					                        element.style.pointerEvents = 'auto';
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    elementData.previousMemoryConfig = configMemory;
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_END): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_END): {
 | 
				
			||||||
| 
						 | 
					@ -556,9 +590,9 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
				
			||||||
                    console.log('test1');
 | 
					                    let config = renderCommand.renderData.image;
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, imageConfigDefinition);
 | 
					                    let imageURL = readStructAtAddress(config.imageData.value, stringDefinition);
 | 
				
			||||||
                    let srcContents = new Uint8Array(memoryDataView.buffer.slice(config.sourceURL.chars.value, config.sourceURL.chars.value + config.sourceURL.length.value));
 | 
					                    let srcContents = new Uint8Array(memoryDataView.buffer.slice(imageURL.chars.value, imageURL.chars.value + imageURL.length.value));
 | 
				
			||||||
                    if (srcContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(srcContents, elementData.previousMemoryText, srcContents.length)) {
 | 
					                    if (srcContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(srcContents, elementData.previousMemoryText, srcContents.length)) {
 | 
				
			||||||
                        element.src = textDecoder.decode(srcContents);
 | 
					                        element.src = textDecoder.decode(srcContents);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
| 
						 | 
					@ -566,6 +600,9 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_CUSTOM): break;
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_CUSTOM): break;
 | 
				
			||||||
 | 
					                default: {
 | 
				
			||||||
 | 
					                    console.log("Error: unhandled render command");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -602,8 +639,8 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition);
 | 
					                    let config = renderCommand.renderData.rectangle;
 | 
				
			||||||
                    let color = config.color;
 | 
					                    let color = config.backgroundColor;
 | 
				
			||||||
                    ctx.beginPath();
 | 
					                    ctx.beginPath();
 | 
				
			||||||
                    window.canvasContext.fillStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                    window.canvasContext.fillStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                    window.canvasContext.roundRect(
 | 
					                    window.canvasContext.roundRect(
 | 
				
			||||||
| 
						 | 
					@ -615,33 +652,35 @@
 | 
				
			||||||
                    ctx.fill();
 | 
					                    ctx.fill();
 | 
				
			||||||
                    ctx.closePath();
 | 
					                    ctx.closePath();
 | 
				
			||||||
                    // Handle link clicks
 | 
					                    // Handle link clicks
 | 
				
			||||||
                    let linkContents = config.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.link.chars.value, config.link.chars.value + config.link.length.value))) : 0;
 | 
					                    if (renderCommand.userData.value !== 0) {
 | 
				
			||||||
                    memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
					                        let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
 | 
				
			||||||
                    if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
					                        let linkContents = customData.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(customData.link.chars.value, customData.link.chars.value + customData.link.length.value))) : 0;
 | 
				
			||||||
                        window.location.href = linkContents;
 | 
					                        memoryDataView.setUint32(0, renderCommand.id.value, true);
 | 
				
			||||||
 | 
					                        if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
 | 
				
			||||||
 | 
					                            window.location.href = linkContents;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, borderConfigDefinition);
 | 
					                    let config = renderCommand.renderData.border;
 | 
				
			||||||
 | 
					                    let color = config.color;
 | 
				
			||||||
                    ctx.beginPath();
 | 
					                    ctx.beginPath();
 | 
				
			||||||
                    ctx.moveTo(boundingBox.x.value * scale, boundingBox.y.value * scale);
 | 
					                    ctx.moveTo(boundingBox.x.value * scale, boundingBox.y.value * scale);
 | 
				
			||||||
                    // Top Left Corner
 | 
					                    // Top Left Corner
 | 
				
			||||||
                    if (config.cornerRadius.topLeft.value > 0) {
 | 
					                    if (config.cornerRadius.topLeft.value > 0) {
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale);
 | 
				
			||||||
                        let color = config.top.color;
 | 
					 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                        ctx.arcTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, config.cornerRadius.topLeft.value * scale);
 | 
					                        ctx.arcTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, config.cornerRadius.topLeft.value * scale);
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Top border
 | 
					                    // Top border
 | 
				
			||||||
                    if (config.top.width.value > 0) {
 | 
					                    if (config.width.top.value > 0) {
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        let color = config.top.color;
 | 
					 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
				
			||||||
| 
						 | 
					@ -650,19 +689,17 @@
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Top Right Corner
 | 
					                    // Top Right Corner
 | 
				
			||||||
                    if (config.cornerRadius.topRight.value > 0) {
 | 
					                    if (config.cornerRadius.topRight.value > 0) {
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - config.cornerRadius.topRight.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - config.cornerRadius.topRight.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
 | 
				
			||||||
                        let color = config.top.color;
 | 
					 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
                        ctx.arcTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topRight.value + halfLineWidth) * scale, config.cornerRadius.topRight.value * scale);
 | 
					                        ctx.arcTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topRight.value + halfLineWidth) * scale, config.cornerRadius.topRight.value * scale);
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Right border
 | 
					                    // Right border
 | 
				
			||||||
                    if (config.right.width.value > 0) {
 | 
					                    if (config.width.right.value > 0) {
 | 
				
			||||||
                        let color = config.right.color;
 | 
					                        let lineWidth = config.width.right.value;
 | 
				
			||||||
                        let lineWidth = config.right.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
| 
						 | 
					@ -672,8 +709,7 @@
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Bottom Right Corner
 | 
					                    // Bottom Right Corner
 | 
				
			||||||
                    if (config.cornerRadius.bottomRight.value > 0) {
 | 
					                    if (config.cornerRadius.bottomRight.value > 0) {
 | 
				
			||||||
                        let color = config.top.color;
 | 
					                        let lineWidth = config.width.top.value;
 | 
				
			||||||
                        let lineWidth = config.top.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.bottomRight.value - halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.bottomRight.value - halfLineWidth) * scale);
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
| 
						 | 
					@ -682,9 +718,8 @@
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Bottom Border
 | 
					                    // Bottom Border
 | 
				
			||||||
                    if (config.bottom.width.value > 0) {
 | 
					                    if (config.width.bottom.value > 0) {
 | 
				
			||||||
                        let color = config.bottom.color;
 | 
					                        let lineWidth = config.width.bottom.value;
 | 
				
			||||||
                        let lineWidth = config.bottom.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
| 
						 | 
					@ -694,8 +729,7 @@
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Bottom Left Corner
 | 
					                    // Bottom Left Corner
 | 
				
			||||||
                    if (config.cornerRadius.bottomLeft.value > 0) {
 | 
					                    if (config.cornerRadius.bottomLeft.value > 0) {
 | 
				
			||||||
                        let color = config.bottom.color;
 | 
					                        let lineWidth = config.width.bottom.value;
 | 
				
			||||||
                        let lineWidth = config.bottom.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.bottomLeft.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale);
 | 
					                        ctx.moveTo((boundingBox.x.value + config.cornerRadius.bottomLeft.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale);
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
| 
						 | 
					@ -704,9 +738,8 @@
 | 
				
			||||||
                        ctx.stroke();
 | 
					                        ctx.stroke();
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    // Left Border
 | 
					                    // Left Border
 | 
				
			||||||
                    if (config.left.width.value > 0) {
 | 
					                    if (config.width.left.value > 0) {
 | 
				
			||||||
                        let color = config.left.color;
 | 
					                        let lineWidth = config.width.left.value;
 | 
				
			||||||
                        let lineWidth = config.left.width.value;
 | 
					 | 
				
			||||||
                        let halfLineWidth = lineWidth / 2;
 | 
					                        let halfLineWidth = lineWidth / 2;
 | 
				
			||||||
                        ctx.lineWidth = lineWidth * scale;
 | 
					                        ctx.lineWidth = lineWidth * scale;
 | 
				
			||||||
                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
					                        ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
 | 
				
			||||||
| 
						 | 
					@ -718,8 +751,8 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, textConfigDefinition);
 | 
					                    let config = renderCommand.renderData.text;
 | 
				
			||||||
                    let textContents = renderCommand.text;
 | 
					                    let textContents = config.stringContents;
 | 
				
			||||||
                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
 | 
					                    let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
 | 
				
			||||||
                    let fontSize = config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR * scale;
 | 
					                    let fontSize = config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR * scale;
 | 
				
			||||||
                    ctx.font = `${fontSize}px ${fontsById[config.fontId.value]}`;
 | 
					                    ctx.font = `${fontSize}px ${fontsById[config.fontId.value]}`;
 | 
				
			||||||
| 
						 | 
					@ -742,8 +775,9 @@
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
					                case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
 | 
				
			||||||
                    let config = readStructAtAddress(renderCommand.config.value, imageConfigDefinition);
 | 
					                    let config = renderCommand.renderData.image;
 | 
				
			||||||
                    let src = textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.sourceURL.chars.value, config.sourceURL.chars.value + config.sourceURL.length.value)));
 | 
					                    let imageURL = readStructAtAddress(config.imageData.value, stringDefinition);
 | 
				
			||||||
 | 
					                    let src = textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(imageURL.chars.value, imageURL.chars.value + imageURL.length.value)));
 | 
				
			||||||
                    if (!imageCache[src]) {
 | 
					                    if (!imageCache[src]) {
 | 
				
			||||||
                        imageCache[src] = {
 | 
					                        imageCache[src] = {
 | 
				
			||||||
                            image: new Image(),
 | 
					                            image: new Image(),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
double windowWidth = 1024, windowHeight = 768;
 | 
					double windowWidth = 1024, windowHeight = 768;
 | 
				
			||||||
float modelPageOneZRotation = 0;
 | 
					float modelPageOneZRotation = 0;
 | 
				
			||||||
uint32_t ACTIVE_RENDERER_INDEX = 0;
 | 
					uint32_t ACTIVE_RENDERER_INDEX = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const uint32_t FONT_ID_BODY_16 = 0;
 | 
					const uint32_t FONT_ID_BODY_16 = 0;
 | 
				
			||||||
const uint32_t FONT_ID_TITLE_56 = 1;
 | 
					const uint32_t FONT_ID_TITLE_56 = 1;
 | 
				
			||||||
| 
						 | 
					@ -52,13 +52,21 @@ typedef struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CustomHTMLData* FrameAllocateCustomData(CustomHTMLData data) {
 | 
					CustomHTMLData* FrameAllocateCustomData(CustomHTMLData data) {
 | 
				
			||||||
    CustomHTMLData *customData = (CustomHTMLData *)(frameArena.memory + frameArena.offset);
 | 
					    CustomHTMLData *customData = (CustomHTMLData *)(frameArena.memory + frameArena.offset);
 | 
				
			||||||
 | 
					    *customData = data;
 | 
				
			||||||
    frameArena.offset += sizeof(CustomHTMLData);
 | 
					    frameArena.offset += sizeof(CustomHTMLData);
 | 
				
			||||||
    return customData;
 | 
					    return customData;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LandingPageBlob(int index, int fontSize, Clay_Color color, Clay_String text, char* imageURL) {
 | 
					Clay_String* FrameAllocateString(Clay_String string) {
 | 
				
			||||||
 | 
					    Clay_String *allocated = (Clay_String *)(frameArena.memory + frameArena.offset);
 | 
				
			||||||
 | 
					    *allocated = string;
 | 
				
			||||||
 | 
					    frameArena.offset += sizeof(Clay_String);
 | 
				
			||||||
 | 
					    return allocated;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void LandingPageBlob(int index, int fontSize, Clay_Color color, Clay_String text, Clay_String imageURL) {
 | 
				
			||||||
    CLAY({ .id = CLAY_IDI("HeroBlob", index), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 480) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }, .border = { .color = color, .width = { 2, 2, 2, 2 }}, .cornerRadius = CLAY_CORNER_RADIUS(10) }) {
 | 
					    CLAY({ .id = CLAY_IDI("HeroBlob", index), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 480) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }, .border = { .color = color, .width = { 2, 2, 2, 2 }}, .cornerRadius = CLAY_CORNER_RADIUS(10) }) {
 | 
				
			||||||
        CLAY({ .id = CLAY_IDI("CheckImage", index), .layout = { .sizing = { CLAY_SIZING_FIXED(32) } }, .image = { .sourceDimensions = { 128, 128 }, .imageData = imageURL } }) {}
 | 
					        CLAY({ .id = CLAY_IDI("CheckImage", index), .layout = { .sizing = { CLAY_SIZING_FIXED(32) } }, .image = { .sourceDimensions = { 128, 128 }, .imageData = FrameAllocateString(imageURL) } }) {}
 | 
				
			||||||
        CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = fontSize, .fontId = FONT_ID_BODY_24, .textColor = color }));
 | 
					        CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = fontSize, .fontId = FONT_ID_BODY_24, .textColor = color }));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -72,11 +80,11 @@ void LandingPageDesktop() {
 | 
				
			||||||
                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_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({ .id = CLAY_ID("HeroImageOuter"), .layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_PERCENT(0.45f) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 } }) {
 | 
					            CLAY({ .id = CLAY_ID("HeroImageOuter"), .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/images/check_5.png");
 | 
					                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/images/check_4.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/images/check_3.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/images/check_2.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/images/check_1.png");
 | 
					                LandingPageBlob(5, 32, COLOR_BLOB_BORDER_1, CLAY_STRING("Compile to 15kb .wasm"), CLAY_STRING("/clay/images/check_1.png"));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -90,11 +98,11 @@ void LandingPageMobile() {
 | 
				
			||||||
            CLAY_TEXT(CLAY_STRING("Clay is laying out this webpage right now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE }));
 | 
					            CLAY_TEXT(CLAY_STRING("Clay is laying out this webpage right now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE }));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        CLAY({ .id = CLAY_ID("HeroImageOuter"), .layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 } }) {
 | 
					        CLAY({ .id = CLAY_ID("HeroImageOuter"), .layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 } }) {
 | 
				
			||||||
            LandingPageBlob(1, 28, COLOR_BLOB_BORDER_5, CLAY_STRING("High performance"), "/clay/images/check_5.png");
 | 
					            LandingPageBlob(1, 28, COLOR_BLOB_BORDER_5, CLAY_STRING("High performance"), CLAY_STRING("/clay/images/check_5.png"));
 | 
				
			||||||
            LandingPageBlob(2, 28, COLOR_BLOB_BORDER_4, CLAY_STRING("Flexbox-style responsive layout"), "/clay/images/check_4.png");
 | 
					            LandingPageBlob(2, 28, COLOR_BLOB_BORDER_4, CLAY_STRING("Flexbox-style responsive layout"), CLAY_STRING("/clay/images/check_4.png"));
 | 
				
			||||||
            LandingPageBlob(3, 28, COLOR_BLOB_BORDER_3, CLAY_STRING("Declarative syntax"), "/clay/images/check_3.png");
 | 
					            LandingPageBlob(3, 28, COLOR_BLOB_BORDER_3, CLAY_STRING("Declarative syntax"), CLAY_STRING("/clay/images/check_3.png"));
 | 
				
			||||||
            LandingPageBlob(4, 28, COLOR_BLOB_BORDER_2, CLAY_STRING("Single .h file for C/C++"), "/clay/images/check_2.png");
 | 
					            LandingPageBlob(4, 28, COLOR_BLOB_BORDER_2, CLAY_STRING("Single .h file for C/C++"), CLAY_STRING("/clay/images/check_2.png"));
 | 
				
			||||||
            LandingPageBlob(5, 28, COLOR_BLOB_BORDER_1, CLAY_STRING("Compile to 15kb .wasm"), "/clay/images/check_1.png");
 | 
					            LandingPageBlob(5, 28, COLOR_BLOB_BORDER_1, CLAY_STRING("Compile to 15kb .wasm"), CLAY_STRING("/clay/images/check_1.png"));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -148,7 +156,7 @@ void DeclarativeSyntaxPageDesktop() {
 | 
				
			||||||
                CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
 | 
					                CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            CLAY({ .id = CLAY_ID("SyntaxPageRightImage"), .layout = { .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} } }) {
 | 
					            CLAY({ .id = CLAY_ID("SyntaxPageRightImage"), .layout = { .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} } }) {
 | 
				
			||||||
                CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .image = { .sourceDimensions = {1136, 1194}, .imageData = "/clay/images/declarative.png" } }) {}
 | 
					                CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .image = { .sourceDimensions = {1136, 1194}, .imageData = FrameAllocateString(CLAY_STRING("/clay/images/declarative.png")) } }) {}
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -164,7 +172,7 @@ void DeclarativeSyntaxPageMobile() {
 | 
				
			||||||
            CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
 | 
					            CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        CLAY({ .id = CLAY_ID("SyntaxPageRightImage"), .layout = { .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} } }) {
 | 
					        CLAY({ .id = CLAY_ID("SyntaxPageRightImage"), .layout = { .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} } }) {
 | 
				
			||||||
            CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .image = { .sourceDimensions = {1136, 1194}, .imageData = "/clay/images/declarative.png" } }) {}
 | 
					            CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .image = { .sourceDimensions = {1136, 1194}, .imageData = FrameAllocateString(CLAY_STRING("/clay/images/declarative.png")) } }) {}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -237,7 +245,7 @@ void RendererButtonActive(Clay_String text) {
 | 
				
			||||||
        .layout = { .sizing = {CLAY_SIZING_FIXED(300) }, .padding = CLAY_PADDING_ALL(16) },
 | 
					        .layout = { .sizing = {CLAY_SIZING_FIXED(300) }, .padding = CLAY_PADDING_ALL(16) },
 | 
				
			||||||
        .backgroundColor = Clay_Hovered() ? COLOR_RED_HOVER : COLOR_RED,
 | 
					        .backgroundColor = Clay_Hovered() ? COLOR_RED_HOVER : COLOR_RED,
 | 
				
			||||||
        .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
					        .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
				
			||||||
        .custom = { .customData = FrameAllocateCustomData((CustomHTMLData) { .disablePointerEvents = true, .cursorPointer = true })}
 | 
					        .userData = FrameAllocateCustomData((CustomHTMLData) { .disablePointerEvents = true, .cursorPointer = true })
 | 
				
			||||||
    }) {
 | 
					    }) {
 | 
				
			||||||
        CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
 | 
					        CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -249,7 +257,7 @@ void RendererButtonInactive(Clay_String text, size_t rendererIndex) {
 | 
				
			||||||
        .border = { .width = {2, 2, 2, 2}, .color = COLOR_RED },
 | 
					        .border = { .width = {2, 2, 2, 2}, .color = COLOR_RED },
 | 
				
			||||||
        .backgroundColor = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT,
 | 
					        .backgroundColor = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT,
 | 
				
			||||||
        .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
					        .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
				
			||||||
        .custom = { .customData = FrameAllocateCustomData((CustomHTMLData) { .disablePointerEvents = true, .cursorPointer = true })}
 | 
					        .userData = FrameAllocateCustomData((CustomHTMLData) { .disablePointerEvents = true, .cursorPointer = true })
 | 
				
			||||||
    }) {
 | 
					    }) {
 | 
				
			||||||
        Clay_OnHover(HandleRendererButtonInteraction, rendererIndex);
 | 
					        Clay_OnHover(HandleRendererButtonInteraction, rendererIndex);
 | 
				
			||||||
        CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
 | 
					        CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
 | 
				
			||||||
| 
						 | 
					@ -315,7 +323,7 @@ void DebuggerPageDesktop() {
 | 
				
			||||||
            CLAY_TEXT(CLAY_STRING("Press the \"d\" key to try it out now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE }));
 | 
					            CLAY_TEXT(CLAY_STRING("Press the \"d\" key to try it out now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE }));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        CLAY({ .id = CLAY_ID("DebuggerRightImageOuter"), .layout = { .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {CLAY_ALIGN_X_CENTER} } }) {
 | 
					        CLAY({ .id = CLAY_ID("DebuggerRightImageOuter"), .layout = { .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {CLAY_ALIGN_X_CENTER} } }) {
 | 
				
			||||||
            CLAY({ .id = CLAY_ID("DebuggerPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 558) } }, .image = { .sourceDimensions = {1620, 1474}, .imageData = "/clay/images/debugger.png" } }) {}
 | 
					            CLAY({ .id = CLAY_ID("DebuggerPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 558) } }, .image = { .sourceDimensions = {1620, 1474}, .imageData = FrameAllocateString(CLAY_STRING("/clay/images/debugger.png")) } }) {}
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -337,10 +345,10 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
 | 
				
			||||||
            CLAY_TEXT(CLAY_STRING("Clay"), &headerTextConfig);
 | 
					            CLAY_TEXT(CLAY_STRING("Clay"), &headerTextConfig);
 | 
				
			||||||
            CLAY({ .id = CLAY_ID("Spacer"), .layout = { .sizing = { .width = CLAY_SIZING_GROW(0) } } }) {}
 | 
					            CLAY({ .id = CLAY_ID("Spacer"), .layout = { .sizing = { .width = CLAY_SIZING_GROW(0) } } }) {}
 | 
				
			||||||
            if (!mobileScreen) {
 | 
					            if (!mobileScreen) {
 | 
				
			||||||
                CLAY({ .id = CLAY_ID("LinkExamplesOuter"), .layout = { .padding = {8, 8} }, .custom = { .customData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples") }) } }) {
 | 
					                CLAY({ .id = CLAY_ID("LinkExamplesOuter"), .layout = { .padding = {8, 8} }, .userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples") }) }) {
 | 
				
			||||||
                    CLAY_TEXT(CLAY_STRING("Examples"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
					                    CLAY_TEXT(CLAY_STRING("Examples"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                CLAY({ .id = CLAY_ID("LinkDocsOuter"), .layout = { .padding = {8, 8} }, .custom = { .customData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md") }) } }) {
 | 
					                CLAY({ .id = CLAY_ID("LinkDocsOuter"), .layout = { .padding = {8, 8} }, .userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md") }) }) {
 | 
				
			||||||
                    CLAY_TEXT(CLAY_STRING("Docs"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
					                    CLAY_TEXT(CLAY_STRING("Docs"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -349,7 +357,7 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
 | 
				
			||||||
                .backgroundColor = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT,
 | 
					                .backgroundColor = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT,
 | 
				
			||||||
                .border = { .width = {2, 2, 2, 2}, .color = COLOR_RED },
 | 
					                .border = { .width = {2, 2, 2, 2}, .color = COLOR_RED },
 | 
				
			||||||
                .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
					                .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
				
			||||||
                .custom = { .customData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples") }) },
 | 
					                .userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples") }),
 | 
				
			||||||
            }) {
 | 
					            }) {
 | 
				
			||||||
                CLAY_TEXT(CLAY_STRING("Discord"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
					                CLAY_TEXT(CLAY_STRING("Discord"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -358,7 +366,7 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
 | 
				
			||||||
                .backgroundColor = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT,
 | 
					                .backgroundColor = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT,
 | 
				
			||||||
                .border = { .width = {2, 2, 2, 2}, .color = COLOR_RED },
 | 
					                .border = { .width = {2, 2, 2, 2}, .color = COLOR_RED },
 | 
				
			||||||
                .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
					                .cornerRadius = CLAY_CORNER_RADIUS(10),
 | 
				
			||||||
                .custom = { .customData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay") }) },
 | 
					                .userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay") }),
 | 
				
			||||||
            }) {
 | 
					            }) {
 | 
				
			||||||
                CLAY_TEXT(CLAY_STRING("Github"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
					                CLAY_TEXT(CLAY_STRING("Github"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -413,7 +421,12 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool debugModeEnabled = false;
 | 
					bool debugModeEnabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CLAY_WASM_EXPORT("SetScratchMemory") void SetScratchMemory(void * memory) {
 | 
				
			||||||
 | 
					    frameArena.memory = memory;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(float width, float height, float mouseWheelX, float mouseWheelY, float mousePositionX, float mousePositionY, bool isTouchDown, bool isMouseDown, bool arrowKeyDownPressedThisFrame, bool arrowKeyUpPressedThisFrame, bool dKeyPressedThisFrame, float deltaTime) {
 | 
					CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(float width, float height, float mouseWheelX, float mouseWheelY, float mousePositionX, float mousePositionY, bool isTouchDown, bool isMouseDown, bool arrowKeyDownPressedThisFrame, bool arrowKeyUpPressedThisFrame, bool dKeyPressedThisFrame, float deltaTime) {
 | 
				
			||||||
 | 
					    frameArena.offset = 0;
 | 
				
			||||||
    windowWidth = width;
 | 
					    windowWidth = width;
 | 
				
			||||||
    windowHeight = height;
 | 
					    windowHeight = height;
 | 
				
			||||||
    Clay_SetLayoutDimensions((Clay_Dimensions) { width, height });
 | 
					    Clay_SetLayoutDimensions((Clay_Dimensions) { width, height });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue