{"id":13729017,"url":"https://github.com/chwar/XRUI","last_synced_at":"2025-05-08T01:31:27.241Z","repository":{"id":181262633,"uuid":"391622973","full_name":"chwar/XRUI","owner":"chwar","description":"Unity Extension for Responsive UI in XR","archived":false,"fork":false,"pushed_at":"2023-07-21T18:55:53.000Z","size":1229,"stargazers_count":17,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-01-28T23:11:52.599Z","etag":null,"topics":["csharp","ui","unity","unity3d","unity3d-plugin","xr"],"latest_commit_sha":null,"homepage":"https://chwar.github.io/xrui/","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/chwar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-08-01T12:37:33.000Z","updated_at":"2024-04-23T13:33:27.544Z","dependencies_parsed_at":null,"dependency_job_id":"b731cad5-7fad-4aa2-abda-4e23ba96a802","html_url":"https://github.com/chwar/XRUI","commit_stats":null,"previous_names":["chwar/xrui"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chwar%2FXRUI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chwar%2FXRUI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chwar%2FXRUI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chwar%2FXRUI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chwar","download_url":"https://codeload.github.com/chwar/XRUI/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252981526,"owners_count":21835441,"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":["csharp","ui","unity","unity3d","unity3d-plugin","xr"],"created_at":"2024-08-03T02:00:53.676Z","updated_at":"2025-05-08T01:31:26.888Z","avatar_url":"https://github.com/chwar.png","language":"C#","funding_links":[],"categories":["C#"],"sub_categories":[],"readme":"# XRUI Framework\n\n[![release](https://flat.badgen.net/github/release/chwar/xrui)](https://github.com/chwar/xrui)\n[![Unity 2021.2+](https://flat.badgen.net/badge/unity/2021.2+)](https://unity3d.com/get-unity/download)\n[![MIT](https://flat.badgen.net/badge/license/MIT/green)](./LICENSE)\n[![Coverage](https://flat.badgen.net/badge/coverage/85%25/green)](./Tests)\n\n\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/204878936-b19b3868-d6c5-428f-ba99-86f1ec389af9.gif\"  alt=\"2dlandscape\" width =\"300\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/204878941-13a1b723-58aa-44e1-aabf-a497c9f72178.gif\" alt=\"2dportrait\" width =\"150\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/204878943-f608c09f-de33-474b-bea8-9264198734b7.gif\" alt=\"3d\" width =\"300\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape (PC)\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait (Android)\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWorld Space (Meta Quest 2)\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nXRUI is a responsive UI framework for making cross-platform XR applications with the Unity 3D editor. Its purpose is to assist users in creating efficient and adaptive UIs that can easily be adjusted to be rendered in 2D (for environments with a 2D screen, e.g. PC, smartphone, tablet) and 3D (i.e., rendered in world space, required to render UI in XR (AR/MR/VR)). This way, XRUI users only need to design and implement their UI once for all platforms. This can also provide memorability and familiarity to end-users that use XRUI enhanced apps on different platforms, thus increasing usability.   \n\nXRUI is based on Unity's new UI system, [UI Toolkit](https://docs.unity3d.com/Manual/UIElements.html). Internally, it uses UXML and USS, so a basic knowledge and understanding of these technologies are required to use this framework. \n\n## Getting Started\n\n1. In the package manager, click on `Add package from git URL` and insert the repository's URL: [https://github.com/chwar/XRUI.git](https://github.com/chwar/XRUI.git)\n  * Alternatively, you can unzip and import the package manually.\n\n2. Add the XRUI controller to your scene by navigating to `XRUI \u003e Add XRUI Controller`. You can also create an empty game object and attach the main XRUI script (`XRUI.cs`). This script is a singleton flagged as `DontDestroyOnLoad`. It contains the main API that can be easily accessed through the instance:\n\n```csharp\nusing com.chwar.xrui;\n\nvoid Start(){\n    // XRUI.Instance...\n}\n```\n\n3. The package uses a default configuration that references the default UXML templates for UI elements. You can create your own by navigating to `Assets \u003e Create \u003e XRUI \u003e Create XRUI Configuration asset`. You can then override the default templates for UI elements with your own (see [Custom UI Elements](#custom-ui-elements)). Don't forget to reference your own XRUI configuration asset to the XRUI controller.\n4. You can have a look at the provided Demo scenes to get a better idea of how XRUI works.\n\n## UI Elements\n\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/204884997-2311b94e-e644-4d79-8fe8-50d8a61fdbf6.png\"  alt=\"2dlandscape\" width =\"400\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/204885001-9618fb5e-d31a-4a72-b7e1-d3dd310dfb4d.png\" alt=\"3d\" width =\"400\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape Overview\u003c/td\u003e\n\u003ctd align=\"center\"\u003e3D (World Space) Overview\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n\nXRUI provides a few UI Elements. The style is minimalistic and inspired from [Bootstrap](https://getbootstrap.com). You can add them in your project by navigating from the Unity menu to `XRUI \u003e Add XRUI Element`. This creates a game object containing a `UIDocument` (which contains the UXML template and USS styles) and an XRUI script that matches the element. Add your own scripts to this object with a reference to the XRUI script to define the behaviour of the UI. \n\nXRUI elements are thought as basic containers for user content. Given the hierarchic nature of UXML, it is easy to append content within the UI elements at runtime. To easily access your UXML contents and append them into various XRUI elements, reference them in the intended UI Elements list within the XRUI controller:\n\n![xruiController](https://user-images.githubusercontent.com/25299178/204763743-bbb68101-10be-4258-8bd4-05d675a42fca.png)\n\n\nThe list of UI elements is accessible within the XRUI controller's instance. Use the `GetUIElement` method for easy access:\n\n```csharp\n// Use the name of the VisualTreeAsset you put in the inspector list \nVisualTreeAsset myElement = XRUI.Instance.GetUIElement(\"MyElement\");\n```\n\n### XRUI Element\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\nWhen adding UI Elements through the XRUI menu in Unity, the system uses the template referenced in the XRUI Configuration asset (see [Installation](#installation)). Each XRUI element script inherits from the `XRUIElement` class, which comes with some useful generic methods.\n\nTo add or remove visual elements from the UI element, call these methods:\n\n```csharp\nVisualElement myElement = someVisualTreeAsset.Instantiate();\nXRUICard card = GetComponent\u003cXRUICard\u003e();\n\n// Appends a visual element inside a parent element\ncard.AddUIElement(myElement, \"xrui-card__container\");\ncard.RemoveUIElement(myElement); \n```\n\nGet an XRUI related visual element from the UI element:\n\n```csharp\nXRUICard card = FindObjectOfType\u003cXRUICard\u003e();\nXRUIMenu menu = FindObjectOfType\u003cXRUIMenu\u003e();\n        \n// Get a generic Visual Element from the card\nvar cardHeader = card.GetXRUIVisualElement(\"xrui-card__header\");\n\n// Get the title Label from the menu \nvar menuTitle = menu.GetXRUIVisualElement\u003cLabel\u003e(\"xrui-menu__title\");\n```\n\nYou can also show or hide XRUI elements at any time:\n\n```csharp\ncard.Show(true);    // Display.Flex, enables MeshRenderer and Collider for world UI\ncard.Show(false);   // Display.None, disables MeshRenderer and Collider for world UI\n\ncard.Show(myElement, false); // Hides myElement\n``` \n\n\u003e Note: Keep in mind that hidden elements will not be found with a regular QML query, as they are hidden. You can still find them by either keeping a reference to the visual element in your code, or by querying it like this: \n\u003e \n\u003e ```csharp\n\u003e card.Query\u003cTemplateContainer\u003e().Where(ve =\u003e \n\u003e\tve.style.display.value.Equals(DisplayStyle.None)).First();\n\u003e ```\n\u003c/details\u003e\n\t\n### XRUI Menu\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\t\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150380152-620c7abc-c9ed-4f59-a5c9-1c290cb188da.png\"  alt=\"2dlandscape\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150380261-88113fc8-5787-45be-891e-c3c63884a5f4.png\" alt=\"2dportrait\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150380451-dcdd3686-2f91-40c5-99da-9114d3119784.png\" alt=\"3d\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWorld Space\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThe provided XRUI Menu template is designed as a side menu that collapses out of the view frustum. It can be configured in the inspector (see screenshot above).\n\t\nThe list element template is the UXML template that is used to create entries. You can provide a template with a simple button, or more complex compositions with images, text, buttons, etc. to suit your needs.\n\t\nAdd entries to your menu:\n\n```csharp\nvar menu = GetComponent\u003cXRUIMenu\u003e();\n\n// The menu returns the created entry to be configured\nvar element = menu.AddElement();\nelement.Q\u003cLabel\u003e(\"MyElementLabel\").text = \"myLabelTitle\";\n```\n\n\u003c/details\u003e\n\n### XRUI List\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150381681-5008c5e6-8656-436d-ad37-5673c88eaf9f.png\"  alt=\"2dlandscape\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150381664-4cf1bd87-ec84-429e-9d75-035f361b3aed.png\" alt=\"2dportrait\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150381684-7843e2c5-fd60-4149-b9ad-2e21ea66c5db.png\" alt=\"3d\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWorld Space\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThe XRUI List works in the same way as the menu:\n\n```csharp\nvar list = GetComponent\u003cXRUIList\u003e();\n\n// The list returns the created entry to be configured\nvar element = list.AddElement();\nelement.Q\u003cLabel\u003e(\"MyElementLabel\").text = \"myLabelTitle\";\n```\n\n\u003c/details\u003e\n\n### XRUI Navbar\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\t\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150387236-07cf2ba4-d59a-47fa-b10d-1d7f2270b4aa.png\"  alt=\"2dlandscape\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150387230-8ae337ba-cc53-4e56-aba8-61972b07cef9.png\" alt=\"2dportrait\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150387239-d4f12053-72e1-444c-8666-074dc7cda6ad.png\" alt=\"3d\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWorld Space\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\t\nThe provided navbar is a very simple dark top bar. Since XRUI does not provide any third-party assets, it is provided empty. However, the default template contains a row of buttons (three justified on the left side, one justified on the right side) to get you started. Since navbar designs can be very different, the adopted solution was to propose a very generic template to fit the most users. You could use the template as a base to add your own elements (buttons, dropdowns, labels) to tailor the navbar to your needs.\n\u003c/details\u003e\n\n### XRUI Card\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150382706-dfcca9f6-28d4-49a6-b104-1f13476e86b3.png\"  alt=\"2dlandscape\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150382701-ea5b0e55-4bbe-4cac-9db5-7ed07fb47afa.png\" alt=\"2dportrait\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150382708-57b80239-35e1-483d-a11d-77f1f93865ab.png\" alt=\"3d\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \t\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWorld Space\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nThe XRUI Card is floating on the right corner in the 2D landscape format, and sticks to the bottom of the screen in portrait format. Use the `AddUIElement` method (see [XRUI Element](#xrui-element)) to fill the card with content.\n\n\u003c/details\u003e\n\t\n### XRUI Modals\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150383323-b82a2a4d-3565-4d58-8695-9fef29920ffb.png\"  alt=\"2dlandscape\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150383320-c52537d2-c74a-4c9d-8dd8-bc7a5955f92d.png\" alt=\"2dportrait\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150383326-c13b93d2-bbfc-4286-83c7-2361fbfea257.png\" alt=\"3d\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \t\n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWorld Space\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\nXRUI creates modals at runtime rather than requiring you to create all of them in the editor in order to save resources.\n\nGiven the hierarchic nature of UXML, modals are easy to reproduce. XRUI provides a modal template, which consists of a title, empty container, two buttons (main and secondary) sticking at the bottom, and a closing button in the top right corner. You can use this template and fill its container dynamically at runtime.\n\nIn Unity, you can reference your modals in the intended list:\n\n\u003cimg width=\"661\" alt=\"modals\" src=\"https://user-images.githubusercontent.com/25299178/204764369-4be62c79-0ac5-4130-947d-ae77155afa7e.png\"\u003e\n\nThe name given to each modal entry can be used to find the matching template and create a modal from it, with the `CreateModal` method:\n\n```csharp\n// Adapt the namespace to your own\nType t = Type.GetType(\"myModalScript\");\nXRUI.Instance.ShowModal(\"DemoModal\", t);\n```\n\n\u003e Note: The user script type has to be passed outside of the XRUI package, because Unity packages can't access the Assembly-CSharp assembly, i.e. can't find user namespaces, and hence, can't find user scripts located in the Assets automatically. It's also not possible to reference it through the inspector, as it only accepts instances of a script and not the script itself.\n\nThis creates a modal game object on which the `XRUIModal` script is attached, as well as a `UIDocument` script that contains the main template. You can access the modal system's API through the `XRUIModal` script.\nThe user script type is used to create an instance of said script when the modal is created. This lets you define the behaviour of your elements. One approach is to create one method per page, and to setup event handlers on your buttons to navigate them. To create modal pages, use the `UpdateModalFlow` method. Its last parameter is a callback function that is fired once upon the page's creation.\n\n```csharp\nprivate XRUIModal _xruiModal;\nprivate UIDocument _uiDocument;\n\nvoid Start() {\n    _xruiModal = GetComponent\u003cXRUIModal\u003e();\n    _uiDocument = GetComponent\u003cUIDocument\u003e();\n    StartPage();\n}\n\nvoid StartPage() {\n    _xruiModal.UpdateModalFlow(\"MyModalPage\", \"MainContainer\", () =\u003e\n    {\n        // This callback is only fired once, when the page is created for the first time\n        // Put here initialization code, event subscriptions, etc. \n\n        Button myButton = RootElement.Q\u003cButton\u003e(\"myButton\");\n        _myButton.clicked += MyPage;\n    });\n\n    // Content to execute every time this page is opened.\n}\n\nvoid MyPage() {\n    // ...\n}\n```\n\n### Using the Default Modal Template\nYou can use the default modal template that comes with the package and fill it with your own content. It consists of a title, empty container, two buttons (main and secondary) sticking at the bottom, and a closing button in the top right corner. You can add your content to the container by referencing it by its USS class (`xrui-modal__container`) to the `UpdateModalFlow` method, as per the example above. You can manipulate the buttons and change the title through the `XRUIModal` API.\n\nAccess the modal's public fields to change the title of the modal, the text of the buttons, or to set the icon of the top right close button:\n\n```csharp\n_xruiModal.ModalTitle.text = \"Create a new project\";\n_xruiModal.CancelButton.text = \"Cancel\";\n_xruiModal.ValidateButton.text = \"Finish\";\n_xruiModal.ValidateButton.visible = true;\n```\n\nChange the justification of the bottom buttons with the `SetButtonsPlacement` method:\n```csharp\n// Supported options: FlexStart, FlexEnd, Center, Space Between, Space Around\n_xruiModal.SetButtonsPlacement(Justify.Center);\n```\n\nSet the action of the cancel and validation buttons:\n```csharp\n// These methods take an action as parameter, but you can provide a function call\n\n_xruiModal.SetCancelButtonAction(XRUIModal.Destroy);\n_xruiModal.SetValidateButtonAction(CreateProject);\n```\n\n\u003e Note: prefer these methods to the direct access to `ValidationButton.clicked` or `CancelButton.clicked`, as the methods replace any other event subscription with the provided action. This means that a click on either button can have only one action on a given page. \n\nDestroy the modal:\n\n```csharp\n_xruiModal.Destroy();\n```\n\n#### Form Validation\nXRUI supports basic form validation by letting you define required fields. For now, only text fields are supported, i.e. XRUI determines if required text fields are empty or not.\n\n```csharp\n_xruiModal.SetRequiredFields(_fieldOne, _fieldTwo, _fieldThree);\n```\n\nYou can pass as many fields as you want in one call. Internally, XRUI checks the page where each indicated field is contained in. When a user is on a page containing required fields, the modal's validation button is disabled until all required fields contain an input. Additionally, you can subscribe your own validation methods to the validation button and flag text fields with errors to indicate users the fields to correct.  \n\n```csharp\n_xruiModal.SetFieldError(_fieldWithError);\n```\n\n\u003c/details\u003e\n\t\n### XRUI Alerts\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150383854-a98bc873-a574-4285-bc93-c38c4833fadf.png\"  alt=\"2dlandscape\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150383853-723ba5af-312f-428d-9734-a3ad430b3411.png\" alt=\"2dportrait\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/150383857-6adaa27b-23f6-4f33-a472-21eb9511af78.png\" alt=\"3d\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape - Primary\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait - Success\u003c/td\u003e\n\u003ctd align=\"center\"\u003eWorld Space - Warning\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\t\n![Peek 2021-08-03 00-03](https://user-images.githubusercontent.com/25299178/127934108-1784dc2d-36d3-4452-8119-3f910f9a258a.gif)\n![Peek 2021-08-03 00-05](https://user-images.githubusercontent.com/25299178/127934111-57e1859b-5900-4487-995f-9d3f55e8da68.gif)\n\nThe provided alert template creates floating cards in 2D landscape and 3D formats, and as notifications at the top of the screen in 2D portrait mode. They also come with animations to attract the attention of users. You can show alerts for different purposes; the types of alerts are inspired from [Bootstrap](https://getbootstrap.com/docs/5.0/components/alerts/).   \n\n\nShow alerts using the `ShowAlert` method:\n\n```csharp\nXRUI.Instance.ShowAlert(XRUIAlert.AlertType.Primary, \"Primary message.\");\nXRUI.Instance.ShowAlert(XRUIAlert.AlertType.Success, \"Success message.\");\nXRUI.Instance.ShowAlert(XRUIAlert.AlertType.Warning, \"Warning message.\");\nXRUI.Instance.ShowAlert(XRUIAlert.AlertType.Danger, \t\"Error message.\");\nXRUI.Instance.ShowAlert(XRUIAlert.AlertType.Info, \t\"Info message.\");\n```\n\nYou can also provide a title:\n\n```csharp\nXRUI.Instance.ShowAlert(XRUI.AlertType.Primary, \"Title\", \"Primary message.\");\n```\n\t\nYou can also give a callback, which will be triggered upon clicking the alert:\n\t\n```csharp\n XRUI.Instance.ShowAlert(XRUI.AlertType.Primary, \"Click me!\", \"Click to trigger callback\", () =\u003e MyCallback());\n```\n\nOr, you can set a countdown after which the alert will disappear:\n\n```csharp\n XRUI.Instance.ShowAlert(XRUI.AlertType.Primary, \"Title\", \"This alert will disappear in 5 seconds\", 5);\n```\n\u003c/details\u003e\n\t\n\t\n### XRUI Contextual Menu\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand!\u003c/summary\u003e\n\n\u003ctable\u003e\n\u003ctr\u003e\t\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/204881019-bd7f6b52-6ef2-47b6-87a0-62e1133a6929.png\"  alt=\"2dlandscape\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/204881022-69287d12-8763-416a-907d-1e390f619211.png\" alt=\"2portrait\" width =\"360\"\u003e\n\u003c/td\u003e\n\u003c/tr\u003e \n\u003ctr\u003e\n\u003ctd align=\"center\"\u003e2D Landscape\u003c/td\u003e\n\u003ctd align=\"center\"\u003e2D Portrait\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003c/table\u003e\n\t\nXRUI can create contextual menus dynamically. The contextual menu is shown as a floating list. Similarly to the menu and list templates, a menu element template is also given to create entries in the contextual menu. Because the entries are context-dependent, they need to be generated dynamically at runtime.\n\t\nThe `ShowContextualMenu` method needs at least the x and y coordinates of the parent element (i.e. the element that was interacted which caused the contextual menu to appear), and a boolean to indicate whether or not the styling should include an arrow pointing at the parent element. A first overload gives the possibility to provide a custom template. A second overload lets developers provide left and right offsets for finer tuning of the menu’s position. The method returns a `XRUIContextualMenu` instance, which is required to add entries to the menu.\n\t\n```csharp\nvar myElement = GetComponent\u003cUIDocument\u003e();\nvar myBtn = myElement.rootVisualElement.Q\u003cButton\u003e(\"myBtn\");\n\t\n// Define parent coordinates for menu positioning\nVector2 parentCoordinates = new Vector2(myBtn.worldBound.x, myBtn.worldBound.y);\n\t\n// For using a custom template\nVisualTreeAsset myTemplate = Resources.Load\u003cVisualTreeAsset\u003e(\"myTemplate\");\n\t\nmyBtn.clicked +=\n{\n\tvar menu;\n\t// Use one of these overloads\n\t// Call with 2 parameters: parent coord. and whether to show a pointing arrow\n\tmenu = XRUI.Instance.ShowContextualMenu(parentCoordinates, false);\n\t\n\t// 3 parameters: provide a custom template as 1st param.\n\tmenu = XRUI.Instance.ShowContextualMenu(myTemplate, parentCoordinates, true);\n\t\n\t// 5 parameters: provide left and right offsets in pixels\n\tmenu = XRUI.Instance.ShowContextualMenu(myTemplate, parentCoordinates, true, 50,\n\t100);\n}\n\t\n// To override the default menu entry template\nmenu.menuElementTemplate = Resources.Load\u003cVisualTreeAsset\u003e(\"myEntryTemplate\");\n\t\n// Add entries to the contextual menu\nvar entry = contextualMenu.AddMenuElement();\n```\n\nIn addition, the contextual menu considers the available space on screen. By default, contextual menus will attempt to display on the right of the parent element. However, if there is no available space, they are displayed on the left instead.\n\t\n\u003c/details\u003e\n\t\n## XR Adaptation\n\n### Global XRUI Format\nXRUI's main functionality is to provide responsiveness for different XR variants. This is done by setting the chosen XRUI format during the app's initialization, which all XRUI Elements (both static and dynamic) adopt thanks to USS styles.\n\nTo change the global XRUI format, change the related value in the XRUI controller:\n\nThe XRUI API provides methods to assess the current XRUI format. You can use it to do target-specific manipulations like so:\n\n```csharp\nif(XRUI.IsGlobalXRUIFormat(XRUI.XRUIFormat.ThreeDimensional)) {\n    // 3D UI specific code here\n}\n\nXRUIFormat format = XRUI.GetGlobalXRUIFormat();\n``` \n\n### Overriding the Global XRUI Format for Specific Elements \nIt is also possible for specific UI elements to override the global format defined in the XRUI controller. This way, hybrid 2D and 3D / World UI elements can be rendered in the same scene. Each XRUI Element possesses the `xruiFormatOverride` property, which can be set to the following values:\n\n- `UseGlobal`: uses the value set in the XRUI controller (default value)\n- `TwoDimensional`: overrides the value set in the XRUI controller by setting this UI element format to 2D\n- `ThreeDimensional`: overrides the value set in the XRUI controller by setting this UI element format to 3D\n\nThe API provides methods to check the format of any XRUI Element:\n\n```csharp\nvar card = GetComponent\u003cXRUICard\u003e();\nif(card.IsXRUIFormat(XRUI.XRUIFormat.ThreeDimensional) {\n    // 3D UI specific code for this given element\n}\n\nXRUIFormat format = card.GetXRUIFormat(); \n```\n\n\u003e Note: When integrating World UI elements while using 2D as a global format, don't forget to change the Panel Settings of the UI Document to an asset that is fit for World UI (you can use the provided `DefaultWorldUIPanelSettings` asset).\n\n### Two Dimensional Format\nFor 2D UI, additional USS styles are provided to adapt for both landscape and portrait orientations. These classes are automatically added when the device (i.e., a smartphone) changes orientation.\nFor ease of use, you can force the portrait mode by checking the `Force Two Dimensional Format to Portrait` checkbox in the XRUI controller.\n\n### Three Dimensional Format (World Space UI)\nWhen XRUI is set to Three Dimensional format, UI is rendered on panels in world space. Each XRUI Element contains a set of `World UI Parameters` which can alter the way it is rendered in world space.\n\n\u003cimg width=\"672\" alt=\"worlduiparameters\" src=\"https://user-images.githubusercontent.com/25299178/204764750-744cacd2-5dcb-4211-8f5c-b6424bec5e35.png\"\u003e\n\n- The `Bend Panel` property will slightly bend the panel, which is a common practice in VR apps.\n- The `Anchor Panel To Camera` property makes the panel follow the gaze of the camera, with a slight delay.\n- The `Camera Follow Threshold` property defines the minimum distance that needs to be between the panel and the camera gaze before the panel recenters itself.\n- The `Custom Panel Dimensions` overrides the size of the panel, which is otherwise calculated from the ratio of the width and height of the UI element defined in the USS sheet.\n- The `Panel Scale` property lets you alter the scale of the panel. By default, the size of panels tend towards one world space unit.\n\n## XRUI Grid System\nIn order to organize easily and efficiently UI elements on screen, XRUI makes use of a grid system. You can use it by navigating to `XRUI \u003e Add XRUI Grid`. In the Unity editor, you can group UI components inside rows through the scene hierarchy. The `XRUIGridController` component is attached to the root of the grid, and contains the list of all rows. A weighting system allows you to define which rows should take which amount of space (this uses the `flex-grow` attribute of CSS/USS Flexbox). \n\nFor example, a top navbar can be setup in one row, with a weight of 0, i.e., it should not \"grow\"--as in, take space--more than its initial size. A second row containing the rest of the on-screen UI can have a weight of 1, i.e. it should take more of the available space than what its initial size requires. Since there are two rows and the first row has a weight of 0, this results in the second row using all remaining screen space. Horizontally, elements are contained in absolute containers, which mean they all take the entire horizontal space and can therefore overlap. \n\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/128205987-c9fcad0c-9639-4de9-902b-1a7141320a38.gif\"  alt=\"pc\" width =\"700\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/25299178/128047151-b90c0e4f-0a09-4a64-b54b-8d011ccba3ac.png\"  alt=\"pc\" width =\"500\"\u003e\n\t\n\u003e Note: In case all UI elements within a row are absolute, the row's height becomes zero, because its USS property is set to `height: auto`. You should then indicate a minimum height in the indicated field to obtain the expected behaviour.\n\n\u003c/details\u003e\n\n## Custom UI Elements\nYou can create your own UXML templates and refer them in the XRUI Configuration asset. You should however be careful in naming your elements, should you want to inherit the functionalities provided by the default UI elements. You can check them with Unity's UI Builder, or you can simply duplicate the UXML files and start working from here. \n\nAlso, the root visual element of your custom templates must have the `.xrui` USS class.\n\n### USS Styles\nXRUI comes with its own set of styles that are imported just after Unity's in UI Toolkit's pipeline. They are imported through a theme file which is used in the provided Panel Settings assets (also linked in the XRUI Configuration asset). You can add your own root styles to this theme file, override the root XRUI styles, or remove some of the imported assets if you don't need them. Should you want to inherit some of the XRUI styles for your own UI elements, you can add the related USS classes to the desired visual elements. \n\nAdditionally, when creating your custom elements based on existing ones, it is recommended that you add the following USS classes to keep the XRUI functionalities (e.g., updating the title from the inspector). They are the following:\n\n|      XRUI Element       |          Root USS Class          | Sub USS Classes                                                                                                                                                                                                                                           |\n|:-----------------------:|:--------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n|          Menu           |           `.xrui-menu`           | `.xrui-menu__title`\u003cbr/\u003e`.xrui-menu__subtitle`\u003cbr/\u003e`.xrui-menu__container`\u003cbr/\u003e`.xrui-menu__btn-container`\u003cbr/\u003e`.xrui-menu__close-btn`\u003cbr/\u003e`.xrui-menu__main-btn`                                                                                         |\n|        Menu item        |        `.xrui-menu-item`         |                                                                                                                                                                                                                                                           |\n|          List           |           `.xrui-list`           | `.xrui-list__title`\u003cbr/\u003e`.xrui-list__add-btn`\u003cbr/\u003e`.xrui-list__container`                                                                                                                                                                                 |\n|        List item        |        `.xrui-list-item`         | `.xrui-list-item__icon`\u003cbr/\u003e`.xrui-list-item__text`                                                                                                                                                                                                       |\n|         Navbar          |          `.xrui-navbar`          |                                                                                                                                                                                                                                                           |\n|          Card           |           `.xrui-card`           | `.xrui-card__title`\u003cbr/\u003e`.xrui-card__subtitle`\u003cbr/\u003e`.xrui-card__container`\u003cbr/\u003e`.xrui-card__close-btn`\u003cbr/\u003e                                                                                                                                               |\n|          Alert          |          `.xrui-alert`           | `.xrui-alert__title`\u003cbr/\u003e`.xrui-alert__content`                                                                                                                                                                                                           |\n|          Modal          |          `.xrui-modal`           | `.xrui-modal__title`\u003cbr/\u003e`.xrui-modal__close-btn`\u003cbr/\u003e`.xrui-modal__container`\u003cbr/\u003e`.xrui-modal__btn-container`\u003cbr/\u003e`.xrui-modal__cancel-btn`\u003cbr/\u003e`.xrui-modal__validate-btn`                                                                             |\n|     Contextual Menu     |     `.xrui-contextual-menu `     | `.xrui-contextual-menu__arrow`\u003cbr/\u003e`.xrui-contextual-menu__container`                                                                                                                                                                                     |\n| Contextual Menu Element | `.xrui-contextual-menu-element ` | `.xrui-contextual-menu-element__text`                                                                                                                                                                                                                     |                 \n|          Icons          |           `.xrui-icon`           | `.xrui-icon--white`\u003cbr/\u003e`.xrui-icon--black`                                                                                                                                                                                                               | \n|        Templates        |                                  | `.xrui-templates__btn`\u003cbr/\u003e`.xrui-templates__separator`\u003cbr/\u003e`.xrui-templates__textfield`                                                                                                                                                                  | \n|       Backgrounds       |                                  | `.xrui-background--primary`\u003cbr/\u003e`.xrui-background--secondary`\u003cbr/\u003e`.xrui-background--warning`\u003cbr/\u003e`.xrui-background--success`\u003cbr/\u003e`.xrui-background--danger`\u003cbr/\u003e`.xrui-background--info`\u003cbr/\u003e`.xrui-background--light-grey`\u003cbr/\u003e`.xrui-background--dark` | \n\n## XR Interactions\nSee the `XRUIDemoInteraction` scene in the Demo folder. \nTo enable interactions with world UI (i.e., make your UI react to MR/VR pointers), you need to add a few objects from the XR Interaction package in your scene:\n\n- An `Event Handler` component\n- The `Input Action Manager` component from the XRI package\n- The `XR Interaction Manager` from the XRI package\n- The `XR UI Input Module` from the XRI package\n\nYour controllers need:\n\n- The `XR Controller` component from the XRI package (preferably with the XRI input actions configured)\n- The `XR Ray Interactor` component from the XRI package\n  - You must check the \"Enable Interaction with UI GameObjects\" checkbox\n\nXRUI automatically adds the `Tracked Device Physics Raycaster` component to World UI game objects.\n\nYou can also specifically disable XR interactions on specific XRUI Elements, to avoid adding unnecessary Game Objects to your scene at runtime. To do so, check the `Disable XR Interaction` checkbox in the `World UI Parameters` section of the XRUI Element.\n## Acknowledgements\n- Thanks to [katas94](https://gist.github.com/katas94/7b220a591215efc36110860a0b1125eb) for the inspiration on interfacing XRUI with Unity Event Handlers and the XR Interaction package.\n- Thanks to [mattvr](https://gist.github.com/mattvr/8cdcc922d1a75d0a7a7abf5d46e23ef0) for their gist to create curved panels.\n- Thanks to [swifter14](https://forum.unity.com/threads/lock-auto-rotation-on-android-doesnt-work.842893/) for the fix on Android auto-rotation lock.\n- Thanks to [NormandErwan](https://github.com/NormandErwan/DocFxForUnity) for DocFxForUnity.\n\n## Roadmap\n- Grid system for World UI\n- Animation mechanism for all XRUI Elements\n- Custom inspectors for ease of use\n\n## Known bugs\n- Raycasts on World UI Interactions do not entirely match the visuals shown to the users when using the Oculus SDK. Collisions are detected on the left of panels although they should not, and they stop too early before the right border of the panel.\n- When scripts are recompiled in the Editor, 2D UI Elements will sometimes not update properly. This is not really problematic as going into play mode re-renders all UI Elements correctly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchwar%2FXRUI","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchwar%2FXRUI","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchwar%2FXRUI/lists"}