{"id":495238,"date":"2026-09-19T05:50:15","date_gmt":"2026-09-19T05:50:15","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=495238"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=495238","title":{"rendered":"Centrifugal. A flexible user interface for creating standalone web applications"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Hi everyone! Today I\u2019d like to talk about another\u00a0<a href=\"https:\/\/github.com\/DjonnyX\/centrifugal\" rel=\"noopener nofollow\">open-source<\/a>\u00a0project of mine for building web applications based on Angular.<\/p>\n<p>Over the past few years, I have conducted numerous successful experiments with high-performance web interfaces, which has given me a clear understanding of the structure and architecture for the project discussed below.<\/p>\n<p>So, meet\u00a0<a href=\"https:\/\/github.com\/DjonnyX\/centrifugal\" rel=\"noopener nofollow\">Centrifugal<\/a>. Check out the project\u2019s\u00a0<a href=\"https:\/\/centrifugal.eugene-grebennikov.pro\/\" rel=\"noopener nofollow\">official website<\/a>\u2014there are plenty of cool use cases there!<\/p>\n<p>The project was originally conceived to create a set of high-performance, flexible tools and components for building web applications. However, during one of the development iterations, I decided to add support for creating \u201call-in-one\u201d interfaces\u2014specifically, a standalone application mode featuring a fully customizable virtual keyboard. This enabled full support for building user interfaces for applications such as self-service kiosks and similar systems.<\/p>\n<p>Keyboard position, layouts, key sets, and styles are fully customizable. A custom mechanism for focusing on on-screen elements has been implemented. When a text field gains focus, the virtual keyboard slides out (depending on the configuration), and scroll containers undergo multi-level scrolling up to the keyboard\u2019s actual edge, ensuring ease of input and readability.<\/p>\n<p>Since custom scroll containers are used, the handling of standard interactive HTML components\u2014such as &lt;button\/&gt;, &lt;a\/&gt;, &lt;input\/&gt;, &lt;textarea\/&gt;, and so on\u2014changes slightly. To ensure correct handling, a special\u00a0<code>NtControl<\/code>\u00a0directive has been created; it must be applied to all standard interactive HTML components.<\/p>\n<p>Example:<\/p>\n<pre><code>&lt;button ntControl (onVirtualClick)=\"onVirtualClickHandler($event)\"&gt;  My button&lt;\/button&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Full support has been implemented for\u00a0<code>&lt;input\/&gt;<\/code>\u00a0types such as text, password, number, email, tel, and URL. Additionally, you can specify a custom text field type and configure the corresponding keyboard layout for that type.<\/p>\n<pre><code>&lt;input type=\"text\" ntControl value\"Text\"&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>For an example of a custom type and keyboard layout, see the\u00a0<a href=\"https:\/\/centrifugal.eugene-grebennikov.pro\/#\/virtual-keyboard\" rel=\"noopener nofollow\">Virtual keyboard<\/a>\u00a0link. Using\u00a0<a href=\"https:\/\/github.com\/DjonnyX\/centrifugal\" rel=\"noopener nofollow\">Centrifugal<\/a>\u00a0components is quite simple; take a look at the example of creating a scroll-view:<\/p>\n<pre><code>&lt;nt-scroll-view #scrollView&gt;  &lt;div class=\"scroll-view__content\" [style.width.px]=\"3000\" [style.height.px]=\"3000\"    [class.grabbing]=\"scrollView.$grabbing | async\"&gt;    My content  &lt;\/div&gt;&lt;\/nt-scroll-view&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>or a slider example:<\/p>\n<pre><code>&lt;nt-slider [step]=\"1\" [max]=\"100\" [value]=\"value()\" thumbSize=\"50%\" (onChange)=\"onSliderChangeHandler($event)\"&gt;&lt;\/nt-slider&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>Fluid UI<\/h3>\n<p>Now I would like to demonstrate the Fluid UI concept and the principles of how it works.<\/p>\n<p>Each component of the user interface\u2014developed using the\u00a0<a href=\"https:\/\/github.com\/DjonnyX\/centrifugal\" rel=\"noopener nofollow\">Centrifugal<\/a>\u00a0library\u2014interacts with the other components along a hierarchical chain, employing specific \u201cphysical\u201d interactions. Forces of compression or tension may be applied, impulses transmitted, and so forth.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/881\/fee\/b12\/881feeb1272ecb4b675546c7240806a9.gif\" alt=\"1000467292.gif\" title=\"A representation of the interaction between Fluid UI components.\" width=\"400\" height=\"246\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/881\/fee\/b12\/881feeb1272ecb4b675546c7240806a9.gif 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/881\/fee\/b12\/881feeb1272ecb4b675546c7240806a9.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>A representation of the interaction between Fluid UI components.<\/figcaption><\/div>\n<\/figure>\n<p>The library does not handle standard web scroll containers; instead,\u00a0<a href=\"https:\/\/github.com\/DjonnyX\/centrifugal\" rel=\"noopener nofollow\">Centrifugal<\/a>\u00a0employs its own implementation of scroll containers featuring specific \u201cphysical\u201d properties\u2014such as scroll speed, acceleration, friction, and so on. This tool focuses entirely on working with standard HTML components, providing developers with familiar methods for building web applications.<\/p>\n<p>In addition to the \u201cphysics\u201d engine, each base component accepts a set of parameters to generate a motion blur effect. Motion blur is disabled by default, as it is a relatively resource-intensive post-processing effect.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d3c\/38e\/85f\/d3c38e85fd1adfab0eab70daa720452d.gif\" alt=\"1000467293.gif\" title=\"An  example demonstrating the compression\/stretching of user interface components.\" width=\"400\" height=\"249\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d3c\/38e\/85f\/d3c38e85fd1adfab0eab70daa720452d.gif 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d3c\/38e\/85f\/d3c38e85fd1adfab0eab70daa720452d.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>An  example demonstrating the compression\/stretching of user interface components.<\/figcaption><\/div>\n<\/figure>\n<p>In addition to motion blur, virtual lists can apply element transformations to create 3D list spaces, as well as depth of field and fog effects for list elements receding into the background.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d1\/912\/a58\/9d1912a58e722eb54b844e3c1290f58b.gif\" alt=\"1000467294.gif\" title=\"Drawer component with vertical spacing.\" width=\"400\" height=\"229\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d1\/912\/a58\/9d1912a58e722eb54b844e3c1290f58b.gif 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d1\/912\/a58\/9d1912a58e722eb54b844e3c1290f58b.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>Drawer component with vertical spacing.<\/figcaption><\/div>\n<\/figure>\n<p>Support is provided for complex component interactions\u2014such as the example in the image above, which demonstrates a sectioned \u201cSheet\u201d web component. In addition to controlling the component itself (opening or closing it), the user can simultaneously interact with its internal components.<\/p>\n<p>Most importantly, notice how simple it is to use complex component implementations in the code:<\/p>\n<pre><code>&lt;nt-sheet #sheet class=\"sheet\" position=\"bottom\"&gt;  &lt;div class=\"sheet__content\" [class.grabbing]=\"sheet.$grabbing | async\"&gt;    Content  &lt;\/div&gt;&lt;\/nt-sheet&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>It is designed with developer ease of use in mind.<\/p>\n<p>All this and more enables you to create sophisticated next-gen web interfaces for your applications!<\/p>\n<h3>API<\/h3>\n<p>The API is available for extensions, enabling the creation of compelling components. See an\u00a0<a href=\"https:\/\/centrifugal.eugene-grebennikov.pro\/#\/time-picker-demo\" rel=\"noopener nofollow\">example of a custom component<\/a>\u00a0built using the library\u2019s standard API.<\/p>\n<p>A full description of the API and usage examples are provided on the project\u2019s\u00a0<a href=\"https:\/\/centrifugal.eugene-grebennikov.pro\/\" rel=\"noopener nofollow\">official website<\/a>.<\/p>\n<h3>Examples<\/h3>\n<p>The\u00a0<code>centrifugal\/examples<\/code>\u00a0section features great examples of how to use the tool. You can view live demos on the project\u2019s official website under \u201cAdvanced Examples.\u201d<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1084070\/\">https:\/\/habr.com\/ru\/articles\/1084070\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi everyone! Today I\u2019d like to talk about another\u00a0open-source\u00a0project of mine for building web applications based on Angular.Over the past few years, I have conducted numerous successful experiments with high-performance web interfaces, which has given me a clear understanding of the structure and architecture for the project discussed below.So, meet\u00a0Centrifugal. Check out the project\u2019s\u00a0official website\u2014there are plenty of cool use cases there!The project was originally conceived to create a set of high-performance, flexible tools and components for building web applications. However, during one of the development iterations, I decided to add support for creating \u201call-in-one\u201d interfaces\u2014specifically, a standalone application mode featuring a fully customizable virtual keyboard. This enabled full support for building user interfaces for applications such as self-service kiosks and similar systems.Keyboard position, layouts, key sets, and styles are fully customizable. A custom mechanism for focusing on on-screen elements has been implemented. When a text field gains focus, the virtual keyboard slides out (depending on the configuration), and scroll containers undergo multi-level scrolling up to the keyboard\u2019s actual edge, ensuring ease of input and readability.Since custom scroll containers are used, the handling of standard interactive HTML components\u2014such as &lt;button\/&gt;, &lt;a\/&gt;, &lt;input\/&gt;, &lt;textarea\/&gt;, and so on\u2014changes slightly. To ensure correct handling, a special\u00a0NtControl\u00a0directive has been created; it must be applied to all standard interactive HTML components.Example:&lt;button ntControl (onVirtualClick)=&#187;onVirtualClickHandler($event)&#187;&gt;  My button&lt;\/button&gt;Full support has been implemented for\u00a0&lt;input\/&gt;\u00a0types such as text, password, number, email, tel, and URL. Additionally, you can specify a custom text field type and configure the corresponding keyboard layout for that type.&lt;input type=&#187;text&#187; ntControl value&#187;Text&#187;&gt;For an example of a custom type and keyboard layout, see the\u00a0Virtual keyboard\u00a0link. Using\u00a0Centrifugal\u00a0components is quite simple; take a look at the example of creating a scroll-view:&lt;nt-scroll-view #scrollView&gt;  &lt;div class=&#187;scroll-view__content&#187; [style.width.px]=&#187;3000&#8243; [style.height.px]=&#187;3000&#8243;    [class.grabbing]=&#187;scrollView.$grabbing | async&#187;&gt;    My content  &lt;\/div&gt;&lt;\/nt-scroll-view&gt;or a slider example:&lt;nt-slider [step]=&#187;1&#8243; [max]=&#187;100&#8243; [value]=&#187;value()&#187; thumbSize=&#187;50%&#187; (onChange)=&#187;onSliderChangeHandler($event)&#187;&gt;&lt;\/nt-slider&gt;Fluid UINow I would like to demonstrate the Fluid UI concept and the principles of how it works.Each component of the user interface\u2014developed using the\u00a0Centrifugal\u00a0library\u2014interacts with the other components along a hierarchical chain, employing specific \u201cphysical\u201d interactions. Forces of compression or tension may be applied, impulses transmitted, and so forth.A representation of the interaction between Fluid UI components.The library does not handle standard web scroll containers; instead,\u00a0Centrifugal\u00a0employs its own implementation of scroll containers featuring specific \u201cphysical\u201d properties\u2014such as scroll speed, acceleration, friction, and so on. This tool focuses entirely on working with standard HTML components, providing developers with familiar methods for building web applications.In addition to the \u201cphysics\u201d engine, each base component accepts a set of parameters to generate a motion blur effect. Motion blur is disabled by default, as it is a relatively resource-intensive post-processing effect.An  example demonstrating the compression\/stretching of user interface components.In addition to motion blur, virtual lists can apply element transformations to create 3D list spaces, as well as depth of field and fog effects for list elements receding into the background.Drawer component with vertical spacing.Support is provided for complex component interactions\u2014such as the example in the image above, which demonstrates a sectioned \u201cSheet\u201d web component. In addition to controlling the component itself (opening or closing it), the user can simultaneously interact with its internal components.Most importantly, notice how simple it is to use complex component implementations in the code:&lt;nt-sheet #sheet class=&#187;sheet&#187; position=&#187;bottom&#187;&gt;  &lt;div class=&#187;sheet__content&#187; [class.grabbing]=&#187;sheet.$grabbing | async&#187;&gt;    Content  &lt;\/div&gt;&lt;\/nt-sheet&gt;It is designed with developer ease of use in mind.All this and more enables you to create sophisticated next-gen web interfaces for your applications!APIThe API is available for extensions, enabling the creation of compelling components. See an\u00a0example of a custom component\u00a0built using the library\u2019s standard API.A full description of the API and usage examples are provided on the project\u2019s\u00a0official website.ExamplesThe\u00a0centrifugal\/examples\u00a0section features great examples of how to use the tool. You can view live demos on the project\u2019s official website under \u201cAdvanced Examples.\u201d\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 https:\/\/habr.com\/ru\/articles\/1084070\/<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-495238","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/495238","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=495238"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/495238\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=495238"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=495238"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=495238"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}