{"id":13423424,"url":"https://github.com/maierfelix/azula","last_synced_at":"2025-04-07T11:01:47.352Z","repository":{"id":90987564,"uuid":"215633985","full_name":"maierfelix/azula","owner":"maierfelix","description":"Lightweight GPU accelerated HTML GUI for native JavaScript","archived":false,"fork":false,"pushed_at":"2019-10-20T14:48:29.000Z","size":38114,"stargazers_count":318,"open_issues_count":4,"forks_count":16,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-03-31T10:03:57.371Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://maierfelix.github.io/azula","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maierfelix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-10-16T20:02:33.000Z","updated_at":"2025-03-15T08:11:26.000Z","dependencies_parsed_at":"2023-07-25T21:01:01.395Z","dependency_job_id":null,"html_url":"https://github.com/maierfelix/azula","commit_stats":{"total_commits":74,"total_committers":2,"mean_commits":37.0,"dds":0.06756756756756754,"last_synced_commit":"fc58af341101b4c1b656d97c2460a21283dd0e4d"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maierfelix%2Fazula","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maierfelix%2Fazula/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maierfelix%2Fazula/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maierfelix%2Fazula/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maierfelix","download_url":"https://codeload.github.com/maierfelix/azula/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247640459,"owners_count":20971556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T00:00:34.263Z","updated_at":"2025-04-07T11:01:47.318Z","avatar_url":"https://github.com/maierfelix.png","language":"C","funding_links":[],"categories":["C","others","GUI Frameworks"],"sub_categories":["Web"],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"#\"\u003e\n    \u003cimg src=\"https://i.imgur.com/FBN4t6x.png\" height=\"118\"\u003e\n  \u003c/a\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  \u003ci\u003eazula\u003c/i\u003e, a lightweight GPU accelerated HTML GUI for native JavaScript applications\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  \u003ca href=\"https://www.npmjs.com/package/azula\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/azula.svg?style=flat-square\" alt=\"NPM Version\" /\u003e\n  \u003c/a\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  \u003cimg src=\"https://i.imgur.com/bfwxryC.gif\" /\u003e\n\u003c/p\u003e\n\n## ‌‌\n\n*azula* is a lightweight alternative to Electron. It is based on [Ultralight](https://github.com/ultralight-ux/Ultralight), which is an embedding friendly Fork of [WebKit](https://webkit.org/), with less memory usage and low disk space requirements.\n\n*azula* can optionally run in [OSR](#osr) mode, which makes it easy to embed *azula* in existing Projects like Game/VR Engines.\n\n## Characteristics\n\n|  | Azula | Electron |\n| :--- | :--- | :--- |\n| CPU | 1.2% | 4.2% |\n| RAM | 37Mb | 64Mb |\n| DISK | 31Mb | 118Mb |\n\n## Platforms\n\n*azula* comes with pre-built N-API binaries for the following platforms:\n\n|       OS      |     Status    |\n| ------------- | ------------- |\n| \u003cimg src=\"https://i.imgur.com/FF3Ssp6.png\" alt=\"\" height=\"16px\"\u003e  Windows       | ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ✔ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌|\n| \u003cimg src=\"https://i.imgur.com/bkBCY7V.png\" alt=\"\" height=\"16px\"\u003e  Linux         | ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ In Progress ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌|\n| \u003cimg src=\"https://i.imgur.com/iPt4GHz.png\" alt=\"\" height=\"16px\"\u003e  MacOS         | ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ In Progress ‌‌ ‌‌ ‌‌ ‌‌ ‌‌ ‌‌|\n\n## Getting Started\n\nInstall *azula* using:\n````\nnpm install azula\n````\n\nYou can now import *azula* into your project:\n````js\nconst azula = require(\"azula\");\n````\n\nOr with *ESM*:\n````js\nimport azula from \"azula\";\n````\n\n## API\n\n  * [Window](#window)\n    - [General](#general)\n      - [title](#windowprototypetitle)\n      - [width](#windowprototypewidth)\n      - [height](#windowprototypeheight)\n      - [update](#windowprototypeupdate)\n      - [flush](#windowprototypeflush)\n      - [shouldClose](#windowprototypeshouldclose)\n    - [Loading](#loading)\n      - [loadHTML](#windowprototypeloadhtml)\n      - [loadFile](#windowprototypeloadfile)\n    - [Events](#events)\n      - [onresize](#windowprototypeonresize)\n      - [oncursorchange](#windowprototypeoncursorchange)\n      - [onconsolemessage](#windowprototypeonconsolemessage)\n    - [Event Dispatching](#event-dispatching)\n      - [dispatchMouseEvent](#windowprototypedispatchmouseevent)\n      - [dispatchKeyEvent](#windowprototypedispatchkeyevent)\n      - [dispatchScrollEvent](#windowprototypedispatchscrollevent)\n    - [Object Messaging](#object-messaging)\n      - [dispatchObject](#windowprototypedispatchobject)\n      - [onobjectmessage](#windowprototypeonobjectmessage)\n    - [Binary Messaging](#binary-messaging)\n      - [dispatchBinaryBuffer](#windowprototypedispatchbinarybuffer)\n      - [onbinarymessage](#windowprototypeonbinarymessage)\n    - [OSR Mode](#osr-mode)\n      - [getSharedHandleD3D11](#windowprototypegetsharedhandled3d11)\n\n## Window\n\nWhen creating a new Window, the following parameters are available:\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| width (*Optional*) | *Number* | The initial width of the window |\n| height (*Optional*) | *Number* | The initial height of the window |\n| title (*Optional*) | *String* | The initial title of the window |\n| useOffscreenRendering (*Optional*) | *Boolean* | When *true*, creates the window in [OSR mode](#osr) |\n\n````js\nlet window = new azula.Window({\n  width: 480,\n  height: 320,\n  title: \"My App\",\n  useOffscreenRendering: false\n});\n````\n\n## General\n\n### Window.prototype.title\n\n| Type | Description |\n| :--- | :--- |\n| *String* | A getter/setter allowing to retrieve or update the title of the window |\n\n````js\nwindow.title = \"My App\";\nwindow.title; // \"My App\"\n````\n\n### Window.prototype.width\n\n| Type | Description |\n| :--- | :--- |\n| *Number* | A getter/setter allowing to retrieve or update the width of the window |\n\n````js\nwindow.width = 640;\nwindow.width; // 640\n````\n\n### Window.prototype.height\n\n| Type | Description |\n| :--- | :--- |\n| *Number* | A getter/setter allowing to retrieve or update the height of the window |\n\n````js\nwindow.height = 480;\nwindow.height; // 480\n````\n\n### Window.prototype.update\n\nThis method should be called to poll window events (making the window interactive). In *non-OSR* mode, this method also does the painting of the window.\n\n````js\nwindow.update();\n````\n\n### Window.prototype.flush\n\nThis method should only be used in [OSR](#osr) mode. Calling this method executes all remaining render operations and flushes the underlying context.\n\n````js\nwindow.flush();\n````\n\n### Window.prototype.shouldClose\n\n| Type | Description |\n| :--- | :--- |\n| *Boolean* | A boolean, indicating if the window should be closed |\n\n````js\nwindow.shouldClose(); // true/false\n````\n\n## Loading\n\n### Window.prototype.loadHTML\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| html | *String* | String representation of the HTML to load |\n\n````js\nwindow.loadHTML(\"\u003cbutton\u003eHello World!\u003c/button\u003e\");\n````\n\n### Window.prototype.loadFile\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| path | *String* | The path from where the content gets read from |\n\n````js\nwindow.loadFile(\"./index.html\");\n````\n\n## Events\n\n### Window.prototype.onresize\n\n| Type | Description |\n| :--- | :--- |\n| *Function* | The function to call when the window gets resized |\n\nThe callback's Event parameter has the following structure:\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| width | *Number* | The new width of the window |\n| height | *Number* | The new height of the window |\n\n````js\nwindow.onresize = e =\u003e {\n  console.log(e.width, e.height);\n};\n````\n\n### Window.prototype.oncursorchange\n\n| Type | Description |\n| :--- | :--- |\n| *Function* | The function to call when the cursor should be changed |\n\nThe callback's Event parameter has the following structure:\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| name | *String* | A name representing the cursor type to change to |\n\n````js\nwindow.oncursorchange = e =\u003e {\n  console.log(e.name);\n};\n````\n\n### Window.prototype.onconsolemessage\n\n| Type | Description |\n| :--- | :--- |\n| *Function* | The function to call when a console message got sent |\n\nThe underlying JavaScript engine of *azula* is WebKit's [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore) engine. Now this means, that the JavaScript running in the GUI is separated from the JavaScript in Node. When the JavaScript in the GUI makes a call to the console, e.g. `console.log(42);`, we have to route this call over to Node.\n\nThe callback's Event parameter has the following structure:\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| level | *String* | The level of the console call. For example *\"log\"*, *\"warn\"* or *\"error\"* |\n| callee | *Function* | Node's equivalent console function to call |\n| message | *String* | The message passed to the console call |\n| source | *String* | The file or location where the call was made. Is empty when [loadHTML](#windowprototypeloadhtml) was used |\n| location | *Object* | An Object describing the exact code location where the console call was made from |\n\nThe location Object comes with the following structure:\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| line | *Number* | The code line where the console call originated from |\n| column | *Number* | The code column where the console call originated from |\n\n````js\nwindow.onconsolemessage = e =\u003e {\n  let location = `at ${e.source ? e.source + \":\" : \"\"}${e.location.line}:${e.location.column}`;\n  e.callee.apply(console, [e.message, location]);\n};\n````\n\n## Event Dispatching\n\nThe Event Dispatching System should only be used in [OSR](#osr) mode. Event Dispatching allows to manually send events to the GUI, such as mouse gestures or key events.\n\n### Window.prototype.dispatchMouseEvent\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| type | *String* | The type of event |\n| x | *Number* | The horizontal position of the mouse |\n| y | *Number* | The vertical position of the mouse |\n| button | *Number* | The currently pressed mouse button |\n\nThe following event types are available:\n\n| Name | Type |\n| :--- | :--- |\n| onmousedown | Simulating a mouse press action |\n| onmouseup | Simulating a mouse leave action |\n| onmousemove | Simulating a mouse move action |\n\n````js\nwindow.dispatchMouseEvent(\"onmousedown\", 16, 32, 1); // press the left mouse button at 16:32\nwindow.dispatchMouseEvent(\"onmouseup\", 16, 32, 1); // leave the left mouse button at 16:32\nwindow.dispatchMouseEvent(\"onmousemove\", 16, 32, 0); // move the mouse to 16:32 without pressing a mouse button\n````\n\n### Window.prototype.dispatchKeyEvent\n\nKey Codes are mapped towards [GLFW's Key Codes](https://www.glfw.org/docs/latest/group__keys.html).\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| type | *String* | The type of event |\n| keyCode | *Number* | A key code representing which key to press |\n\nThe following event types are available:\n\n| Name | Type |\n| :--- | :--- |\n| onkeydown | Simulating a key press action |\n| onkeyup | Simulating a key leave action |\n\n````js\nwindow.dispatchKeyEvent(\"onkeydown\", x); // press a key\nwindow.dispatchKeyEvent(\"onkeyup\", x); // leave a key\n````\n\n### Window.prototype.dispatchScrollEvent\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| type | *String* | The type of event |\n| deltaX | *Number* | The horizontal amount to scroll |\n| deltaY | *Number* | The vertical amount to scroll |\n\nThe following event types are available:\n\n| Name | Type |\n| :--- | :--- |\n| onmousewheel | Simulating a mouse wheel action |\n\n````js\nwindow.dispatchScrollEvent(\"onmousewheel\", 0, 1); // scroll upwards, vertically by 1\nwindow.dispatchScrollEvent(\"onmousewheel\", -1, 0); // scroll downwards, horizontally by -1\n````\n\n## Object Messaging\n\nThe underlying JavaScript engine of *azula* is WebKit's [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore) engine. The JavaScript engine of Node is different to the one used in *azula*, so we cannot directly exchange data. The Object Messaging System allows to send Object between both engines.\n\nNote that to be sent Objects should kept small, as behind the scenes, they get serialized.\n\n### Window.prototype.dispatchObject\n\nAn equivalent method is available in the GUI. See [this](https://github.com/maierfelix/azula/tree/master/examples/messaging) example as a reference.\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| object | *Object* | The Object to send to the GUI |\n\n````js\nwindow.dispatchObject({ message: \"PING\" });\n````\n\n### Window.prototype.onobjectmessage\n\nAn equivalent method is available in the GUI. See [this](https://github.com/maierfelix/azula/tree/master/examples/messaging) example as a reference.\n\n| Type | Description |\n| :--- | :--- |\n| *Function* | The function to call when an object message was sent from the GUI |\n\nThe callback's Event parameter has the following structure:\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| object | *Object* | The Object sent from the GUI |\n\n````js\nwindow.onobjectmessage = object =\u003e {\n  console.log(object);\n};\n````\n\n## Binary Messaging\n\nThe underlying JavaScript engine of *azula* is WebKit's [JavaScriptCore](https://developer.apple.com/documentation/javascriptcore) engine. The JavaScript engine of Node is different to the one used in *azula*, so we cannot directly exchange data. The Binary Messaging System allows to efficiently pass [ArrayBuffers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) between both engines. Even though the engines are different, ArrayBuffers can be exchanged without any copying, meaning they don't have any overhead.\n\n### Window.prototype.dispatchBinaryBuffer\n\nAn equivalent method is available in the GUI. See [this](https://github.com/maierfelix/azula/tree/master/examples/binary) example as a reference.\n\nThe *binarymessage* system should only be used when sending large data between Node and *azula*. The `buffer` argument is a referenced buffer, which means there is no overhead when sending it between Node and *azula* as the data is effectively referenced.\n\nThe second argument is an Object (and is optional), which can be used to give some additional information about the `buffer` argument. This Object should be kept small, as it gets serialized behind the scenes, and so comes with some overhead.\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| buffer | *ArrayBuffer* | The ArrayBuffer to send to the GUI |\n| args (*Optional*) | *Object* | An Used-defined Object providing additional information about the *buffer* |\n\n````js\nwindow.dispatchBinaryBuffer(new ArrayBuffer(16), { kind: \"SOME_DATA\" });\n````\n\n### Window.prototype.onbinarymessage\n\nAn equivalent method is available in the GUI. See [this](https://github.com/maierfelix/azula/tree/master/examples/binary) example as a reference.\n\nThe *binarymessage* system should only be used when sending large data between Node and *azula*. The `buffer` argument is a referenced buffer, which means there is no overhead when sending it between Node and *azula* as the data is effectively referenced.\n\nThe second argument is an Object (and is optional), which can be used to give some additional information about the `buffer` argument. This Object should be kept small, as it gets serialized behind the scenes, and so comes with some overhead.\n\n| Type | Description |\n| :--- | :--- |\n| *Function* | The function to call when a binary message was sent from the GUI |\n\nThe callback's Event parameter has the following structure:\n\n| Name | Type | Description |\n| :--- | :--- | :--- |\n| buffer | *ArrayBuffer* | The ArrayBuffer sent from the GUI |\n| args (*Optional*) | *Object* | An Used-defined Object providing additional information about the sent *buffer* |\n\n````js\nwindow.onbinarymessage = (buffer, args) =\u003e {\n  console.log(buffer, args);\n};\n````\n\n## OSR Mode\n\n### Window.prototype.getSharedHandleD3D11\n\n| Type | Description |\n| :--- | :--- |\n| *BigInt* | A BigInt representing a Windows HANDLE |\n\nOn Windows, you can use this method to retrieve a shared [HANDLE](https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types) to the underlying D3D11 render texture.\n\n````js\nlet handle = window.getSharedHandleD3D11();\n````\n\n## OSR\n\nSee [this](https://github.com/maierfelix/azula/tree/master/examples/OSR) example as a reference.\n\n*azula* supports running in OSR (*Offscreen rendering*) mode. This means, that instead of creating a window, an invisible texture gets used and rendered into. This texture can then be imported into a 3D engine for example. Another common use case would be, to display the texture in a VR environment.\n\nOn **Windows**, you can request a shared HANDLE using the Window's [getSharedHandleD3D11](#windowprototypegetsharedhandled3d11) method.\n\n## License\n\nAzula is MIT licensed, while [Ultralight](https://github.com/ultralight-ux/Ultralight) comes with the following License:\n\n````\nUltralight is free for non-commercial use, educational use, \nand also free for commercial use by small indie developers making\nless than US$100,000 a year. You can find full terms in the SDK. \nPricing plans for larger commercial projects will be announced later.\n````\n\nFor further information regaring the licensing of Ultralight, see [this](https://github.com/ultralight-ux/Ultralight/tree/master/license) link.\n\n## ‌‌\n*No, you miscalculated! You should have feared me more! - [Azula](https://en.wikipedia.org/wiki/Azula)*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaierfelix%2Fazula","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaierfelix%2Fazula","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaierfelix%2Fazula/lists"}