From 78c124cc0c9e6b82ed1ffdfe08181272a5831b9b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 31 Jan 2024 03:31:36 +0000 Subject: [PATCH] deploy: 1fac2ec6513a26f7628e74cd216a358b5e57dc2f --- 404.html | 4 ++-- About/index.html | 4 ++-- Airbrush/index.html | 4 ++-- Appendix/Vector-fill/index.html | 4 ++-- Basics/Basics/index.html | 4 ++-- Basics/Stamp/index.html | 4 ++-- Basics/Vanilla/index.html | 6 +++--- Introduction/index.html | 16 +++++++++------- Tessellation/index.html | 4 ++-- .../{styles.15dfc647.css => styles.9052d387.css} | 2 +- assets/js/ac092286.bc24b4de.js | 1 + assets/js/ac092286.f7f1d5f0.js | 1 - assets/js/bc662926.39ae1e06.js | 1 + assets/js/bc662926.4b304381.js | 1 - ...main.cc49c654.js => runtime~main.c8dce5ea.js} | 2 +- category/appendix/index.html | 4 ++-- category/basics/index.html | 4 ++-- index.html | 4 ++-- 18 files changed, 36 insertions(+), 34 deletions(-) rename assets/css/{styles.15dfc647.css => styles.9052d387.css} (72%) create mode 100644 assets/js/ac092286.bc24b4de.js delete mode 100644 assets/js/ac092286.f7f1d5f0.js create mode 100644 assets/js/bc662926.39ae1e06.js delete mode 100644 assets/js/bc662926.4b304381.js rename assets/js/{runtime~main.cc49c654.js => runtime~main.c8dce5ea.js} (53%) diff --git a/404.html b/404.html index e91c0d4..b5a2272 100644 --- a/404.html +++ b/404.html @@ -3,8 +3,8 @@ -Brush Rendering Tutorial - +Brush Rendering Tutorial + diff --git a/About/index.html b/About/index.html index e6ef80b..432b58d 100644 --- a/About/index.html +++ b/About/index.html @@ -3,8 +3,8 @@ -About | Brush Rendering Tutorial - +About | Brush Rendering Tutorial + diff --git a/Airbrush/index.html b/Airbrush/index.html index 7ee5d52..66de56b 100644 --- a/Airbrush/index.html +++ b/Airbrush/index.html @@ -3,8 +3,8 @@ -Airbrush | Brush Rendering Tutorial - +Airbrush | Brush Rendering Tutorial + diff --git a/Appendix/Vector-fill/index.html b/Appendix/Vector-fill/index.html index ab69c07..c3e47d5 100644 --- a/Appendix/Vector-fill/index.html +++ b/Appendix/Vector-fill/index.html @@ -3,8 +3,8 @@ -Pre-introduction to Vector Fill | Brush Rendering Tutorial - +Pre-introduction to Vector Fill | Brush Rendering Tutorial + diff --git a/Basics/Basics/index.html b/Basics/Basics/index.html index 4fd0971..2ff5c9d 100644 --- a/Basics/Basics/index.html +++ b/Basics/Basics/index.html @@ -3,8 +3,8 @@ -Problem Statement | Brush Rendering Tutorial - +Problem Statement | Brush Rendering Tutorial + diff --git a/Basics/Stamp/index.html b/Basics/Stamp/index.html index 1a97705..bbb8a4c 100644 --- a/Basics/Stamp/index.html +++ b/Basics/Stamp/index.html @@ -3,8 +3,8 @@ -Stamp | Brush Rendering Tutorial - +Stamp | Brush Rendering Tutorial + diff --git a/Basics/Vanilla/index.html b/Basics/Vanilla/index.html index e20e052..6319531 100644 --- a/Basics/Vanilla/index.html +++ b/Basics/Vanilla/index.html @@ -3,8 +3,8 @@ -Vanilla | Brush Rendering Tutorial - +Vanilla | Brush Rendering Tutorial + @@ -36,7 +36,7 @@ When mocking geometry shader's behavior with instanced rendering, the code gets obscure. Sadly, graphics engineers cannot easily enjoy this elegance because of Apple's Metal API.

You may argue that geometry shader can cause a lot of performance issues. But benefiting from hard work by GPU engineers and manufacturers, -the computational power is very much superfluous to draw 2D contents with a modern discrete graphics card. +the computational power is very much superfluous to draw 2D strokes with a modern discrete graphics card. Performance is not everything. Writing maintainable and easy-to-understand code is much more critical in some cases.

We use instanced rendering to draw a large number of objects with the same vertex data. diff --git a/Introduction/index.html b/Introduction/index.html index b3a7ba9..2f61ebb 100644 --- a/Introduction/index.html +++ b/Introduction/index.html @@ -3,8 +3,8 @@ -Introduction | Brush Rendering Tutorial - +Introduction | Brush Rendering Tutorial + @@ -17,8 +17,8 @@

This tutorial series will teach you how to use the modern GPU graphics pipeline to render brush strokes, commonly seen with a paint tool in graphics design software like Photoshop. The contents mainly come from my research work Ciallo: The next generation vector paint program, -and a textbook "Image and Video-Based Artistic Stylisation" edited by Paul Rosin, John Collomosse. -The book introduces brush stroke rendering in its second chapter, authored by Stephen DiVerdi. +and the second chapter of the textbook "Image and Video-Based Artistic Stylisation" edited by Paul Rosin, John Collomosse. +The chapter introduces classical stroke rendering methods, authored by Stephen DiVerdi. Since there will be more research work on GPU brush stroke rendering, I will continuously update this tutorial series to teach you related techniques in (potentially) influential research works.

Prerequisites

@@ -36,7 +36,7 @@

StructureContent

The Basic section covers the basics of the rendering and stylization methods. Articles in the Basic part are organized in a progressive fashion. -You may miss something important if skip one of them. +Don't jump right into one of them, or you may miss something important. After learning the Basic section, you can freely select your favorite topics. I will list extra prerequisites at the very beginning of each article.

Live coding

@@ -56,8 +56,10 @@

Suppl

Citation

@inproceedings{Ciallo2023,
author = {Ciao, Shen and Wei, Li-Yi},
title = {Ciallo: The next-Generation Vector Paint Program},
year = {2023},
isbn = {9798400701436},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
url = {https://doi.org/10.1145/3587421.3595418},
doi = {10.1145/3587421.3595418},
booktitle = {ACM SIGGRAPH 2023 Talks},
articleno = {67},
numpages = {2},
keywords = {Digital painting, stylized stroke, arrangement, vector graphics. coloring, graphics processing unit (GPU)},
location = {Los Angeles, CA, USA},
series = {SIGGRAPH '23}
}
Research Tip

To demonstrate your research work about brush rendering, select vector drawings have variable radius or pen pressure data. -Regular vector drawing datasets don't contain them.

diff --git a/Tessellation/index.html b/Tessellation/index.html index fd48302..85b80b9 100644 --- a/Tessellation/index.html +++ b/Tessellation/index.html @@ -3,8 +3,8 @@ -Tessellation-based Rendering | Brush Rendering Tutorial - +Tessellation-based Rendering | Brush Rendering Tutorial + diff --git a/assets/css/styles.15dfc647.css b/assets/css/styles.9052d387.css similarity index 72% rename from assets/css/styles.15dfc647.css rename to assets/css/styles.9052d387.css index 55af79b..8210d5c 100644 --- a/assets/css/styles.15dfc647.css +++ b/assets/css/styles.9052d387.css @@ -1 +1 @@ -.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#2e8555;--ifm-color-primary-dark:#29784c;--ifm-color-primary-darker:#277148;--ifm-color-primary-darkest:#205d3b;--ifm-color-primary-light:#33925d;--ifm-color-primary-lighter:#359962;--ifm-color-primary-lightest:#3cad6e;--ifm-code-font-size:95%;--ifm-table-cell-padding:0px;--ifm-table-head-background:#fff;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.list_eTzJ article:last-child,.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_BuS1>:last-child,.cardContainer_fWXF :last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{content:"";height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#25c2a0;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--docusaurus-highlighted-code-line-bg:#0000004d}#__docusaurus-base-url-issue-banner-container,.katex-html,.themedComponent_mlkZ,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.katex-mathml{font-size:18px}figcaption{text-after-overflow:0;font-style:italic;padding-bottom:.5em}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.dropdownNavbarItemMobile_S0Fm{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}@supports selector(:has(*)){.navbarSearchContainer_Bca1:not(:has(>*)){display:none}}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.cardContainer_fWXF{--ifm-link-color:var(--ifm-color-emphasis-800);--ifm-link-hover-color:var(--ifm-color-emphasis-700);--ifm-link-hover-decoration:none;border:1px solid var(--ifm-color-emphasis-200);box-shadow:0 1.5px 3px 0 #00000026;transition:all var(--ifm-transition-fast) ease;transition-property:border,box-shadow}.cardContainer_fWXF:hover{border-color:var(--ifm-color-primary);box-shadow:0 3px 6px 0 #0003}.cardTitle_rnsV{font-size:1.2rem}.cardDescription_PWke{font-size:.8rem}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.title_kItE{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-leading)*1.25)}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.docSidebarContainer_YfHR,.sidebarLogo_isFc{display:none}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.navbarSearchContainer_Bca1{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn,.generatedIndexPage_vN6x{max-width:75%!important}.list_eTzJ article:nth-last-child(-n+2){margin-bottom:0!important}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown li,body{word-wrap:break-word}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}.clean-list,.containsTaskList_mC6p,.details_lb9f>summary,.dropdown__menu,.menu__list{list-style:none}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ifm-color-primary:#2e8555;--ifm-color-primary-dark:#29784c;--ifm-color-primary-darker:#277148;--ifm-color-primary-darkest:#205d3b;--ifm-color-primary-light:#33925d;--ifm-color-primary-lighter:#359962;--ifm-color-primary-lightest:#3cad6e;--ifm-code-font-size:95%;--ifm-table-cell-padding:0px;--ifm-table-head-background:#fff;--docusaurus-highlighted-code-line-bg:#0000001a;--docusaurus-announcement-bar-height:auto;--docusaurus-tag-list-border:var(--ifm-color-emphasis-300);--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}*{box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);text-rendering:optimizelegibility}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.list_eTzJ article:last-child,.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col{padding-left:0;padding-right:0}.row--align-top{align-items:flex-start}.row--align-bottom{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center{align-items:center}.row--align-stretch{align-items:stretch}.row--align-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{border-collapse:collapse;display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.text--center{text-align:center}.text--left{text-align:left}.text--justify{text-align:justify}.text--right{text-align:right}.text--capitalize{text-transform:capitalize}.text--lowercase{text-transform:lowercase}.admonitionHeading_Gvgb,.alert__heading,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.text--italic{font-style:italic}.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list{padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.card--full-height,.navbar__logo img,body,html{height:100%}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child){padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{font-size:.8rem;margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover{opacity:.7}.close:focus,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}#nprogress,.dropdown__menu,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color);text-decoration:none}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__links{margin-bottom:1rem}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item{margin-top:0}.admonitionContent_BuS1>:last-child,.cardContainer_fWXF :last-child,.collapsibleContent_i85q p:last-child,.details_lb9f>summary>p:last-child,.footer__items,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title{font-size:3rem}.hero__subtitle{font-size:1.5rem}.menu__list{margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child){margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after{transform:rotate(90deg)}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color);text-decoration:none}.menu__caret:before,.menu__link--sublist-caret:after{content:"";height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast) linear;width:1.25rem;filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;margin-left:auto;min-width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar,.navbar>.container,.navbar>.container-fluid{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;position:fixed;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out;left:0;top:0;visibility:hidden}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;margin-right:1rem;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto;height:2rem;margin-right:.5rem}.navbar__items{align-items:center;display:flex;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.navbar__items--center .navbar__brand{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color);text-decoration:none}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:.9rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;right:0;transition-property:opacity,visibility}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination__link:hover{text-decoration:none}.pagination-nav{grid-gap:var(--ifm-spacing-horizontal);display:grid;gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover);text-decoration:none}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs,mstyle{display:flex}.tabs,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);margin-bottom:0;overflow-x:auto}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;left:0;position:fixed;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}[data-theme=dark]{--ifm-color-primary:#25c2a0;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--docusaurus-highlighted-code-line-bg:#0000004d}#__docusaurus-base-url-issue-banner-container,.katex-html,.themedComponent_mlkZ,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}span.katex-mathml{font-size:18px}span.katex-display math{padding-bottom:.7em}figcaption{text-after-overflow:0;font-style:italic;padding-bottom:.5em}mstyle{flex-direction:row;justify-content:left;width:100%}.hidden{display:none!important}body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit;text-decoration:underline}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}.iconExternalLink_nPIU{margin-left:.3rem}.dropdownNavbarItemMobile_S0Fm{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}@supports selector(:has(*)){.navbarSearchContainer_Bca1:not(:has(>*)){display:none}}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,:hover>.hash-link{opacity:1}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg{margin-top:3rem}#__docusaurus{display:flex;flex-direction:column;min-height:100%}.cardContainer_fWXF{--ifm-link-color:var(--ifm-color-emphasis-800);--ifm-link-hover-color:var(--ifm-color-emphasis-700);--ifm-link-hover-decoration:none;border:1px solid var(--ifm-color-emphasis-200);box-shadow:0 1.5px 3px 0 #00000026;transition:all var(--ifm-transition-fast) ease;transition-property:border,box-shadow}.cardContainer_fWXF:hover{border-color:var(--ifm-color-primary);box-shadow:0 3px 6px 0 #0003}.cardTitle_rnsV{font-size:1.2rem}.cardDescription_PWke{font-size:.8rem}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color);text-decoration:none}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tags_jXut{display:inline}.tag_QGVx{display:inline-block;margin:0 .4rem .5rem 0}.lastUpdated_vwxv{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.tocCollapsibleContent_vkbj a{display:block}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V{border-top-left-radius:0;border-top-right-radius:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}.theme-code-block:hover .buttonGroup__atx button{opacity:.4}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{fill:currentColor;height:inherit;left:0;opacity:inherit;position:absolute;top:0;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.img_ev3q{height:auto}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family)}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionHeading_Gvgb code{text-transform:none}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{fill:var(--ifm-alert-foreground-color);display:inline-block;height:1.6em;width:1.6em}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}.title_kItE{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-leading)*1.25)}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.docSidebarContainer_YfHR,.sidebarLogo_isFc{display:none}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.navbarSearchContainer_Bca1{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_vwxv{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn,.generatedIndexPage_vN6x{max-width:75%!important}.list_eTzJ article:nth-last-child(-n+2){margin-bottom:0!important}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}}@media (min-width:1440px){.container{max-width:var(--ifm-container-width-xl)}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.docItemContainer_F8PC{padding:0 .3rem}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/assets/js/ac092286.bc24b4de.js b/assets/js/ac092286.bc24b4de.js new file mode 100644 index 0000000..120678f --- /dev/null +++ b/assets/js/ac092286.bc24b4de.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbrush_stroke_tutorial=self.webpackChunkbrush_stroke_tutorial||[]).push([[364],{5923:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var r=t(5893),o=t(1151),a=t(5632);const i={title:"Introduction",sidebar_position:2},s=void 0,l={id:"Introduction/Introduction",title:"Introduction",description:"Vanilla",source:"@site/docs/Introduction/Introduction.mdx",sourceDirName:"Introduction",slug:"/Introduction/",permalink:"/brush-rendering-tutorial/Introduction/",draft:!1,unlisted:!1,editUrl:"https://github.com/ShenCiao/brush-rendering-tutorial/tree/main/docs/Introduction/Introduction.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{title:"Introduction",sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Table of Contents",permalink:"/brush-rendering-tutorial/"},next:{title:"Basics",permalink:"/brush-rendering-tutorial/category/basics"}},c={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Structure",id:"structure",level:2},{value:"Content",id:"content",level:3},{value:"Live coding",id:"live-coding",level:3},{value:"Supplementary contents",id:"supplementary-contents",level:3},{value:"Citation",id:"citation",level:2}];function u(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.a)(),...e.components},{Details:t}=n;return t||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)("div",{className:"row row--no-gutters margin-left--xs",children:[(0,r.jsxs)("div",{className:"col col--6",children:[(0,r.jsx)(a.ij,{}),(0,r.jsx)("center",{children:(0,r.jsx)("em",{children:" Vanilla "})})]}),(0,r.jsxs)("div",{className:"col col--6",children:[(0,r.jsx)(a.ij,{uniforms:a.PQ}),(0,r.jsx)("center",{children:(0,r.jsx)("em",{children:" Pencil "})})]})]}),"\n",(0,r.jsx)("br",{}),"\n",(0,r.jsxs)(n.admonition,{type:"note",children:[(0,r.jsx)(n.p,{children:"When hovering your mouse on the canvas you can:"}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Pan"}),": Left-click and drag the mouse."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Zoom"}),": Scroll or drag the mouse wheel."]}),"\n"]})]}),"\n",(0,r.jsxs)(n.p,{children:["This tutorial series will teach you how to use the modern GPU graphics pipeline to render brush strokes,\ncommonly seen with a paint tool in graphics design software like Photoshop.\nThe contents mainly come from my research work ",(0,r.jsx)(n.a,{href:"https://github.com/ShenCiao/Ciallo",children:"Ciallo: The next generation vector paint program"}),',\nand the second chapter of the textbook "Image and Video-Based Artistic Stylisation" edited by Paul Rosin, John Collomosse.\nThe chapter introduces classical stroke rendering methods, authored by Stephen DiVerdi.\nSince there will be more research work on GPU brush stroke rendering,\nI will continuously update this tutorial series to teach you related techniques in (potentially) influential research works.']}),"\n",(0,r.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsx)(n.p,{children:"Decent experience in one of the GPU graphics APIs like OpenGL and D3D is required.\nIf you were relatively new to computer graphics, you should at least have rendered your first 3D scene and practiced instanced rendering."}),"\n",(0,r.jsxs)(n.p,{children:["GPU APIs have built-in line rendering functionalities.\nIt's totally fine if you never heard about ",(0,r.jsx)(n.code,{children:"LINES"}),", ",(0,r.jsx)(n.code,{children:"LINE_STRIP"}),", and ",(0,r.jsx)(n.code,{children:"LINE_LOOP"})," GPU primitives.\nWe won't use the functionalities in this tutorial series.\nIf you're interested in learning about their drawbacks, you can check out mattdesl's article titled ",(0,r.jsx)(n.a,{href:"https://mattdesl.svbtle.com/drawing-lines-is-hard",children:"Drawing Lines is Hard"}),".\nReading it isn't a prerequisite, I still recommend it."]}),"\n",(0,r.jsx)(n.p,{children:"Though I create all the demos in the web environment, you don't have to know about WebGL or WebGPU.\nWe will concentrate on high-level techniques rather than the implementation details.\nNo matter which GPU API you are familiar with, utilizing them to render a stroke will be easy after this series."}),"\n",(0,r.jsx)(n.h2,{id:"structure",children:"Structure"}),"\n",(0,r.jsx)(n.h3,{id:"content",children:"Content"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.a,{href:"../category/basics/",children:"Basic"})," section covers the basics of the rendering and stylization methods.\nArticles in the Basic part are organized in a progressive fashion.\nDon't jump right into one of them, or you may miss something important.\nAfter learning the Basic section, you can freely select your favorite topics.\nI will list extra prerequisites at the very beginning of each article."]}),"\n",(0,r.jsx)(n.h3,{id:"live-coding",children:"Live coding"}),"\n",(0,r.jsxs)(n.p,{children:["You will find live code editors similar to the one displayed below, inspired by ",(0,r.jsx)(n.a,{href:"https://thebookofshaders.com/",children:(0,r.jsx)(n.em,{children:"The Book of Shader"})}),".\nThe rendering result is updated in real-time after modifying the code.\nGive it a try by altering the values of ",(0,r.jsx)(n.code,{children:"maxRadius"}),", and watch how the canvas below changes."]}),"\n",(0,r.jsx)(a.ij,{showEditor:[!0,!1,!1]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["If there are bugs for common usages in the code editors or canvases, tell me at the ",(0,r.jsx)(n.a,{href:"https://github.com/ShenCiao/brush-rendering-tutorial/issues",children:"issue"})," page."]})}),"\n",(0,r.jsx)(n.p,{children:'Only geometry generation code "geometry.js" is demonstrated here.\nYou will find "vertex.glsl" and "fragment.glsl" for vertex and fragment shader code.\nWhether they are hidden or shown will depend on the context.'}),"\n",(0,r.jsx)(n.h3,{id:"supplementary-contents",children:"Supplementary contents"}),"\n",(0,r.jsx)(t,{open:!0,children:(0,r.jsxs)(n.p,{children:[(0,r.jsx)("summary",{children:"Dropdown tab"}),"\nSome contents are hidden inside a dropdown tab like this.\nThey are complementary to the main contents.\nFeel free to skip them."]})}),"\n",(0,r.jsx)(n.h2,{id:"citation",children:"Citation"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"@inproceedings{Ciallo2023,\n author = {Ciao, Shen and Wei, Li-Yi},\n title = {Ciallo: The next-Generation Vector Paint Program},\n year = {2023},\n isbn = {9798400701436},\n publisher = {Association for Computing Machinery},\n address = {New York, NY, USA},\n url = {https://doi.org/10.1145/3587421.3595418},\n doi = {10.1145/3587421.3595418},\n booktitle = {ACM SIGGRAPH 2023 Talks},\n articleno = {67},\n numpages = {2},\n keywords = {Digital painting, stylized stroke, arrangement, vector graphics. coloring, graphics processing unit (GPU)},\n location = {Los Angeles, CA, USA},\n series = {SIGGRAPH '23}\n}\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Research Tip",type:"note",children:[(0,r.jsx)(n.p,{children:"To demonstrate your research work about brush rendering, select vector drawings have variable radius or pen pressure data.\nRegular vector graphics datasets don't contain them."}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["OpenSketch: ",(0,r.jsx)(n.a,{href:"https://dl.acm.org/doi/10.1145/3355089.3356533",children:"Paper"})]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://zachzeyuwang.github.io/tracing-vs-freehand.html",children:"Tracing versus freehand"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://chufengxiao.github.io/DifferSketching/",children:"DifferSketching"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://cloud.blender.org/p/gallery/5b642e25bf419c1042056fc6",children:"Blender Grease Pencil"})}),"\n",(0,r.jsxs)(n.li,{children:["... Tell me more in the ",(0,r.jsx)(n.a,{href:"https://github.com/ShenCiao/brush-rendering-tutorial/discussions/1",children:"discussion"}),"."]}),"\n"]})]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(u,{...e})}):u(e)}},5632:(e,n,t)=>{t.d(n,{ij:()=>g,Sw:()=>b,rL:()=>j,PQ:()=>w});var r=t(7294),o=t(9477),a=t(5452),i=t(4866),s=t(5162),l=t(3764),c=t(5034),d=t(9279);const u="precision mediump float;\nprecision mediump int;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\nin vec2 position0;\nin float radius0;\nin float summedLength0;\nin vec2 position1;\nin float radius1;\nin float summedLength1;\n\nout vec2 p; // position of the current pixel\nflat out vec2 p0;\nflat out float r0;\nflat out float l0;\nflat out vec2 p1;\nflat out float r1;\nflat out float l1;\n\nvoid main()\t{\n r0 = radius0;\n r1 = radius1;\n p0 = position0;\n p1 = position1;\n l0 = summedLength0;\n l1 = summedLength1;\n\n vec2 tangent = normalize(position1 - position0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float cosTheta = (r0 - r1)/distance(p0, p1);\n // the vertex1 with radius is fully inside the vertex0.\n if(abs(cosTheta) >= 1.0) return;\n\n // Each instance is a trapzoid, whose vertices' positions are determined here.\n // Use gl_VertexID {0, 1, 2, 3} to index and get the desired parameters.\n // Be careful with the backface culling! We are ignoring it here.\n vec2 offsetSign = vec2[](\n vec2(-1.0,-1.0),\n vec2(-1.0, 1.0),\n vec2( 1.0, 1.0),\n vec2( 1.0,-1.0)\n )[gl_VertexID];\n vec2 position = vec2[](position0, position0, position1, position1)[gl_VertexID];\n float radius = vec4(radius0, radius0, radius1, radius1)[gl_VertexID];\n\n float tanHalfTheta = sqrt((1.0+cosTheta) / (1.0-cosTheta));\n float cotHalfTheta = 1.0 / tanHalfTheta;\n float normalTanValue = vec4(tanHalfTheta, tanHalfTheta, cotHalfTheta, cotHalfTheta)[gl_VertexID];\n if(normalTanValue > 10.0 || normalTanValue < 0.1) return;\n\n vec2 trapzoidVertexPosition = position +\n offsetSign.x * radius * tangent +\n offsetSign.y * radius * normal * normalTanValue;\n p = trapzoidVertexPosition;\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4(trapzoidVertexPosition, 0.0, 1.0);\n}\n",h="precision mediump float;\nprecision mediump int;\n\nin vec2 p;\nflat in vec2 p0;\nflat in float r0;\nflat in float l0;\nflat in vec2 p1;\nflat in float r1;\nflat in float l1;\n\n// Common\nuniform int type;\nconst int Vanilla = 0, Stamp = 1, Airbrush = 2;\nuniform vec4 color;\n// Stamp\nuniform mediump sampler2D footprint;\nuniform float stampIntervalRatio;\nuniform float noiseFactor;\nuniform float rotationFactor;\nfloat x2n(float x); // from distance to stamp index.\nfloat n2x(float n); // from stamp index to distance.\nmat2 rotate(float angle);\n// Airbrush\nuniform mediump sampler2D gradient;\nfloat sampleGraident(float distance){ return texture(gradient, vec2(distance, 0.0)).r; }\n\n// Noise helper functions from _The Book of Shader_.\nfloat random (in vec2 st);\nfloat noise (in vec2 st);\nfloat fbm (in vec2 st);\n\nout vec4 outColor;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n // The local coordinate orgin at p0, x axis along the tangent direct.\n float len = distance(p1, p0);\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n vec2 p0Local = vec2(0, 0);\n vec2 p1Local = vec2(len, 0);\n\n float cosTheta = (r0 - r1)/len;\n float d0 = distance(p, p0);\n float d0cos = pLocal.x / d0;\n float d1 = distance(p, p1);\n float d1cos = (pLocal.x - len) / d1;\n\n // Remove corners\n if(d0cos < cosTheta && d0 > r0) discard;\n if(d1cos > cosTheta && d1 > r1) discard;\n\n if(type == Vanilla){\n if(d0 < r0 && d1 < r1) discard;\n float A = (d0 < r0 || d1 < r1) ? 1.0 - sqrt(1.0 - color.a) : color.a;\n outColor = vec4(color.rgb, A);\n return;\n }\n\n if(type == Stamp){\n // The method here is not published yet, it should be explained in a 10min video.\n // The footprint is a disk instead of a square.\n // We set a quadratic polynomial to calculate the effect range, the range on polyline edge footprint can touch the current pixel.\n // Two roots of the quadratic polynomial are the effectRangeFront and effectRangeBack.\n // Formulas from SIGGRAPH 2022 Talk - A Fast & Robust Solution for Cubic & Higher-Order Polynomials\n float a, b, c, delta;\n a = 1.0 - pow(cosTheta, 2.0);\n b = 2.0 * (r0 * cosTheta - pLocal.x);\n c = pow(pLocal.x, 2.0) + pow(pLocal.y, 2.0) - pow(r0, 2.0);\n delta = pow(b, 2.0) - 4.0*a*c;\n if(delta <= 0.0) discard; // This should never happen.\n\n float tempMathBlock = b + sign(b) * sqrt(delta);\n float x1 = -2.0 * c / tempMathBlock;\n float x2 = -tempMathBlock / (2.0*a);\n float effectRangeFront = x1 <= x2 ? x1 : x2;\n float effectRangeBack = x1 > x2 ? x1 : x2;\n\n // We stamp on polyline every time the stamp index comes to an integer.\n float index0 = l0/stampIntervalRatio; // The stamp index of vertex0.\n float startIndex, endIndex;\n if (effectRangeFront <= 0.0){\n startIndex = ceil(index0);\n }\n else{\n startIndex = ceil(index0 + x2n(effectRangeFront));\n }\n float index1 = l1/stampIntervalRatio;\n float backIndex = x2n(effectRangeBack) + index0;\n endIndex = index1 < backIndex ? index1 : backIndex;\n if(startIndex > endIndex) discard;\n\n // The main loop to sample and blend color from the footprint.\n int MAX_i = 128; float currIndex = startIndex;\n float A = 0.0;\n for(int i = 0; i < MAX_i; i++){\n float currStampLocalX = n2x(currIndex - index0);\n // Apply roation and sample the footprint.\n vec2 pToCurrStamp = pLocal - vec2(currStampLocalX, 0.0);\n float currStampRadius = r0 - cosTheta * currStampLocalX;\n float angle = rotationFactor*radians(360.0*fract(sin(currIndex)*1.0));\n pToCurrStamp *= rotate(angle);\n vec2 textureCoordinate = (pToCurrStamp/currStampRadius + 1.0)/2.0;\n float opacity = texture(footprint, textureCoordinate).a;\n // Blend opacity.\n float opacityNoise = noiseFactor*fbm(textureCoordinate*50.0);\n opacity = clamp(opacity - opacityNoise, 0.0, 1.0) * color.a;\n A = A * (1.0-opacity) + opacity;\n\n currIndex += 1.0;\n if(currIndex > endIndex) break;\n }\n if(A < 1e-4) discard;\n outColor = vec4(color.rgb, A);\n return;\n }\n\n if(type == Airbrush){\n // The method here is not published yet. Shen is not fully satisfied with the current solution.\n float tanTheta = sqrt(1.0 - cosTheta*cosTheta)/cosTheta;\n float mid = pLocal.x - abs(pLocal.y)/tanTheta;\n float A = color.a;\n float transparency0 = d0 > r0 ? 1.0:sqrt(1.0 - A*sampleGraident(d0/r0));\n float transparency1 = d1 > r1 ? 1.0:sqrt(1.0 - A*sampleGraident(d1/r1));\n float transparency;\n\n // A bunch of math derived with the continuous form of airbrush here.\n if(mid <= 0.0){\n transparency = transparency0/transparency1;\n }\n if(mid > 0.0 && mid < len){\n float r = (mid * r1 + (len - mid) * r0)/len;\n float dr = distance(pLocal, vec2(mid, 0))/r;\n transparency = (1.0 - A*sampleGraident(dr))/transparency0/transparency1;\n }\n if(mid >= len){\n transparency = transparency1/transparency0;\n }\n\n outColor = vec4(color.rgb, 1.0 - transparency);\n }\n}\n\nfloat x2n(float x){\n float L = distance(p0, p1);\n if(r0 == r1) return x/(stampIntervalRatio*r0);\n else return -L / stampIntervalRatio / (r0 - r1) * log(1.0 - (1.0 - r1/r0)/L * x);\n}\n\nfloat n2x(float n){\n float L = distance(p0, p1);\n if(r0 == r1) return n * stampIntervalRatio * r0;\n else return L * (1.0-exp(-(r0-r1)*n*stampIntervalRatio/L)) / (1.0-r1/r0);\n}\n\n// Helper functions----------------------------------------------------------------------------------\nmat2 rotate(float angle){\n return mat2(cos(angle), -sin(angle), sin(angle), cos(angle));\n}\n\nfloat random (in vec2 st) {\n return fract(sin(dot(st.xy,\n vec2(12.9898,78.233)))*\n 43758.5453123);\n}\n\nfloat noise (in vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n\n // Four corners in 2D of a tile\n float a = random(i);\n float b = random(i + vec2(1.0, 0.0));\n float c = random(i + vec2(0.0, 1.0));\n float d = random(i + vec2(1.0, 1.0));\n\n vec2 u = f * f * (3.0 - 2.0 * f);\n\n return mix(a, b, u.x) +\n (c - a)* u.y * (1.0 - u.x) +\n (d - b) * u.x * u.y;\n}\n\n#define OCTAVES 6\nfloat fbm (in vec2 st) {\n // Initial values\n float value = 0.0;\n float amplitude = .5;\n float frequency = 0.;\n //\n // Loop of octaves\n for (int i = 0; i < OCTAVES; i++) {\n value += amplitude * noise(st);\n st *= 2.;\n amplitude *= .5;\n }\n return value;\n}\n";var p=t(9131),f=t(412),m=t(5893);let x=function(e){return e[e.Vanilla=0]="Vanilla",e[e.Stamp=1]="Stamp",e[e.Airbrush=2]="Airbrush",e}({});function g(e){let{uniforms:n=null,showEditor:t=null}=e;const p=(0,r.useRef)(),f=(0,r.useRef)(),g=(0,r.useRef)();function v(e,n,t){const r=[...n],a=[...n.slice(2)],i=[...t],s=[...t.slice(1)],l=[];let c=0;for(let h=0;h{const e=(1+Math.sqrt(5))/2,t=p.current.clientWidth,r=t*(.5/e),i=4*e,s=i*(.5/e),l=new o.iKG(i/-2,i/2,s/2,s/-2,-1e3,1e3);l.position.z=5;const c=new o.CP7({antialias:!0,alpha:!0,premultipliedAlpha:!1,powerPreference:"high-performance"});function m(){const n=p.current.clientWidth,t=.5*n/e;c.setSize(n,t)}c.setClearColor(new o.Ilk(1,1,1),0),c.setSize(t,r),window.addEventListener("resize",m),p.current.appendChild(c.domElement);const y=new o.xsS,w=new a.o(l,c.domElement);w.enableRotate=!1,w.enableDamping=!1,w.screenSpacePanning=!0,w.addEventListener("change",(()=>{c.render(y,l)})),f.current=()=>c.render(y,l),window.addEventListener("TextureLoaded",f.current);const b=new o.u9r;b.setIndex([0,1,2,2,3,0]);const j=new Function(d.Z),[I,T]=j();v(b,I,T);const S={type:{value:x.Vanilla},color:{value:[0,0,0,1]},footprint:{value:new o.xEZ},stampIntervalRatio:{value:1},noiseFactor:{value:0},rotationFactor:{value:0},gradient:{value:new o.IEO}},A=new o.FIo({uniforms:n||S,vertexShader:u,fragmentShader:h,side:o.ehD,transparent:!0,glslVersion:o.LSk});return g.current=new o.SPe(b,A,T.length-1),g.current.frustumCulled=!1,y.add(g.current),f.current(),()=>{c.dispose(),window.removeEventListener("resize",m),window.removeEventListener("TextureLoaded",f.current)}}),[]);const w=(0,r.useCallback)(((e,n)=>{let t=[],r=[];try{const n=new Function(e);[t,r]=n()}catch(a){return void console.log(a.toString())}function o(e){if(Array.isArray(e)){for(let n=0;n{y(e,"")}})}),T&&(0,m.jsx)(s.Z,{value:"fragment.glsl",children:(0,m.jsx)(c.r,{height:b,defaultValue:h,onChange:e=>{y("",e)}})})]})}),(0,m.jsx)("div",{ref:p,style:{width:"100%"},onMouseDown:e=>e.preventDefault()})]})}let v=new o.xEZ;f.Z.canUseDOM&&(v=(new o.dpR).load(`/${p.Z.projectName}/img/stamp2.png`,(e=>{window.dispatchEvent(new CustomEvent("TextureLoaded"))}),void 0,void 0));let y=new o.xEZ;f.Z.canUseDOM&&(y=(new o.dpR).load(`/${p.Z.projectName}/img/dot.png`,(e=>{window.dispatchEvent(new CustomEvent("TextureLoaded"))}),void 0,void 0));const w={type:{value:x.Stamp},color:{value:[0,0,0,1]},footprint:{value:v},stampIntervalRatio:{value:.4},noiseFactor:{value:1.2},rotationFactor:{value:.75}},b=(((e,n)=>{let t=new o.AXT(new o.FM8(0,1),e,n,new o.FM8(1,0));const r=256,a=new Uint8Array(1024),i=t.getPoints(512);for(let o=0;o=t.x&&e<=r.x){let n=(t.y*(r.x-e)+r.y*(e-t.x))/(r.x-t.x);a[4*o]=Math.floor(255*n)}}}const s=new o.IEO(a,r,1);s.needsUpdate=!0})(new o.FM8(.33,1),new o.FM8(.66,0)),x.Airbrush,{type:{value:x.Stamp},color:{value:[0,0,0,.5]},footprint:{value:y},stampIntervalRatio:{value:2},noiseFactor:{value:0},rotationFactor:{value:0}}),j={type:{value:x.Stamp},color:{value:[0,0,0,.5]},footprint:{value:y},stampIntervalRatio:{value:1},noiseFactor:{value:0},rotationFactor:{value:0}}}}]); \ No newline at end of file diff --git a/assets/js/ac092286.f7f1d5f0.js b/assets/js/ac092286.f7f1d5f0.js deleted file mode 100644 index dc15622..0000000 --- a/assets/js/ac092286.f7f1d5f0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbrush_stroke_tutorial=self.webpackChunkbrush_stroke_tutorial||[]).push([[364],{5923:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>s,default:()=>h,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var r=t(5893),o=t(1151),a=t(5632);const i={title:"Introduction",sidebar_position:2},s=void 0,l={id:"Introduction/Introduction",title:"Introduction",description:"Vanilla",source:"@site/docs/Introduction/Introduction.mdx",sourceDirName:"Introduction",slug:"/Introduction/",permalink:"/brush-rendering-tutorial/Introduction/",draft:!1,unlisted:!1,editUrl:"https://github.com/ShenCiao/brush-rendering-tutorial/tree/main/docs/Introduction/Introduction.mdx",tags:[],version:"current",sidebarPosition:2,frontMatter:{title:"Introduction",sidebar_position:2},sidebar:"tutorialSidebar",previous:{title:"Table of Contents",permalink:"/brush-rendering-tutorial/"},next:{title:"Basics",permalink:"/brush-rendering-tutorial/category/basics"}},c={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Structure",id:"structure",level:2},{value:"Content",id:"content",level:3},{value:"Live coding",id:"live-coding",level:3},{value:"Supplementary contents",id:"supplementary-contents",level:3},{value:"Citation",id:"citation",level:2}];function u(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,o.a)(),...e.components},{Details:t}=n;return t||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)("div",{className:"row row--no-gutters margin-left--xs",children:[(0,r.jsxs)("div",{className:"col col--6",children:[(0,r.jsx)(a.ij,{}),(0,r.jsx)("center",{children:(0,r.jsx)("em",{children:" Vanilla "})})]}),(0,r.jsxs)("div",{className:"col col--6",children:[(0,r.jsx)(a.ij,{uniforms:a.PQ}),(0,r.jsx)("center",{children:(0,r.jsx)("em",{children:" Pencil "})})]})]}),"\n",(0,r.jsx)("br",{}),"\n",(0,r.jsxs)(n.admonition,{type:"note",children:[(0,r.jsx)(n.p,{children:"When hovering your mouse on the canvas you can:"}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Pan"}),": Left-click and drag the mouse."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Zoom"}),": Scroll or drag the mouse wheel."]}),"\n"]})]}),"\n",(0,r.jsxs)(n.p,{children:["This tutorial series will teach you how to use the modern GPU graphics pipeline to render brush strokes,\ncommonly seen with a paint tool in graphics design software like Photoshop.\nThe contents mainly come from my research work ",(0,r.jsx)(n.a,{href:"https://github.com/ShenCiao/Ciallo",children:"Ciallo: The next generation vector paint program"}),',\nand a textbook "Image and Video-Based Artistic Stylisation" edited by Paul Rosin, John Collomosse.\nThe book introduces brush stroke rendering in its second chapter, authored by Stephen DiVerdi.\nSince there will be more research work on GPU brush stroke rendering,\nI will continuously update this tutorial series to teach you related techniques in (potentially) influential research works.']}),"\n",(0,r.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsx)(n.p,{children:"Decent experience in one of the GPU graphics APIs like OpenGL and D3D is required.\nIf you were relatively new to computer graphics, you should at least have rendered your first 3D scene and practiced instanced rendering."}),"\n",(0,r.jsxs)(n.p,{children:["GPU APIs have built-in line rendering functionalities.\nIt's totally fine if you never heard about ",(0,r.jsx)(n.code,{children:"LINES"}),", ",(0,r.jsx)(n.code,{children:"LINE_STRIP"}),", and ",(0,r.jsx)(n.code,{children:"LINE_LOOP"})," GPU primitives.\nWe won't use the functionalities in this tutorial series.\nIf you're interested in learning about their drawbacks, you can check out mattdesl's article titled ",(0,r.jsx)(n.a,{href:"https://mattdesl.svbtle.com/drawing-lines-is-hard",children:"Drawing Lines is Hard"}),".\nReading it isn't a prerequisite, I still recommend it."]}),"\n",(0,r.jsx)(n.p,{children:"Though I create all the demos in the web environment, you don't have to know about WebGL or WebGPU.\nWe will concentrate on high-level techniques rather than the implementation details.\nNo matter which GPU API you are familiar with, utilizing them to render a stroke will be easy after this series."}),"\n",(0,r.jsx)(n.h2,{id:"structure",children:"Structure"}),"\n",(0,r.jsx)(n.h3,{id:"content",children:"Content"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.a,{href:"../category/basics/",children:"Basic"})," section covers the basics of the rendering and stylization methods.\nArticles in the Basic part are organized in a progressive fashion.\nYou may miss something important if skip one of them.\nAfter learning the Basic section, you can freely select your favorite topics.\nI will list extra prerequisites at the very beginning of each article."]}),"\n",(0,r.jsx)(n.h3,{id:"live-coding",children:"Live coding"}),"\n",(0,r.jsxs)(n.p,{children:["You will find live code editors similar to the one displayed below, inspired by ",(0,r.jsx)(n.a,{href:"https://thebookofshaders.com/",children:(0,r.jsx)(n.em,{children:"The Book of Shader"})}),".\nThe rendering result is updated in real-time after modifying the code.\nGive it a try by altering the values of ",(0,r.jsx)(n.code,{children:"maxRadius"}),", and watch how the canvas below changes."]}),"\n",(0,r.jsx)(a.ij,{showEditor:[!0,!1,!1]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["If there are bugs for common usages in the code editors or canvases, tell me at the ",(0,r.jsx)(n.a,{href:"https://github.com/ShenCiao/brush-rendering-tutorial/issues",children:"issue"})," page."]})}),"\n",(0,r.jsx)(n.p,{children:'Only geometry generation code "geometry.js" is demonstrated here.\nYou will find "vertex.glsl" and "fragment.glsl" for vertex and fragment shader code.\nWhether they are hidden or shown will depend on the context.'}),"\n",(0,r.jsx)(n.h3,{id:"supplementary-contents",children:"Supplementary contents"}),"\n",(0,r.jsx)(t,{open:!0,children:(0,r.jsxs)(n.p,{children:[(0,r.jsx)("summary",{children:"Dropdown tab"}),"\nSome contents are hidden inside a dropdown tab like this.\nThey are complementary to the main contents.\nFeel free to skip them."]})}),"\n",(0,r.jsx)(n.h2,{id:"citation",children:"Citation"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{children:"@inproceedings{Ciallo2023,\n author = {Ciao, Shen and Wei, Li-Yi},\n title = {Ciallo: The next-Generation Vector Paint Program},\n year = {2023},\n isbn = {9798400701436},\n publisher = {Association for Computing Machinery},\n address = {New York, NY, USA},\n url = {https://doi.org/10.1145/3587421.3595418},\n doi = {10.1145/3587421.3595418},\n booktitle = {ACM SIGGRAPH 2023 Talks},\n articleno = {67},\n numpages = {2},\n keywords = {Digital painting, stylized stroke, arrangement, vector graphics. coloring, graphics processing unit (GPU)},\n location = {Los Angeles, CA, USA},\n series = {SIGGRAPH '23}\n}\n"})}),"\n",(0,r.jsxs)(n.admonition,{title:"Research Tip",type:"note",children:[(0,r.jsx)(n.p,{children:"To demonstrate your research work about brush rendering, select vector drawings have variable radius or pen pressure data.\nRegular vector drawing datasets don't contain them."}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Zeyu Wang's work: ",(0,r.jsx)(n.a,{href:"https://dl.acm.org/doi/10.1145/3450626.3459819",children:"Paper"})," | ",(0,r.jsx)(n.a,{href:"https://github.com/zachzeyuwang/tracing-vs-freehand",children:"Dataset"})]}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.a,{href:"https://cloud.blender.org/p/gallery/5b642e25bf419c1042056fc6",children:"Blender Grease Pencil"})}),"\n",(0,r.jsxs)(n.li,{children:["... Tell me more in the ",(0,r.jsx)(n.a,{href:"https://github.com/ShenCiao/brush-rendering-tutorial/discussions/1",children:"discussion"}),"."]}),"\n"]})]})]})}function h(e={}){const{wrapper:n}={...(0,o.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(u,{...e})}):u(e)}},5632:(e,n,t)=>{t.d(n,{ij:()=>v,Sw:()=>b,rL:()=>j,PQ:()=>w});var r=t(7294),o=t(9477),a=t(5452),i=t(4866),s=t(5162),l=t(3764),c=t(5034),d=t(9279);const u="precision mediump float;\nprecision mediump int;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\nin vec2 position0;\nin float radius0;\nin float summedLength0;\nin vec2 position1;\nin float radius1;\nin float summedLength1;\n\nout vec2 p; // position of the current pixel\nflat out vec2 p0;\nflat out float r0;\nflat out float l0;\nflat out vec2 p1;\nflat out float r1;\nflat out float l1;\n\nvoid main()\t{\n r0 = radius0;\n r1 = radius1;\n p0 = position0;\n p1 = position1;\n l0 = summedLength0;\n l1 = summedLength1;\n\n vec2 tangent = normalize(position1 - position0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float cosTheta = (r0 - r1)/distance(p0, p1);\n // the vertex1 with radius is fully inside the vertex0.\n if(abs(cosTheta) >= 1.0) return;\n\n // Each instance is a trapzoid, whose vertices' positions are determined here.\n // Use gl_VertexID {0, 1, 2, 3} to index and get the desired parameters.\n // Be careful with the backface culling! We are ignoring it here.\n vec2 offsetSign = vec2[](\n vec2(-1.0,-1.0),\n vec2(-1.0, 1.0),\n vec2( 1.0, 1.0),\n vec2( 1.0,-1.0)\n )[gl_VertexID];\n vec2 position = vec2[](position0, position0, position1, position1)[gl_VertexID];\n float radius = vec4(radius0, radius0, radius1, radius1)[gl_VertexID];\n\n float tanHalfTheta = sqrt((1.0+cosTheta) / (1.0-cosTheta));\n float cotHalfTheta = 1.0 / tanHalfTheta;\n float normalTanValue = vec4(tanHalfTheta, tanHalfTheta, cotHalfTheta, cotHalfTheta)[gl_VertexID];\n if(normalTanValue > 10.0 || normalTanValue < 0.1) return;\n\n vec2 trapzoidVertexPosition = position +\n offsetSign.x * radius * tangent +\n offsetSign.y * radius * normal * normalTanValue;\n p = trapzoidVertexPosition;\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4(trapzoidVertexPosition, 0.0, 1.0);\n}\n",h="precision mediump float;\nprecision mediump int;\n\nin vec2 p;\nflat in vec2 p0;\nflat in float r0;\nflat in float l0;\nflat in vec2 p1;\nflat in float r1;\nflat in float l1;\n\n// Common\nuniform int type;\nconst int Vanilla = 0, Stamp = 1, Airbrush = 2;\nuniform vec4 color;\n// Stamp\nuniform mediump sampler2D footprint;\nuniform float stampIntervalRatio;\nuniform float noiseFactor;\nuniform float rotationFactor;\nfloat x2n(float x); // from distance to stamp index.\nfloat n2x(float n); // from stamp index to distance.\nmat2 rotate(float angle);\n// Airbrush\nuniform mediump sampler2D gradient;\nfloat sampleGraident(float distance){ return texture(gradient, vec2(distance, 0.0)).r; }\n\n// Noise helper functions from _The Book of Shader_.\nfloat random (in vec2 st);\nfloat noise (in vec2 st);\nfloat fbm (in vec2 st);\n\nout vec4 outColor;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n // The local coordinate orgin at p0, x axis along the tangent direct.\n float len = distance(p1, p0);\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n vec2 p0Local = vec2(0, 0);\n vec2 p1Local = vec2(len, 0);\n\n float cosTheta = (r0 - r1)/len;\n float d0 = distance(p, p0);\n float d0cos = pLocal.x / d0;\n float d1 = distance(p, p1);\n float d1cos = (pLocal.x - len) / d1;\n\n // Remove corners\n if(d0cos < cosTheta && d0 > r0) discard;\n if(d1cos > cosTheta && d1 > r1) discard;\n\n if(type == Vanilla){\n if(d0 < r0 && d1 < r1) discard;\n float A = (d0 < r0 || d1 < r1) ? 1.0 - sqrt(1.0 - color.a) : color.a;\n outColor = vec4(color.rgb, A);\n return;\n }\n\n if(type == Stamp){\n // The method here is not published yet, it should be explained in a 10min video.\n // The footprint is a disk instead of a square.\n // We set a quadratic polynomial to calculate the effect range, the range on polyline edge footprint can touch the current pixel.\n // Two roots of the quadratic polynomial are the effectRangeFront and effectRangeBack.\n // Formulas from SIGGRAPH 2022 Talk - A Fast & Robust Solution for Cubic & Higher-Order Polynomials\n float a, b, c, delta;\n a = 1.0 - pow(cosTheta, 2.0);\n b = 2.0 * (r0 * cosTheta - pLocal.x);\n c = pow(pLocal.x, 2.0) + pow(pLocal.y, 2.0) - pow(r0, 2.0);\n delta = pow(b, 2.0) - 4.0*a*c;\n if(delta <= 0.0) discard; // This should never happen.\n\n float tempMathBlock = b + sign(b) * sqrt(delta);\n float x1 = -2.0 * c / tempMathBlock;\n float x2 = -tempMathBlock / (2.0*a);\n float effectRangeFront = x1 <= x2 ? x1 : x2;\n float effectRangeBack = x1 > x2 ? x1 : x2;\n\n // We stamp on polyline every time the stamp index comes to an integer.\n float index0 = l0/stampIntervalRatio; // The stamp index of vertex0.\n float startIndex, endIndex;\n if (effectRangeFront <= 0.0){\n startIndex = ceil(index0);\n }\n else{\n startIndex = ceil(index0 + x2n(effectRangeFront));\n }\n float index1 = l1/stampIntervalRatio;\n float backIndex = x2n(effectRangeBack) + index0;\n endIndex = index1 < backIndex ? index1 : backIndex;\n if(startIndex > endIndex) discard;\n\n // The main loop to sample and blend color from the footprint.\n int MAX_i = 128; float currIndex = startIndex;\n float A = 0.0;\n for(int i = 0; i < MAX_i; i++){\n float currStampLocalX = n2x(currIndex - index0);\n // Apply roation and sample the footprint.\n vec2 pToCurrStamp = pLocal - vec2(currStampLocalX, 0.0);\n float currStampRadius = r0 - cosTheta * currStampLocalX;\n float angle = rotationFactor*radians(360.0*fract(sin(currIndex)*1.0));\n pToCurrStamp *= rotate(angle);\n vec2 textureCoordinate = (pToCurrStamp/currStampRadius + 1.0)/2.0;\n float opacity = texture(footprint, textureCoordinate).a;\n // Blend opacity.\n float opacityNoise = noiseFactor*fbm(textureCoordinate*50.0);\n opacity = clamp(opacity - opacityNoise, 0.0, 1.0) * color.a;\n A = A * (1.0-opacity) + opacity;\n\n currIndex += 1.0;\n if(currIndex > endIndex) break;\n }\n if(A < 1e-4) discard;\n outColor = vec4(color.rgb, A);\n return;\n }\n\n if(type == Airbrush){\n // The method here is not published yet. Shen is not fully satisfied with the current solution.\n float tanTheta = sqrt(1.0 - cosTheta*cosTheta)/cosTheta;\n float mid = pLocal.x - abs(pLocal.y)/tanTheta;\n float A = color.a;\n float transparency0 = d0 > r0 ? 1.0:sqrt(1.0 - A*sampleGraident(d0/r0));\n float transparency1 = d1 > r1 ? 1.0:sqrt(1.0 - A*sampleGraident(d1/r1));\n float transparency;\n\n // A bunch of math derived with the continuous form of airbrush here.\n if(mid <= 0.0){\n transparency = transparency0/transparency1;\n }\n if(mid > 0.0 && mid < len){\n float r = (mid * r1 + (len - mid) * r0)/len;\n float dr = distance(pLocal, vec2(mid, 0))/r;\n transparency = (1.0 - A*sampleGraident(dr))/transparency0/transparency1;\n }\n if(mid >= len){\n transparency = transparency1/transparency0;\n }\n\n outColor = vec4(color.rgb, 1.0 - transparency);\n }\n}\n\nfloat x2n(float x){\n float L = distance(p0, p1);\n if(r0 == r1) return x/(stampIntervalRatio*r0);\n else return -L / stampIntervalRatio / (r0 - r1) * log(1.0 - (1.0 - r1/r0)/L * x);\n}\n\nfloat n2x(float n){\n float L = distance(p0, p1);\n if(r0 == r1) return n * stampIntervalRatio * r0;\n else return L * (1.0-exp(-(r0-r1)*n*stampIntervalRatio/L)) / (1.0-r1/r0);\n}\n\n// Helper functions----------------------------------------------------------------------------------\nmat2 rotate(float angle){\n return mat2(cos(angle), -sin(angle), sin(angle), cos(angle));\n}\n\nfloat random (in vec2 st) {\n return fract(sin(dot(st.xy,\n vec2(12.9898,78.233)))*\n 43758.5453123);\n}\n\nfloat noise (in vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n\n // Four corners in 2D of a tile\n float a = random(i);\n float b = random(i + vec2(1.0, 0.0));\n float c = random(i + vec2(0.0, 1.0));\n float d = random(i + vec2(1.0, 1.0));\n\n vec2 u = f * f * (3.0 - 2.0 * f);\n\n return mix(a, b, u.x) +\n (c - a)* u.y * (1.0 - u.x) +\n (d - b) * u.x * u.y;\n}\n\n#define OCTAVES 6\nfloat fbm (in vec2 st) {\n // Initial values\n float value = 0.0;\n float amplitude = .5;\n float frequency = 0.;\n //\n // Loop of octaves\n for (int i = 0; i < OCTAVES; i++) {\n value += amplitude * noise(st);\n st *= 2.;\n amplitude *= .5;\n }\n return value;\n}\n";var p=t(9131),f=t(412),m=t(5893);let x=function(e){return e[e.Vanilla=0]="Vanilla",e[e.Stamp=1]="Stamp",e[e.Airbrush=2]="Airbrush",e}({});function v(e){let{uniforms:n=null,showEditor:t=null}=e;const p=(0,r.useRef)(),f=(0,r.useRef)(),v=(0,r.useRef)();function g(e,n,t){const r=[...n],a=[...n.slice(2)],i=[...t],s=[...t.slice(1)],l=[];let c=0;for(let h=0;h{const e=(1+Math.sqrt(5))/2,t=p.current.clientWidth,r=t*(.5/e),i=4*e,s=i*(.5/e),l=new o.iKG(i/-2,i/2,s/2,s/-2,-1e3,1e3);l.position.z=5;const c=new o.CP7({antialias:!0,alpha:!0,premultipliedAlpha:!1,powerPreference:"high-performance"});function m(){const n=p.current.clientWidth,t=.5*n/e;c.setSize(n,t)}c.setClearColor(new o.Ilk(1,1,1),0),c.setSize(t,r),window.addEventListener("resize",m),p.current.appendChild(c.domElement);const y=new o.xsS,w=new a.o(l,c.domElement);w.enableRotate=!1,w.enableDamping=!1,w.screenSpacePanning=!0,w.addEventListener("change",(()=>{c.render(y,l)})),f.current=()=>c.render(y,l),window.addEventListener("TextureLoaded",f.current);const b=new o.u9r;b.setIndex([0,1,2,2,3,0]);const j=new Function(d.Z),[I,T]=j();g(b,I,T);const S={type:{value:x.Vanilla},color:{value:[0,0,0,1]},footprint:{value:new o.xEZ},stampIntervalRatio:{value:1},noiseFactor:{value:0},rotationFactor:{value:0},gradient:{value:new o.IEO}},A=new o.FIo({uniforms:n||S,vertexShader:u,fragmentShader:h,side:o.ehD,transparent:!0,glslVersion:o.LSk});return v.current=new o.SPe(b,A,T.length-1),v.current.frustumCulled=!1,y.add(v.current),f.current(),()=>{c.dispose(),window.removeEventListener("resize",m),window.removeEventListener("TextureLoaded",f.current)}}),[]);const w=(0,r.useCallback)(((e,n)=>{let t=[],r=[];try{const n=new Function(e);[t,r]=n()}catch(a){return void console.log(a.toString())}function o(e){if(Array.isArray(e)){for(let n=0;n{y(e,"")}})}),T&&(0,m.jsx)(s.Z,{value:"fragment.glsl",children:(0,m.jsx)(c.r,{height:b,defaultValue:h,onChange:e=>{y("",e)}})})]})}),(0,m.jsx)("div",{ref:p,style:{width:"100%"},onMouseDown:e=>e.preventDefault()})]})}let g=new o.xEZ;f.Z.canUseDOM&&(g=(new o.dpR).load(`/${p.Z.projectName}/img/stamp2.png`,(e=>{window.dispatchEvent(new CustomEvent("TextureLoaded"))}),void 0,void 0));let y=new o.xEZ;f.Z.canUseDOM&&(y=(new o.dpR).load(`/${p.Z.projectName}/img/dot.png`,(e=>{window.dispatchEvent(new CustomEvent("TextureLoaded"))}),void 0,void 0));const w={type:{value:x.Stamp},color:{value:[0,0,0,1]},footprint:{value:g},stampIntervalRatio:{value:.4},noiseFactor:{value:1.2},rotationFactor:{value:.75}},b=(((e,n)=>{let t=new o.AXT(new o.FM8(0,1),e,n,new o.FM8(1,0));const r=256,a=new Uint8Array(1024),i=t.getPoints(512);for(let o=0;o=t.x&&e<=r.x){let n=(t.y*(r.x-e)+r.y*(e-t.x))/(r.x-t.x);a[4*o]=Math.floor(255*n)}}}const s=new o.IEO(a,r,1);s.needsUpdate=!0})(new o.FM8(.33,1),new o.FM8(.66,0)),x.Airbrush,{type:{value:x.Stamp},color:{value:[0,0,0,.5]},footprint:{value:y},stampIntervalRatio:{value:2},noiseFactor:{value:0},rotationFactor:{value:0}}),j={type:{value:x.Stamp},color:{value:[0,0,0,.5]},footprint:{value:y},stampIntervalRatio:{value:1},noiseFactor:{value:0},rotationFactor:{value:0}}}}]); \ No newline at end of file diff --git a/assets/js/bc662926.39ae1e06.js b/assets/js/bc662926.39ae1e06.js new file mode 100644 index 0000000..3dd49a7 --- /dev/null +++ b/assets/js/bc662926.39ae1e06.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkbrush_stroke_tutorial=self.webpackChunkbrush_stroke_tutorial||[]).push([[805],{7565:(s,e,a)=>{a.r(e),a.d(e,{assets:()=>A,contentTitle:()=>v,default:()=>w,frontMatter:()=>g,metadata:()=>u,toc:()=>N});var n=a(5893),i=a(1151),t=a(4896);const l="const maxRadius = 1/3;\nconst segmentCount = 32;\n\nconst position = [-4.0, -1.0, -2.0, 1.0, 2.0, 1.0, 4.0, -1.0];\nconst radius = [maxRadius, maxRadius, maxRadius, maxRadius];\n\nposition.forEach(function (value, index, arr){\n arr[index] *= 0.5;\n});\n\nradius.forEach(function (value, index, arr){\n arr[index] *= 0.5;\n});\n\n\n\nreturn [position, radius];\n",r="precision mediump float;\nprecision mediump int;\n\n// Take golbal const values like the `radius` here as uniforms. You can modify them freely.\nconst float radius = 1.0/2.0;\n\nuniform mat4 modelViewMatrix;\n// The `projectionMatrix` is a orthogonal projection matrix here, which is the default setting when rendering 2D stuff.\nuniform mat4 projectionMatrix;\n\n// The position of polyline vertices v_i and v_{i+1}\nin vec2 position0;\nin vec2 position1;\n\n// Output values to the fragment shader, `p` will be the current world position of a pixel. The others are shown in the diagram.\n// If you don't know about the `flat` qualifier here, you should jump right into the description below and come back later.\nout vec2 p;\nflat out vec2 p0;\nflat out vec2 p1;\nflat out float r;\n\nvoid main(){\n p0 = position0;\n p1 = position1;\n r = radius;\n\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n /* Each instance is a rectangle, whose vertices' positions are determined here.\n * The built-in variable `gl_VertexID` records the vertex index, whose value is one of the {0, 1, 2, 3}\n * We use `gl_VertexID` to index values we need for.\n * Here, 0 is the vertex on the lowerleft corner, 1 upperleft, 2 upperright, 3 lowerright\n */\n vec2 position = vec2[](p0, p0, p1, p1)[gl_VertexID];\n vec2 offsetSign = vec2[](\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n vec2(1.0, 1.0),\n vec2(1.0, -1.0)\n )[gl_VertexID];\n\n vec2 vertexPosition = position +\n offsetSign.x * r * tangent +\n offsetSign.y * r * normal;\n\n // Output positions are interpolated by the graphics pipeline to give us the world poisition of a pixel in fragement shader.\n p = vertexPosition;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 0.0, 1.0);\n}",c="precision mediump float;\nprecision mediump int;\n\nconst vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n\nout vec4 outColor;\n\nin vec2 p;\n// These variable are shown in the diagram\nflat in vec2 p0;\nflat in vec2 p1;\nflat in float r;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float len = distance(p1, p0);\n\n // Calculate the pixel position in the local coordinate shown in the diagram.\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n\n float d0 = distance(p, p0);\n float d1 = distance(p, p1);\n\n // Remove corners\n if(pLocal.x < 0.0 && d0 > r) discard; // left corners\n if(pLocal.x > len && d1 > r) discard; // right corners\n\n outColor = color;\n}";function h(s){let{showEditor:e=[!1,!1,!1]}=s;return(0,n.jsx)(t.m,{geometry:l,vertexShader:r,fragmentShader:c,showEditor:e})}var m=a(9279);const d="precision mediump float;\nprecision mediump int;\n\n// Set alpha value to 0.5\nconst vec4 color = vec4(0.0, 0.0, 0.0, 0.5);\n\nout vec4 outColor;\n\nin vec2 p;\nflat in vec2 p0;\nflat in vec2 p1;\nflat in float r;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float len = distance(p1, p0);\n\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n\n float d0 = distance(p, p0);\n float d1 = distance(p, p1);\n\n if(pLocal.x < 0.0 && d0 > r) discard;\n if(pLocal.x > len && d1 > r) discard;\n\n // ------------------------------------------------\n float A = color.a;\n // If pixel is inside one of the joint areas\n if (d0 < r || d1 < r) A = 1.0 - sqrt(1.0 - A);\n // If pixel is inside both joint areas, opacity is zero, discard it\n if (d0 < r && d1 < r) discard;\n\n outColor = vec4(color.rgb, A);\n}";function o(s){let{showEditor:e=[!1,!1,!1]}=s;return(0,n.jsx)(t.m,{geometry:m.Z,vertexShader:r,fragmentShader:d,showEditor:e})}const p="precision mediump float;\nprecision mediump int;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\n// Radius values are given by geometry data\nin float radius0;\nin float radius1;\nin vec2 position0;\nin vec2 position1;\n\nout vec2 p;\nflat out vec2 p0;\nflat out vec2 p1;\n// Output radius\nflat out float r0;\nflat out float r1;\n\nvoid main(){\n p0 = position0;\n p1 = position1;\n r0 = radius0;\n r1 = radius1;\n\n float cosTheta = (r0 - r1)/distance(p0, p1);\n // Coner case: One circle is entirely inside the another, discard the edge.\n if(abs(cosTheta) >= 1.0) return;\n\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n vec2 offsetSign = vec2[](\n vec2(-1.0,-1.0),\n vec2(-1.0, 1.0),\n vec2( 1.0, 1.0),\n vec2( 1.0,-1.0)\n )[gl_VertexID];\n vec2 position = vec2[](position0, position0, position1, position1)[gl_VertexID];\n float radius = vec4(radius0, radius0, radius1, radius1)[gl_VertexID];\n\n // Apply the half angle formula from cos(theta) to tan(theta/2)\n float tanHalfTheta = sqrt((1.0+cosTheta) / (1.0-cosTheta));\n float cotHalfTheta = 1.0 / tanHalfTheta;\n float normalTanValue = vec4(tanHalfTheta, tanHalfTheta, cotHalfTheta, cotHalfTheta)[gl_VertexID];\n // Corner case: The small circle is very close to the big one, casuing large offset in the normal direction, discard the edge\n if(normalTanValue > 10.0 || normalTanValue < 0.1) return;\n\n vec2 trapzoidVertexPosition = position +\n offsetSign.x * radius * tangent +\n offsetSign.y * radius * normal * normalTanValue;\n p = trapzoidVertexPosition;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 0.0, 1.0);\n}",x="precision mediump float;\nprecision mediump int;\n\nconst vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n\nout vec4 outColor;\n\nin vec2 p;\n\nflat in vec2 p0;\nflat in vec2 p1;\n// Radius values given by geometry, passed from the vertex shader\nflat in float r0;\nflat in float r1;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float len = distance(p1, p0);\n\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n\n float d0 = distance(p, p0);\n float d1 = distance(p, p1);\n float d0cos = pLocal.x / d0; // cosine value of the angle between line(p0, p) and current edge\n float d1cos = (pLocal.x - len) / d1; // between line(p1, p) and current edge\n\n float cosTheta = (r0 - r1)/distance(p0, p1);\n\n // Discard corners\n if(d0cos < cosTheta && d0 > r0) discard;\n if(d1cos > cosTheta && d1 > r1) discard;\n\n // Deal with opactiy\n float A = color.a;\n if (d0 < r0 && d1 < r1) discard;\n if (d0 < r0 || d1 < r1) A = 1.0 - sqrt(1.0 - A);\n\n outColor = vec4(color.rgb, A);\n}";function j(s){let{showEditor:e=[!1,!1,!1]}=s;return(0,n.jsx)(t.m,{geometry:m.Z,vertexShader:p,fragmentShader:x,showEditor:e})}const g={sidebar_position:1},v=void 0,u={id:"Basics/Vanilla/Vanilla",title:"Vanilla",description:"Uni radius",source:"@site/docs/Basics/Vanilla/Vanilla.mdx",sourceDirName:"Basics/Vanilla",slug:"/Basics/Vanilla/",permalink:"/brush-rendering-tutorial/Basics/Vanilla/",draft:!1,unlisted:!1,editUrl:"https://github.com/ShenCiao/brush-rendering-tutorial/tree/main/docs/Basics/Vanilla/Vanilla.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Problem Statement",permalink:"/brush-rendering-tutorial/Basics/Basics/"},next:{title:"Stamp",permalink:"/brush-rendering-tutorial/Basics/Stamp/"}},A={},N=[{value:"Uni radius",id:"uni-radius",level:2},{value:"Geometry shader implementation is elegant",id:"geometry-shader-implementation-is-elegant",level:4},{value:"Opacity",id:"opacity",level:2},{value:"Variable radius",id:"variable-radius",level:2},{value:"Corner case",id:"corner-case",level:2}];function f(s){const e={a:"a",annotation:"annotation",code:"code",em:"em",h2:"h2",h4:"h4",img:"img",math:"math",mfrac:"mfrac",mi:"mi",mn:"mn",mo:"mo",mrow:"mrow",msqrt:"msqrt",msub:"msub",p:"p",path:"path",pre:"pre",semantics:"semantics",span:"span",strong:"strong",svg:"svg",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.a)(),...s.components},{Details:t}=e;return t||function(s,e){throw new Error("Expected "+(e?"component":"object")+" `"+s+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:"uni-radius",children:"Uni radius"}),"\n",(0,n.jsx)(e.p,{children:"Let's start with a solid stroke with a single radius value.\nLater, add variable radius to it."}),"\n","\n",(0,n.jsx)(h,{}),"\n",(0,n.jsxs)(e.p,{children:["We are given a polyline with a set of vertices.\nIn the diagram below, we select an edge with two consecutive vertices, labeled as ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"v"}),(0,n.jsx)(e.mi,{children:"i"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"v_i"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.5806em",verticalAlign:"-0.15em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"v"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0359em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"v"}),(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mi,{children:"i"}),(0,n.jsx)(e.mo,{children:"+"}),(0,n.jsx)(e.mn,{children:"1"})]})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"v_{i+1}"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.6389em",verticalAlign:"-0.2083em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"v"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0359em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsxs)(e.span,{className:"mord mtight",children:[(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"}),(0,n.jsx)(e.span,{className:"mbin mtight",children:"+"}),(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})]})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2083em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),", then draw a capsule on it.\nIf we render every single edge like this, edges will connect to each other naturally, as shown on the right."]}),"\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(2003).Z+"",width:"2560",height:"1080"})}),(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(9948).Z+"",width:"2560",height:"1080"})})]})}),(0,n.jsx)(e.tbody,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Draw a capsule on an edge"})}),(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Connected capsules"})})]})})]}),"\n",(0,n.jsxs)(e.p,{children:["The diagram quite looks like drawing an ",(0,n.jsx)(e.a,{href:"https://www.google.com/search?q=articulated+arm+2D+diagram&tbm=isch",children:"articulated arm"}),".\nTherefore, we call it ",(0,n.jsx)(e.strong,{children:"articulated"})," stroke (Line) rendering."]}),"\n",(0,n.jsx)(e.p,{children:"Hopefully, the above idea sounds straightforward to you.\nIt's also easy to implement with GPU APIs.\nTo draw the capsule, we generate four new vertices to invoke a rectangle, as shown in the left figure below.\nThen, discard the pixels in the four corners, as shown on the right. All is done!"}),"\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"quad",src:a(2621).Z+"",width:"2560",height:"1080"})}),(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"quad",src:a(561).Z+"",width:"2560",height:"1080"})})]})}),(0,n.jsx)(e.tbody,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Generate rectangle vertices"})}),(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Discard corners"})})]})})]}),"\n",(0,n.jsx)(e.p,{children:"There are several possible ways to generate the rectangle vertices.\nThe most elegant one is to use a geometry shader.\nBut sadly, it's not supported on Apple's ecosystem and web platform, and many readers are not experienced in it.\nSo, I will mainly introduce another implementation with instanced rendering.\nBut if you're familiar with geometry shader, check out the dropdown tab below."}),"\n",(0,n.jsxs)(t,{children:[(0,n.jsx)("summary",{children:"Geometry shader implementation"}),(0,n.jsx)(e.p,{children:"Geometry shader is designed for transforming geometry.\nWe can write very elegant code on the CPU side, which feels like an OpenGL built-in stroke (line strip) rendering functionality."}),(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-cpp",children:"glUseProgram(brushStrokeProgram)\n/* set uniforms ... */\nglBindVertexArray(vao);\nglDrawArrays(GL_LINE_STRIP, ...);\n"})}),(0,n.jsx)(e.p,{children:"Pseudo code in the geometry shader:"}),(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-glsl",children:"layout(lines) in;\nlayout(triangle_strip, max_vertices = 4) out;\n\nvoid main(){\n /* Set the down left vertex variables */\n EmitVertex();\n /* Set the up left vertex variables */\n EmitVertex();\n /* Set the down right vertex variables */\n EmitVertex();\n /* Set the up right vertex variables */\n EmitVertex();\n}\n"})}),(0,n.jsx)(e.p,{children:"You will find the details in the upcoming description."}),(0,n.jsx)(e.h4,{id:"geometry-shader-implementation-is-elegant",children:"Geometry shader implementation is elegant"}),(0,n.jsxs)(e.p,{children:["The vertex array buffer object ",(0,n.jsx)(e.code,{children:"vao"})," is created like drawing a line strip.\nWe bind it and draw it as a line strip, then get a custom \"line strip\"!\nEvery line of the code is incredibly descriptive and self-explanatory.\nWhen mocking geometry shader's behavior with instanced rendering, the code gets obscure.\nSadly, graphics engineers cannot easily enjoy this elegance because of Apple's Metal API."]}),(0,n.jsx)(e.p,{children:"You may argue that geometry shader can cause a lot of performance issues.\nBut benefiting from hard work by GPU engineers and manufacturers,\nthe computational power is very much superfluous to draw 2D strokes with a modern discrete graphics card.\nPerformance is not everything.\nWriting maintainable and easy-to-understand code is much more critical in some cases."})]}),"\n",(0,n.jsxs)(e.p,{children:["We use instanced rendering to draw a large number of objects with the same vertex data.\nFor drawing a stroke, each instance is the rectangle shown above, and the number of instances is the number of stroke's edges\n(number of polyline vertices minus one).\nTo place a rectangle, all rectangle's vertices need to know the positions of polyline vertices ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_1"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and radius value ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsx)(e.mi,{children:"r"})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"r"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"r"})]})})]}),".\nWe will set a local coordinate in the shader program, origin at ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),", X and Y axes align to the tangent and normal direction:\n",(0,n.jsx)(e.img,{alt:"coo",src:a(9367).Z+"",width:"2560",height:"1080"})]}),"\n",(0,n.jsx)(e.p,{children:'You will find implementation details in the comments of the shader code below.\nThe "vertex.glsl" for the vertex shader and "fragment.glsl" for the fragment shader, feel free to change them:'}),"\n",(0,n.jsx)(h,{showEditor:[!1,!0,!0]}),"\n",(0,n.jsxs)(t,{children:[(0,n.jsx)("summary",{children:(0,n.jsxs)(e.p,{children:["In case you don't know the ",(0,n.jsx)(e.code,{children:"flat"})," qualifier"]})}),(0,n.jsxs)(e.p,{children:["Shader variables are interpolated by default when passing to a fragment shader.\nThe ",(0,n.jsx)(e.code,{children:"flat"})," qualifier tells your shader program no to interpolate the variable.\nIf you still need clarifications, check out this ",(0,n.jsx)(e.a,{href:"https://www.geeks3d.com/20130514/opengl-interpolation-qualifiers-glsl-tutorial/",children:"article"}),"."]})]}),"\n",(0,n.jsx)(e.h2,{id:"opacity",children:"Opacity"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"trans",src:a(7139).Z+"",width:"958",height:"296"})}),"\n",(0,n.jsxs)(e.p,{children:["Obviously, we are not dealing with transparency correctly in image above.\nYou can replicate it by setting the ",(0,n.jsx)(e.code,{children:"color"})," variable in the fragment shader above as ",(0,n.jsx)(e.code,{children:"const vec4 color = vec4(0.0, 0.0, 0.0, 0.5);"}),".\nThe areas where two edges connect are doubly colored.\nWe need to fix it."]}),"\n",(0,n.jsx)(e.p,{children:'For clarification, we define "joint" areas in the two circles at the start and end of the capsule,\nand the non-joint area is called "bone" area.'}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"joint",src:a(2625).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsxs)(e.p,{children:["Joint areas are doubly colored.\nWe need to adjust joints' pixels opacity (alpha value) to get the target opacity of bone.\nLabel joint alpha ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_j"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and bone alpha ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"b"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_b"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"b"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),".\nSince rgb values from previous and next edge are the same, we can apply alpha compositing formula:\n",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"b"})]}),(0,n.jsx)(e.mo,{children:"="}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{children:"+"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{stretchy:"false",children:"("}),(0,n.jsx)(e.mn,{children:"1"}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{stretchy:"false",children:")"})]}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_b = \\Alpha_j + \\Alpha_j(1 - \\Alpha_j)"})]})})}),(0,n.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"b"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.jsx)(e.span,{className:"mrel",children:"="}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"+"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"1.0361em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mopen",children:"("}),(0,n.jsx)(e.span,{className:"mord",children:"1"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"1.0361em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mclose",children:")"})]})]})]}),", and solve and joint opacity"]}),"\n",(0,n.jsx)(e.span,{className:"katex-display",children:(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{children:"="}),(0,n.jsx)(e.mn,{children:"1"}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsx)(e.msqrt,{children:(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mn,{children:"1"}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"b"})]})]})})]}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_j = 1 - \\sqrt{1 - \\Alpha_b}"})]})})}),(0,n.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.jsx)(e.span,{className:"mrel",children:"="}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.7278em",verticalAlign:"-0.0833em"}}),(0,n.jsx)(e.span,{className:"mord",children:"1"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"1.24em",verticalAlign:"-0.2395em"}}),(0,n.jsx)(e.span,{className:"mord sqrt",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsxs)(e.span,{className:"vlist",style:{height:"1.0005em"},children:[(0,n.jsxs)(e.span,{className:"svg-align",style:{top:"-3.2em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3.2em"}}),(0,n.jsxs)(e.span,{className:"mord",style:{paddingLeft:"1em"},children:[(0,n.jsx)(e.span,{className:"mord",children:"1"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"b"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})]}),(0,n.jsxs)(e.span,{style:{top:"-2.9605em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3.2em"}}),(0,n.jsx)(e.span,{className:"hide-tail",style:{minWidth:"1.02em",height:"1.28em"},children:(0,n.jsx)(e.svg,{xmlns:"http://www.w3.org/2000/svg",width:"400em",height:"1.28em",viewBox:"0 0 400000 1296",preserveAspectRatio:"xMinYMin slice",children:(0,n.jsx)(e.path,{d:"M263,681c0.7,0,18,39.7,52,119\nc34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120\nc340,-704.7,510.7,-1060.3,512,-1067\nl0 -0\nc4.7,-7.3,11,-11,19,-11\nH40000v40H1012.3\ns-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232\nc-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1\ns-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26\nc-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z\nM1001 80h400000v40h-400000z"})})})]})]}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2395em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})]})}),"\n",(0,n.jsx)(e.p,{children:"Let's see how to implement it:"}),"\n",(0,n.jsxs)(t,{children:[(0,n.jsx)("summary",{children:"About alpha compositing"}),(0,n.jsxs)(e.p,{children:["I've seen very experienced graphics engineers unfamiliar with alpha compositing.\nI would recommend two articles ",(0,n.jsx)(e.a,{href:"https://ciechanow.ski/alpha-compositing/",children:"1"})," and ",(0,n.jsx)(e.a,{href:"https://wiki.edunitas.com/IT/en/114-10/alpha-channels_400_eduNitas.html",children:"2"}),".\nThe topic is so important for 2D rendering that I will write a dedicated article to explain when introducing the airbrush."]})]}),"\n","\n",(0,n.jsx)(o,{showEditor:[!1,!1,!0]}),"\n",(0,n.jsx)(e.h2,{id:"variable-radius",children:"Variable radius"}),"\n",(0,n.jsx)(e.p,{children:"We are given a polyline with a radius value at each point to represent the variable radius stroke.\nThe rendering process is basically the same as uni-radius stroke:\nPlace four new vertices and discard the four corners, as shown in the figure below."}),"\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(9289).Z+"",width:"2560",height:"1080"})}),(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(8533).Z+"",width:"2560",height:"1080"})})]})}),(0,n.jsx)(e.tbody,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"An edge"})}),(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Connected edges"})})]})})]}),"\n",(0,n.jsxs)(e.p,{children:["The new vertices form a trapezoid rather than a rectangle to cover the whole capsule.\nWe need to solve a few extra geometric parameters in this trapezoid.\nFirst solve the angle ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsx)(e.mi,{children:"\u03b8"})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\theta"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.6944em"}}),(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"\u03b8"})]})})]})," in the diagrams.\nAs the figure below shows, draw a perpendicular from ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_1"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," to the radius at ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),".\nThe distance between ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_1"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," is known."]}),"\n",(0,n.jsx)(e.span,{className:"katex-display",children:(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mi,{children:"cos"}),(0,n.jsx)(e.mo,{children:"\u2061"}),(0,n.jsx)(e.mi,{children:"\u03b8"}),(0,n.jsx)(e.mo,{children:"="}),(0,n.jsxs)(e.mfrac,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"r"}),(0,n.jsx)(e.mn,{children:"0"})]}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"r"}),(0,n.jsx)(e.mn,{children:"1"})]})]}),(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"}),(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]}),(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"}),(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"})]})]})]}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\cos\\theta = \\frac{r_0 - r_1}{||p_0 - p_1||}"})]})})}),(0,n.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.6944em"}}),(0,n.jsx)(e.span,{className:"mop",children:"cos"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"\u03b8"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.jsx)(e.span,{className:"mrel",children:"="}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"2.1963em",verticalAlign:"-0.936em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,n.jsx)(e.span,{className:"mfrac",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsxs)(e.span,{className:"vlist",style:{height:"1.2603em"},children:[(0,n.jsxs)(e.span,{style:{top:"-2.314em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord",children:"\u2223\u2223"}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mord",children:"\u2223\u2223"})]})]}),(0,n.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,n.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,n.jsxs)(e.span,{style:{top:"-3.677em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"r"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0278em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"r"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0278em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})]})]}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.936em"},children:(0,n.jsx)(e.span,{})})})]})}),(0,n.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"theta",src:a(8917).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.p,{children:"The line between trapezoid corners and polyline points are bisectors, drawn in solid black line,\nso the corners' offset along the normal direction can be calculated.\nYou can easily know the parameters in the lower half part with symmetry."}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"para",src:a(1642).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.p,{children:"Shader code implementation:"}),"\n","\n","\n",(0,n.jsx)(j,{showEditor:[!1,!0,!0]}),"\n",(0,n.jsx)(e.h2,{id:"corner-case",children:"Corner case"}),"\n",(0,n.jsx)(e.p,{children:"In the vertex shader, we discard edges in the two corner conditions.\nBut in fact, they represent one corner case, as shown in the figures below."}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"near",src:a(9528).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-glsl",children:"// Corner case: The small circle is very close to the big one, casuing large offset in the normal direction, discard the edge\n if(normalTanValue > 10.0 || normalTanValue < 0.1) return;\n"})}),"\n",(0,n.jsxs)(e.p,{children:["When the small circle is very close to the big one, we get a large ",(0,n.jsx)(e.code,{children:"normalTanValue"})," value and invoked triangles will cover large areas of pixels,\nIt can hurt the performance badly."]}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"inside",src:a(8058).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-glsl",children:"// Coner case: One circle is entirely inside the another, discard the edge.\n if(abs(cosTheta) >= 1.0) return;\n"})}),"\n",(0,n.jsx)(e.p,{children:"When the small circle gets closer and entirely inside the big one, how to place vertices is undefined."}),"\n",(0,n.jsxs)(e.p,{children:["The two ",(0,n.jsx)(e.code,{children:"if"})," conditions happened in the same situation: the radius changes drastically in a short distance between points.\nIt rarely happens for the geometry data comes from a 2D canvas.\nModern tablets are stable enough to avoid generating this ill data.\nBut it is common in 3D, I will introduce the solution together with 3D stroke rendering."]})]})}function w(s={}){const{wrapper:e}={...(0,i.a)(),...s.components};return e?(0,n.jsx)(e,{...s,children:(0,n.jsx)(f,{...s})}):f(s)}},4896:(s,e,a)=>{a.d(e,{m:()=>p});var n=a(7294),i=a(9477),t=a(5452),l=a(4866),r=a(5162),c=a(3764),h=a(5034),m=a(412),d=a(9131),o=a(5893);function p(s){let{geometry:e,vertexShader:a,fragmentShader:p,showEditor:x=null,uniforms:j=null}=s;const g=(0,n.useRef)(),v=(0,n.useRef)(),u=(0,n.useRef)(),A=(0,n.useRef)();function N(s,e,a){const n=[...e],t=[...e.slice(2)],l=[...a],r=[...a.slice(1)],c=[];let h=0;for(let o=0;o{const s=(1+Math.sqrt(5))/2,n=g.current.clientWidth,l=n*(.5/s),r=5*s,c=r*(.5/s),h=new i.iKG(r/-2,r/2,c/2,c/-2,-1e3,1e3);h.position.z=5;const o=new i.CP7({preserveDrawingBuffer:!0,powerPreference:"high-performance",antialias:!0,alpha:!0,premultipliedAlpha:!1});function x(){const e=g.current.clientWidth,a=.5*e/s;o.setSize(e,a)}o.setClearColor(new i.Ilk(1,1,1),0),o.setSize(n,l),A.current=o,window.addEventListener("resize",x),g.current.appendChild(o.domElement);const f=new i.xsS,w=new t.o(h,o.domElement);w.enableRotate=!1,w.enableDamping=!1,w.screenSpacePanning=!0,w.addEventListener("change",(()=>{o.render(f,h)})),v.current=()=>o.render(f,h),window.addEventListener("TextureLoaded",v.current);let y=new i.u9r;if("string"==typeof e){const s=[0,1,2,2,3,0];y.setIndex(s);const a=new Function(e),[n,i]=a();N(y,n,i)}else{if(!(e instanceof i.u9r))return void console.error("Unrecognized geometry input: "+typeof e);y=e}let b=new i.xEZ;m.Z.canUseDOM&&(b=(new i.dpR).load(`/${d.Z.projectName}/img/stamp86.png`,(s=>{window.dispatchEvent(new CustomEvent("TextureLoaded"))}),void 0,void 0));let L={footprint:{value:b}};j&&(L=j);const C=new i.FIo({vertexShader:a,fragmentShader:p,side:i.ehD,transparent:!0,glslVersion:i.LSk,uniforms:L});return u.current=new i.SPe(y,C,y.getAttribute("position0").count-1),u.current.frustumCulled=!1,f.add(u.current),v.current(),()=>{o.dispose(),window.removeEventListener("resize",x),window.removeEventListener("TextureLoaded",v.current)}}),[]);const w=(0,n.useCallback)(((s,e)=>{let a=[],n=[];try{const e=new Function(s);[a,n]=e()}catch(t){return void console.log(t.toString())}function i(s){if(Array.isArray(s)){for(let e=0;e{f(s,"")}})}),C&&(0,o.jsx)(r.Z,{value:"fragment.glsl",children:(0,o.jsx)(h.r,{height:y,defaultValue:p,onChange:s=>{f("",s)}})})]})}),(0,o.jsx)("div",{ref:g,style:{width:"100%"},onMouseDown:s=>{s.preventDefault(),2==s.button&&console.log(A.current.domElement.toDataURL())}})]})}},9367:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/coordinate-68714349e3013c769921a0eb25796188.png"},7139:(s,e,a)=>{a.d(e,{Z:()=>n});const n="data:image/png;base64,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"},2003:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-capsule-2431a7ac5ef2ad09ed6f95c0bdc851cc.png"},9948:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-connect-154f70dedb0fdc2925c947b72c9b5e63.png"},2625:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-joint-4a2efa37d7b523b21cea374679424637.png"},561:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-quad-capsule-b5f5c7122375176a3a612ac132814fe5.png"},2621:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-quad-faf9f304af7d8eb2aa3e3f4b48fe0a24.png"},9289:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-capsule-1a4d1542500b2b4bc675225002014fb5.png"},8533:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-connect-7370fb26c99bcde2bd3a2a2472e1762e.png"},8058:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-inside-3f14e22e18826517a08aefef56ca7b68.png"},9528:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-near-ee8cdfc7cab5636a8382e54837f25a35.png"},1642:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-parameters-9d4c6d7aa31d0f61fd39ba9f69eaae6d.png"},8917:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-theta-12b21c91e67f9f33e901ae6d7435f111.png"}}]); \ No newline at end of file diff --git a/assets/js/bc662926.4b304381.js b/assets/js/bc662926.4b304381.js deleted file mode 100644 index 78b3386..0000000 --- a/assets/js/bc662926.4b304381.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkbrush_stroke_tutorial=self.webpackChunkbrush_stroke_tutorial||[]).push([[805],{7565:(s,e,a)=>{a.r(e),a.d(e,{assets:()=>A,contentTitle:()=>v,default:()=>w,frontMatter:()=>g,metadata:()=>u,toc:()=>N});var n=a(5893),i=a(1151),t=a(4896);const l="const maxRadius = 1/3;\nconst segmentCount = 32;\n\nconst position = [-4.0, -1.0, -2.0, 1.0, 2.0, 1.0, 4.0, -1.0];\nconst radius = [maxRadius, maxRadius, maxRadius, maxRadius];\n\nposition.forEach(function (value, index, arr){\n arr[index] *= 0.5;\n});\n\nradius.forEach(function (value, index, arr){\n arr[index] *= 0.5;\n});\n\n\n\nreturn [position, radius];\n",r="precision mediump float;\nprecision mediump int;\n\n// Take golbal const values like the `radius` here as uniforms. You can modify them freely.\nconst float radius = 1.0/2.0;\n\nuniform mat4 modelViewMatrix;\n// The `projectionMatrix` is a orthogonal projection matrix here, which is the default setting when rendering 2D stuff.\nuniform mat4 projectionMatrix;\n\n// The position of polyline vertices v_i and v_{i+1}\nin vec2 position0;\nin vec2 position1;\n\n// Output values to the fragment shader, `p` will be the current world position of a pixel. The others are shown in the diagram.\n// If you don't know about the `flat` qualifier here, you should jump right into the description below and come back later.\nout vec2 p;\nflat out vec2 p0;\nflat out vec2 p1;\nflat out float r;\n\nvoid main(){\n p0 = position0;\n p1 = position1;\n r = radius;\n\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n /* Each instance is a rectangle, whose vertices' positions are determined here.\n * The built-in variable `gl_VertexID` records the vertex index, whose value is one of the {0, 1, 2, 3}\n * We use `gl_VertexID` to index values we need for.\n * Here, 0 is the vertex on the lowerleft corner, 1 upperleft, 2 upperright, 3 lowerright\n */\n vec2 position = vec2[](p0, p0, p1, p1)[gl_VertexID];\n vec2 offsetSign = vec2[](\n vec2(-1.0, -1.0),\n vec2(-1.0, 1.0),\n vec2(1.0, 1.0),\n vec2(1.0, -1.0)\n )[gl_VertexID];\n\n vec2 vertexPosition = position +\n offsetSign.x * r * tangent +\n offsetSign.y * r * normal;\n\n // Output positions are interpolated by the graphics pipeline to give us the world poisition of a pixel in fragement shader.\n p = vertexPosition;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 0.0, 1.0);\n}",c="precision mediump float;\nprecision mediump int;\n\nconst vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n\nout vec4 outColor;\n\nin vec2 p;\n// These variable are shown in the diagram\nflat in vec2 p0;\nflat in vec2 p1;\nflat in float r;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float len = distance(p1, p0);\n\n // Calculate the pixel position in the local coordinate shown in the diagram.\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n\n float d0 = distance(p, p0);\n float d1 = distance(p, p1);\n\n // Remove corners\n if(pLocal.x < 0.0 && d0 > r) discard; // left corners\n if(pLocal.x > len && d1 > r) discard; // right corners\n\n outColor = color;\n}";function h(s){let{showEditor:e=[!1,!1,!1]}=s;return(0,n.jsx)(t.m,{geometry:l,vertexShader:r,fragmentShader:c,showEditor:e})}var m=a(9279);const d="precision mediump float;\nprecision mediump int;\n\n// Set alpha value to 0.5\nconst vec4 color = vec4(0.0, 0.0, 0.0, 0.5);\n\nout vec4 outColor;\n\nin vec2 p;\nflat in vec2 p0;\nflat in vec2 p1;\nflat in float r;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float len = distance(p1, p0);\n\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n\n float d0 = distance(p, p0);\n float d1 = distance(p, p1);\n\n if(pLocal.x < 0.0 && d0 > r) discard;\n if(pLocal.x > len && d1 > r) discard;\n\n // ------------------------------------------------\n float A = color.a;\n // If pixel is inside one of the joint areas\n if (d0 < r || d1 < r) A = 1.0 - sqrt(1.0 - A);\n // If pixel is inside both joint areas, opacity is zero, discard it\n if (d0 < r && d1 < r) discard;\n\n outColor = vec4(color.rgb, A);\n}";function o(s){let{showEditor:e=[!1,!1,!1]}=s;return(0,n.jsx)(t.m,{geometry:m.Z,vertexShader:r,fragmentShader:d,showEditor:e})}const p="precision mediump float;\nprecision mediump int;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\n\n// Radius values are given by geometry data\nin float radius0;\nin float radius1;\nin vec2 position0;\nin vec2 position1;\n\nout vec2 p;\nflat out vec2 p0;\nflat out vec2 p1;\n// Output radius\nflat out float r0;\nflat out float r1;\n\nvoid main(){\n p0 = position0;\n p1 = position1;\n r0 = radius0;\n r1 = radius1;\n\n float cosTheta = (r0 - r1)/distance(p0, p1);\n // Coner case: One circle is entirely inside the another, discard the edge.\n if(abs(cosTheta) >= 1.0) return;\n\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n vec2 offsetSign = vec2[](\n vec2(-1.0,-1.0),\n vec2(-1.0, 1.0),\n vec2( 1.0, 1.0),\n vec2( 1.0,-1.0)\n )[gl_VertexID];\n vec2 position = vec2[](position0, position0, position1, position1)[gl_VertexID];\n float radius = vec4(radius0, radius0, radius1, radius1)[gl_VertexID];\n\n // Apply the half angle formula from cos(theta) to tan(theta/2)\n float tanHalfTheta = sqrt((1.0+cosTheta) / (1.0-cosTheta));\n float cotHalfTheta = 1.0 / tanHalfTheta;\n float normalTanValue = vec4(tanHalfTheta, tanHalfTheta, cotHalfTheta, cotHalfTheta)[gl_VertexID];\n // Corner case: The small circle is very close to the big one, casuing large offset in the normal direction, discard the edge\n if(normalTanValue > 10.0 || normalTanValue < 0.1) return;\n\n vec2 trapzoidVertexPosition = position +\n offsetSign.x * radius * tangent +\n offsetSign.y * radius * normal * normalTanValue;\n p = trapzoidVertexPosition;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 0.0, 1.0);\n}",x="precision mediump float;\nprecision mediump int;\n\nconst vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n\nout vec4 outColor;\n\nin vec2 p;\n\nflat in vec2 p0;\nflat in vec2 p1;\n// Radius values given by geometry, passed from the vertex shader\nflat in float r0;\nflat in float r1;\n\nvoid main() {\n vec2 tangent = normalize(p1 - p0);\n vec2 normal = vec2(-tangent.y, tangent.x);\n float len = distance(p1, p0);\n\n vec2 pLocal = vec2(dot(p-p0, tangent), dot(p-p0, normal));\n\n float d0 = distance(p, p0);\n float d1 = distance(p, p1);\n float d0cos = pLocal.x / d0; // cosine value of the angle between line(p0, p) and current edge\n float d1cos = (pLocal.x - len) / d1; // between line(p1, p) and current edge\n\n float cosTheta = (r0 - r1)/distance(p0, p1);\n\n // Discard corners\n if(d0cos < cosTheta && d0 > r0) discard;\n if(d1cos > cosTheta && d1 > r1) discard;\n\n // Deal with opactiy\n float A = color.a;\n if (d0 < r0 && d1 < r1) discard;\n if (d0 < r0 || d1 < r1) A = 1.0 - sqrt(1.0 - A);\n\n outColor = vec4(color.rgb, A);\n}";function j(s){let{showEditor:e=[!1,!1,!1]}=s;return(0,n.jsx)(t.m,{geometry:m.Z,vertexShader:p,fragmentShader:x,showEditor:e})}const g={sidebar_position:1},v=void 0,u={id:"Basics/Vanilla/Vanilla",title:"Vanilla",description:"Uni radius",source:"@site/docs/Basics/Vanilla/Vanilla.mdx",sourceDirName:"Basics/Vanilla",slug:"/Basics/Vanilla/",permalink:"/brush-rendering-tutorial/Basics/Vanilla/",draft:!1,unlisted:!1,editUrl:"https://github.com/ShenCiao/brush-rendering-tutorial/tree/main/docs/Basics/Vanilla/Vanilla.mdx",tags:[],version:"current",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"tutorialSidebar",previous:{title:"Problem Statement",permalink:"/brush-rendering-tutorial/Basics/Basics/"},next:{title:"Stamp",permalink:"/brush-rendering-tutorial/Basics/Stamp/"}},A={},N=[{value:"Uni radius",id:"uni-radius",level:2},{value:"Geometry shader implementation is elegant",id:"geometry-shader-implementation-is-elegant",level:4},{value:"Opacity",id:"opacity",level:2},{value:"Variable radius",id:"variable-radius",level:2},{value:"Corner case",id:"corner-case",level:2}];function f(s){const e={a:"a",annotation:"annotation",code:"code",em:"em",h2:"h2",h4:"h4",img:"img",math:"math",mfrac:"mfrac",mi:"mi",mn:"mn",mo:"mo",mrow:"mrow",msqrt:"msqrt",msub:"msub",p:"p",path:"path",pre:"pre",semantics:"semantics",span:"span",strong:"strong",svg:"svg",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.a)(),...s.components},{Details:t}=e;return t||function(s,e){throw new Error("Expected "+(e?"component":"object")+" `"+s+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(e.h2,{id:"uni-radius",children:"Uni radius"}),"\n",(0,n.jsx)(e.p,{children:"Let's start with a solid stroke with a single radius value.\nLater, add variable radius to it."}),"\n","\n",(0,n.jsx)(h,{}),"\n",(0,n.jsxs)(e.p,{children:["We are given a polyline with a set of vertices.\nIn the diagram below, we select an edge with two consecutive vertices, labeled as ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"v"}),(0,n.jsx)(e.mi,{children:"i"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"v_i"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.5806em",verticalAlign:"-0.15em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"v"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0359em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"v"}),(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mi,{children:"i"}),(0,n.jsx)(e.mo,{children:"+"}),(0,n.jsx)(e.mn,{children:"1"})]})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"v_{i+1}"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.6389em",verticalAlign:"-0.2083em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"v"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0359em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsxs)(e.span,{className:"mord mtight",children:[(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"}),(0,n.jsx)(e.span,{className:"mbin mtight",children:"+"}),(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})]})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2083em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),", then draw a capsule on it.\nIf we render every single edge like this, edges will connect to each other naturally, as shown on the right."]}),"\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(2003).Z+"",width:"2560",height:"1080"})}),(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(9948).Z+"",width:"2560",height:"1080"})})]})}),(0,n.jsx)(e.tbody,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Draw a capsule on an edge"})}),(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Connected capsules"})})]})})]}),"\n",(0,n.jsxs)(e.p,{children:["The diagram quite looks like drawing an ",(0,n.jsx)(e.a,{href:"https://www.google.com/search?q=articulated+arm+2D+diagram&tbm=isch",children:"articulated arm"}),".\nTherefore, we call it ",(0,n.jsx)(e.strong,{children:"articulated"})," stroke (Line) rendering."]}),"\n",(0,n.jsx)(e.p,{children:"Hopefully, the above idea sounds straightforward to you.\nIt's also easy to implement with GPU APIs.\nTo draw the capsule, we generate four new vertices to invoke a rectangle, as shown in the left figure below.\nThen, discard the pixels in the four corners, as shown on the right. All is done!"}),"\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"quad",src:a(2621).Z+"",width:"2560",height:"1080"})}),(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"quad",src:a(561).Z+"",width:"2560",height:"1080"})})]})}),(0,n.jsx)(e.tbody,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Generate rectangle vertices"})}),(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Discard corners"})})]})})]}),"\n",(0,n.jsx)(e.p,{children:"There are several possible ways to generate the rectangle vertices.\nThe most elegant one is to use a geometry shader.\nBut sadly, it's not supported on Apple's ecosystem and web platform, and many readers are not experienced in it.\nSo, I will mainly introduce another implementation with instanced rendering.\nBut if you're familiar with geometry shader, check out the dropdown tab below."}),"\n",(0,n.jsxs)(t,{children:[(0,n.jsx)("summary",{children:"Geometry shader implementation"}),(0,n.jsx)(e.p,{children:"Geometry shader is designed for transforming geometry.\nWe can write very elegant code on the CPU side, which feels like an OpenGL built-in stroke (line strip) rendering functionality."}),(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-cpp",children:"glUseProgram(brushStrokeProgram)\n/* set uniforms ... */\nglBindVertexArray(vao);\nglDrawArrays(GL_LINE_STRIP, ...);\n"})}),(0,n.jsx)(e.p,{children:"Pseudo code in the geometry shader:"}),(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-glsl",children:"layout(lines) in;\nlayout(triangle_strip, max_vertices = 4) out;\n\nvoid main(){\n /* Set the down left vertex variables */\n EmitVertex();\n /* Set the up left vertex variables */\n EmitVertex();\n /* Set the down right vertex variables */\n EmitVertex();\n /* Set the up right vertex variables */\n EmitVertex();\n}\n"})}),(0,n.jsx)(e.p,{children:"You will find the details in the upcoming description."}),(0,n.jsx)(e.h4,{id:"geometry-shader-implementation-is-elegant",children:"Geometry shader implementation is elegant"}),(0,n.jsxs)(e.p,{children:["The vertex array buffer object ",(0,n.jsx)(e.code,{children:"vao"})," is created like drawing a line strip.\nWe bind it and draw it as a line strip, then get a custom \"line strip\"!\nEvery line of the code is incredibly descriptive and self-explanatory.\nWhen mocking geometry shader's behavior with instanced rendering, the code gets obscure.\nSadly, graphics engineers cannot easily enjoy this elegance because of Apple's Metal API."]}),(0,n.jsx)(e.p,{children:"You may argue that geometry shader can cause a lot of performance issues.\nBut benefiting from hard work by GPU engineers and manufacturers,\nthe computational power is very much superfluous to draw 2D contents with a modern discrete graphics card.\nPerformance is not everything.\nWriting maintainable and easy-to-understand code is much more critical in some cases."})]}),"\n",(0,n.jsxs)(e.p,{children:["We use instanced rendering to draw a large number of objects with the same vertex data.\nFor drawing a stroke, each instance is the rectangle shown above, and the number of instances is the number of stroke's edges\n(number of polyline vertices minus one).\nTo place a rectangle, all rectangle's vertices need to know the positions of polyline vertices ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_1"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and radius value ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsx)(e.mi,{children:"r"})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"r"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"r"})]})})]}),".\nWe will set a local coordinate in the shader program, origin at ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),", X and Y axes align to the tangent and normal direction:\n",(0,n.jsx)(e.img,{alt:"coo",src:a(9367).Z+"",width:"2560",height:"1080"})]}),"\n",(0,n.jsx)(e.p,{children:'You will find implementation details in the comments of the shader code below.\nThe "vertex.glsl" for the vertex shader and "fragment.glsl" for the fragment shader, feel free to change them:'}),"\n",(0,n.jsx)(h,{showEditor:[!1,!0,!0]}),"\n",(0,n.jsxs)(t,{children:[(0,n.jsx)("summary",{children:(0,n.jsxs)(e.p,{children:["In case you don't know the ",(0,n.jsx)(e.code,{children:"flat"})," qualifier"]})}),(0,n.jsxs)(e.p,{children:["Shader variables are interpolated by default when passing to a fragment shader.\nThe ",(0,n.jsx)(e.code,{children:"flat"})," qualifier tells your shader program no to interpolate the variable.\nIf you still need clarifications, check out this ",(0,n.jsx)(e.a,{href:"https://www.geeks3d.com/20130514/opengl-interpolation-qualifiers-glsl-tutorial/",children:"article"}),"."]})]}),"\n",(0,n.jsx)(e.h2,{id:"opacity",children:"Opacity"}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"trans",src:a(7139).Z+"",width:"958",height:"296"})}),"\n",(0,n.jsxs)(e.p,{children:["Obviously, we are not dealing with transparency correctly in image above.\nYou can replicate it by setting the ",(0,n.jsx)(e.code,{children:"color"})," variable in the fragment shader above as ",(0,n.jsx)(e.code,{children:"const vec4 color = vec4(0.0, 0.0, 0.0, 0.5);"}),".\nThe areas where two edges connect are doubly colored.\nWe need to fix it."]}),"\n",(0,n.jsx)(e.p,{children:'For clarification, we define "joint" areas in the two circles at the start and end of the capsule,\nand the non-joint area is called "bone" area.'}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"joint",src:a(2625).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsxs)(e.p,{children:["Joint areas are doubly colored.\nWe need to adjust joints' pixels opacity (alpha value) to get the target opacity of bone.\nLabel joint alpha ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_j"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and bone alpha ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"b"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_b"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"b"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),".\nSince rgb values from previous and next edge are the same, we can apply alpha compositing formula:\n",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"b"})]}),(0,n.jsx)(e.mo,{children:"="}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{children:"+"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{stretchy:"false",children:"("}),(0,n.jsx)(e.mn,{children:"1"}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{stretchy:"false",children:")"})]}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_b = \\Alpha_j + \\Alpha_j(1 - \\Alpha_j)"})]})})}),(0,n.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"b"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.jsx)(e.span,{className:"mrel",children:"="}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"+"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"1.0361em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mopen",children:"("}),(0,n.jsx)(e.span,{className:"mord",children:"1"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"1.0361em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mclose",children:")"})]})]})]}),", and solve and joint opacity"]}),"\n",(0,n.jsx)(e.span,{className:"katex-display",children:(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"j"})]}),(0,n.jsx)(e.mo,{children:"="}),(0,n.jsx)(e.mn,{children:"1"}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsx)(e.msqrt,{children:(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mn,{children:"1"}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"A"}),(0,n.jsx)(e.mi,{children:"b"})]})]})})]}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\Alpha_j = 1 - \\sqrt{1 - \\Alpha_b}"})]})})}),(0,n.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.05724em"},children:"j"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.jsx)(e.span,{className:"mrel",children:"="}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.7278em",verticalAlign:"-0.0833em"}}),(0,n.jsx)(e.span,{className:"mord",children:"1"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"1.24em",verticalAlign:"-0.2395em"}}),(0,n.jsx)(e.span,{className:"mord sqrt",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsxs)(e.span,{className:"vlist",style:{height:"1.0005em"},children:[(0,n.jsxs)(e.span,{className:"svg-align",style:{top:"-3.2em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3.2em"}}),(0,n.jsxs)(e.span,{className:"mord",style:{paddingLeft:"1em"},children:[(0,n.jsx)(e.span,{className:"mord",children:"1"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathrm",children:"A"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mathnormal mtight",children:"b"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})]}),(0,n.jsxs)(e.span,{style:{top:"-2.9605em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3.2em"}}),(0,n.jsx)(e.span,{className:"hide-tail",style:{minWidth:"1.02em",height:"1.28em"},children:(0,n.jsx)(e.svg,{xmlns:"http://www.w3.org/2000/svg",width:"400em",height:"1.28em",viewBox:"0 0 400000 1296",preserveAspectRatio:"xMinYMin slice",children:(0,n.jsx)(e.path,{d:"M263,681c0.7,0,18,39.7,52,119\nc34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120\nc340,-704.7,510.7,-1060.3,512,-1067\nl0 -0\nc4.7,-7.3,11,-11,19,-11\nH40000v40H1012.3\ns-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232\nc-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1\ns-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26\nc-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z\nM1001 80h400000v40h-400000z"})})})]})]}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.2395em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})]})}),"\n",(0,n.jsx)(e.p,{children:"Let's see how to implement it:"}),"\n",(0,n.jsxs)(t,{children:[(0,n.jsx)("summary",{children:"About alpha compositing"}),(0,n.jsxs)(e.p,{children:["I've seen very experienced graphics engineers unfamiliar with alpha compositing.\nI would recommend two articles ",(0,n.jsx)(e.a,{href:"https://ciechanow.ski/alpha-compositing/",children:"1"})," and ",(0,n.jsx)(e.a,{href:"https://wiki.edunitas.com/IT/en/114-10/alpha-channels_400_eduNitas.html",children:"2"}),".\nThe topic is so important for 2D rendering that I will write a dedicated article to explain when introducing the airbrush."]})]}),"\n","\n",(0,n.jsx)(o,{showEditor:[!1,!1,!0]}),"\n",(0,n.jsx)(e.h2,{id:"variable-radius",children:"Variable radius"}),"\n",(0,n.jsx)(e.p,{children:"We are given a polyline with a radius value at each point to represent the variable radius stroke.\nThe rendering process is basically the same as uni-radius stroke:\nPlace four new vertices and discard the four corners, as shown in the figure below."}),"\n",(0,n.jsxs)(e.table,{children:[(0,n.jsx)(e.thead,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(9289).Z+"",width:"2560",height:"1080"})}),(0,n.jsx)(e.th,{style:{textAlign:"center"},children:(0,n.jsx)(e.img,{alt:"edge",src:a(8533).Z+"",width:"2560",height:"1080"})})]})}),(0,n.jsx)(e.tbody,{children:(0,n.jsxs)(e.tr,{children:[(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"An edge"})}),(0,n.jsx)(e.td,{style:{textAlign:"center"},children:(0,n.jsx)(e.em,{children:"Connected edges"})})]})})]}),"\n",(0,n.jsxs)(e.p,{children:["The new vertices form a trapezoid rather than a rectangle to cover the whole capsule.\nWe need to solve a few extra geometric parameters in this trapezoid.\nFirst solve the angle ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsx)(e.mi,{children:"\u03b8"})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\theta"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.6944em"}}),(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"\u03b8"})]})})]})," in the diagrams.\nAs the figure below shows, draw a perpendicular from ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_1"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," to the radius at ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]}),".\nThe distance between ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_0"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," and ",(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsx)(e.mrow,{children:(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]})}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"p_1"})]})})}),(0,n.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})})]})," is known."]}),"\n",(0,n.jsx)(e.span,{className:"katex-display",children:(0,n.jsxs)(e.span,{className:"katex",children:[(0,n.jsx)(e.span,{className:"katex-mathml",children:(0,n.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block",children:(0,n.jsxs)(e.semantics,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mi,{children:"cos"}),(0,n.jsx)(e.mo,{children:"\u2061"}),(0,n.jsx)(e.mi,{children:"\u03b8"}),(0,n.jsx)(e.mo,{children:"="}),(0,n.jsxs)(e.mfrac,{children:[(0,n.jsxs)(e.mrow,{children:[(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"r"}),(0,n.jsx)(e.mn,{children:"0"})]}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"r"}),(0,n.jsx)(e.mn,{children:"1"})]})]}),(0,n.jsxs)(e.mrow,{children:[(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"}),(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"0"})]}),(0,n.jsx)(e.mo,{children:"\u2212"}),(0,n.jsxs)(e.msub,{children:[(0,n.jsx)(e.mi,{children:"p"}),(0,n.jsx)(e.mn,{children:"1"})]}),(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"}),(0,n.jsx)(e.mi,{mathvariant:"normal",children:"\u2223"})]})]})]}),(0,n.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\cos\\theta = \\frac{r_0 - r_1}{||p_0 - p_1||}"})]})})}),(0,n.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"0.6944em"}}),(0,n.jsx)(e.span,{className:"mop",children:"cos"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"\u03b8"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.jsx)(e.span,{className:"mrel",children:"="}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,n.jsxs)(e.span,{className:"base",children:[(0,n.jsx)(e.span,{className:"strut",style:{height:"2.1963em",verticalAlign:"-0.936em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mopen nulldelimiter"}),(0,n.jsx)(e.span,{className:"mfrac",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsxs)(e.span,{className:"vlist",style:{height:"1.2603em"},children:[(0,n.jsxs)(e.span,{style:{top:"-2.314em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord",children:"\u2223\u2223"}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",children:"p"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mord",children:"\u2223\u2223"})]})]}),(0,n.jsxs)(e.span,{style:{top:"-3.23em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,n.jsx)(e.span,{className:"frac-line",style:{borderBottomWidth:"0.04em"}})]}),(0,n.jsxs)(e.span,{style:{top:"-3.677em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"r"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0278em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"0"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,n.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.jsxs)(e.span,{className:"mord",children:[(0,n.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.02778em"},children:"r"}),(0,n.jsx)(e.span,{className:"msupsub",children:(0,n.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,n.jsxs)(e.span,{className:"vlist-r",children:[(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.3011em"},children:(0,n.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0278em",marginRight:"0.05em"},children:[(0,n.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,n.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,n.jsx)(e.span,{className:"mord mtight",children:"1"})})]})}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,n.jsx)(e.span,{})})})]})})]})]})]})]}),(0,n.jsx)(e.span,{className:"vlist-s",children:"\u200b"})]}),(0,n.jsx)(e.span,{className:"vlist-r",children:(0,n.jsx)(e.span,{className:"vlist",style:{height:"0.936em"},children:(0,n.jsx)(e.span,{})})})]})}),(0,n.jsx)(e.span,{className:"mclose nulldelimiter"})]})]})]})]})}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"theta",src:a(8917).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.p,{children:"The line between trapezoid corners and polyline points are bisectors, drawn in solid black line,\nso the corners' offset along the normal direction can be calculated.\nYou can easily know the parameters in the lower half part with symmetry."}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"para",src:a(1642).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.p,{children:"Shader code implementation:"}),"\n","\n","\n",(0,n.jsx)(j,{showEditor:[!1,!0,!0]}),"\n",(0,n.jsx)(e.h2,{id:"corner-case",children:"Corner case"}),"\n",(0,n.jsx)(e.p,{children:"In the vertex shader, we discard edges in the two corner conditions.\nBut in fact, they represent one corner case, as shown in the figures below."}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"near",src:a(9528).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-glsl",children:"// Corner case: The small circle is very close to the big one, casuing large offset in the normal direction, discard the edge\n if(normalTanValue > 10.0 || normalTanValue < 0.1) return;\n"})}),"\n",(0,n.jsxs)(e.p,{children:["When the small circle is very close to the big one, we get a large ",(0,n.jsx)(e.code,{children:"normalTanValue"})," value and invoked triangles will cover large areas of pixels,\nIt can hurt the performance badly."]}),"\n",(0,n.jsx)(e.p,{children:(0,n.jsx)(e.img,{alt:"inside",src:a(8058).Z+"",width:"2560",height:"1080"})}),"\n",(0,n.jsx)(e.pre,{children:(0,n.jsx)(e.code,{className:"language-glsl",children:"// Coner case: One circle is entirely inside the another, discard the edge.\n if(abs(cosTheta) >= 1.0) return;\n"})}),"\n",(0,n.jsx)(e.p,{children:"When the small circle gets closer and entirely inside the big one, how to place vertices is undefined."}),"\n",(0,n.jsxs)(e.p,{children:["The two ",(0,n.jsx)(e.code,{children:"if"})," conditions happened in the same situation: the radius changes drastically in a short distance between points.\nIt rarely happens for the geometry data comes from a 2D canvas.\nModern tablets are stable enough to avoid generating this ill data.\nBut it is common in 3D, I will introduce the solution together with 3D stroke rendering."]})]})}function w(s={}){const{wrapper:e}={...(0,i.a)(),...s.components};return e?(0,n.jsx)(e,{...s,children:(0,n.jsx)(f,{...s})}):f(s)}},4896:(s,e,a)=>{a.d(e,{m:()=>p});var n=a(7294),i=a(9477),t=a(5452),l=a(4866),r=a(5162),c=a(3764),h=a(5034),m=a(412),d=a(9131),o=a(5893);function p(s){let{geometry:e,vertexShader:a,fragmentShader:p,showEditor:x=null,uniforms:j=null}=s;const g=(0,n.useRef)(),v=(0,n.useRef)(),u=(0,n.useRef)(),A=(0,n.useRef)();function N(s,e,a){const n=[...e],t=[...e.slice(2)],l=[...a],r=[...a.slice(1)],c=[];let h=0;for(let o=0;o{const s=(1+Math.sqrt(5))/2,n=g.current.clientWidth,l=n*(.5/s),r=5*s,c=r*(.5/s),h=new i.iKG(r/-2,r/2,c/2,c/-2,-1e3,1e3);h.position.z=5;const o=new i.CP7({preserveDrawingBuffer:!0,powerPreference:"high-performance",antialias:!0,alpha:!0,premultipliedAlpha:!1});function x(){const e=g.current.clientWidth,a=.5*e/s;o.setSize(e,a)}o.setClearColor(new i.Ilk(1,1,1),0),o.setSize(n,l),A.current=o,window.addEventListener("resize",x),g.current.appendChild(o.domElement);const f=new i.xsS,w=new t.o(h,o.domElement);w.enableRotate=!1,w.enableDamping=!1,w.screenSpacePanning=!0,w.addEventListener("change",(()=>{o.render(f,h)})),v.current=()=>o.render(f,h),window.addEventListener("TextureLoaded",v.current);let y=new i.u9r;if("string"==typeof e){const s=[0,1,2,2,3,0];y.setIndex(s);const a=new Function(e),[n,i]=a();N(y,n,i)}else{if(!(e instanceof i.u9r))return void console.error("Unrecognized geometry input: "+typeof e);y=e}let b=new i.xEZ;m.Z.canUseDOM&&(b=(new i.dpR).load(`/${d.Z.projectName}/img/stamp86.png`,(s=>{window.dispatchEvent(new CustomEvent("TextureLoaded"))}),void 0,void 0));let L={footprint:{value:b}};j&&(L=j);const C=new i.FIo({vertexShader:a,fragmentShader:p,side:i.ehD,transparent:!0,glslVersion:i.LSk,uniforms:L});return u.current=new i.SPe(y,C,y.getAttribute("position0").count-1),u.current.frustumCulled=!1,f.add(u.current),v.current(),()=>{o.dispose(),window.removeEventListener("resize",x),window.removeEventListener("TextureLoaded",v.current)}}),[]);const w=(0,n.useCallback)(((s,e)=>{let a=[],n=[];try{const e=new Function(s);[a,n]=e()}catch(t){return void console.log(t.toString())}function i(s){if(Array.isArray(s)){for(let e=0;e{f(s,"")}})}),C&&(0,o.jsx)(r.Z,{value:"fragment.glsl",children:(0,o.jsx)(h.r,{height:y,defaultValue:p,onChange:s=>{f("",s)}})})]})}),(0,o.jsx)("div",{ref:g,style:{width:"100%"},onMouseDown:s=>{s.preventDefault(),2==s.button&&console.log(A.current.domElement.toDataURL())}})]})}},9367:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/coordinate-68714349e3013c769921a0eb25796188.png"},7139:(s,e,a)=>{a.d(e,{Z:()=>n});const n="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA74AAAEoCAYAAAB/3i12AAAUFklEQVR4Xu3X3ZHjxppFUZkyprQJbYJMkAnjgcYDmXBNaFPkygSuiuqq08UiPhJI5M9aEedV6spkANi//QZwgG/fvv14Zv8LwBLy+b93+b4BAGgiP0qOXn4sATCWfK4fvXwvAQC8LD84Wi4/pgDoUz6/Wy7fWwAAu+RHRQ/LjywArpXP6R6W7zMAgF/kB0SPyw8vANrK53KPy/cbAMBv+cEwwvJDDIBz5XN4hOX7DgBYUH4gjLj8MAPgWPncHXH5/gMAFpAfBDMsP9QAeE0+Z2dYvg8BgEnlR8BMy482AJ6Tz9eZlu9FAGAy+fKfdfkBB8A++Tyddfl+BAAmkC/8FZYfcwB8LZ+jKyzflwDAoPIlv9Lyow6Az+Xzc6XlexMAGEy+3FdcftwB8FE+N1dcvj8BgEHkS33l/f7773/lhx7A6rZnYz4vV16+RwGAjv34sb2/f32hrz7xC/CT6P182zs036sAQGdE79cTvwCi99HELwB0TPTuW34AAqwmn4v268QvAHRI9NaWH4EAq8jnod2f+AWAjoje55YfgwCzy+egPZ74BYAOiN7Xlh+FALPK55/tn/gFgAttL2IfM68vvg0BppPPPattO0PxCwAXEL3H7cPXIcCE8rln9W3nKH4BoCHRe/w+fCECTCSfd/b8tvMUvwDQwC16fcwcv3+/EgEmkc85e223cxW/AHAi0XvubmcLMIt8ztnru52t+AWAE4jeNrudMcDo8vlmx+12xuIXAA70Pno3+QK24/b+nAFGls83O27vz1n8AsABRG/7vT9vgBHlc82O3/vzFr8A8IKM3k2+eO345ZkDjCafa3b88szFLwA8QfReuzx7gFHk88zOW569+AWAgs+id5MvXDtvefYAo8jnmZ23PPuN+AWAHe5F7yZfuHbu8vwBepfPMTt3ef434hcAviB6+1reAUDv8jlm5y/v4Eb8AsAnvoreTb5o7fzlHQD0Lp9jdv7yDt4TvwDwzqPo3eSL1tos7wGgV/n8sjbLe0jiFwB+E729L+8CoFf5/LJ2y7tI4heApe2J3k2+YK3d8i4AepXPL2u3vIvPiF8AlrQ3ejf5grW2y/sA6E0+t6zt8j7uEb8ALKUSvZt8wVrb5X0A9CafW9Z2eR9fEb8ALEH0jre8E4De5HPL2i/v5CviF4CpVaN3ky9Wa7+8E4De5HPL2i/v5BHxC8CUnoneTb5Yrf3yTgB6k88ta7+8kz3ELwBTeTZ6N/litWuW9wLQi3xe2TXLe9lL/AIwhVeid5MvVrtmeS8AvcjnlV2zvJcK8QvA0F6N3k2+WO2a5b0A9CKfV3bN8l6qxC8AQzoier9///6ffLHaNcu7AehFPq/smm3v7LybKvELwFCOiN6N8O1neTcAvcjnlV2zI8J3I34BGMJR0bsRvv0s7wagF/m8smt2VPhuxC8AXTsyejfCt5/l3QD0Ip9Xds2ODN+N+AWgS0dH70b49rO8G4Be5PPKrtnR4bsRvwB05Yzo3QjffpZ3A9CLfF7ZNTsjfDfiF4AunBW9G+Hbz/JuAHqRzyu7ZmeF70b8AnCpM6N3I3z7Wd4NQC/yeWXX7Mzw3YhfAC5xdvRuhG8/y7sB6EU+r+yanR2+G/ELQFMtovcmX6x2zfJeAHqRzyu7ZnkvZxG/ADTRMno3+WK1a5b3AtCLfF7ZNct7OZP4BeBUraN3ky9Wa7+8E4De5HPL2i/v5GziF4BTXBG9m3yxWvvlnQD0Jp9b1n55Jy2IXwAOdVX0bvLFau2XdwLQm3xuWfvlnbQifgE4xJXRu8kXq7Vf3glAb/K5Ze2Xd9KS+AXgJVdH702+XK3t8j4AepPPLWu7vI8riF8AntJL9G7yBWvtlncB0Kt8flm75V1cRfwCUNJT9G7yBWvtlncB0Kt8flm75V1cSfwCsEtv0bvJF6y1W94FQK/y+WXtlndxNfELwJd6jN6bfMlam+U9APQqn1/WZnkPvRC/AHyq5+jd5IvWzl/eAUDv8jlm5y/voCfiF4APeo/eTb5o7fzlHQD0Lp9jdv7yDnojfgH4rxGi9yZftnbu8vwBepfPMTt3ef69Er8Aixspejf5wrXzlmcPMIp8ntl5y7PvmfgFWNRo0XuTL107Z3nuAKPI55mdszz3EYhfgMWMGr2bfPHa8cszBxhNPtfs+OWZj0L8Aixi5Oi9yZevHbs8b4DR5HPNjl2e92jEL8DkZojeTb6A7bjlWQOMKp9vdtzyrEckfgEmNUv03uRL2I5ZnjPAqPL5Zscsz3lk4hdgMrNF7yZfxPb68owBRpfPOXt9ecajE78Ak5gxem/yZWzPL88WYBb5vLPnl2c7C/ELMLiZo3eTL2R7fnm2ALPI5509vzzbmYhfgEHNHr03+VK2+vJMAWaTzz2rL890RuIXYDCrRO9Nvpxt//IsAWaVzz/bvzzLmYlfgEGsFr03+ZK2fctzBJhVPv9s3/IcVyB+ATq3avRu8kVtj5dnCDC7fA7a4+UZrkL8AnRq5ei9yZe13V+eHcAq8nlo95dntxrxC9AZ0ftTvrTt1+WZAawmn4v26/LMViV+ATohen+VL2/7uTwrgFXl89F+Ls9qdeIX4GKi9758idu3H3/88cf/5TkBrGp7JuZz0kTvPeIX4CKi97F8ma880QvwK/H7cXk+fCR+ARoTvfvlS33FiV6A+8TvP8tz4XPiF6AR0VuXL/eVJnoBHls9fvM8+Jr4BTiZ6H1Nvuhnn+gF2G/F+M0zYD/xC3AS0XuMfOnPOtELULdS/ObfTp34BTiY6D1Wvvxnm+gFeN4K8Zt/M88TvwAHEb3nyQ+BGSZ6AV43a/zm38kxxC/Ai0RvG/lhMOpEL8BxZorf/Ns4nvgFeJLobS8/FEaa6AU43ujxm38P5xK/AEWi91r54dD7RC/AeUaM3/wbaEf8AuwkevuRHxI9TvQCnG+U+M1/N9cQvwAPiN5+5cdFDxO9AO30Gr/576QP4hfgDtE7lvzwaD3RC9BeD/Gb/yb6JX4Bguidy/fv3/9z5v78888//vrrr9/NzKz9tmdwPpePXr5XGJf4BXgjeqn4+++//yd/QwC0tT2L8/kM94hfYHmilwrRC9AP8UuF+AWWJXqpEL0A/RG/VIhfYDmilwrRC9Av8UuF+AWWIXqpEL0A/RO/VIhfYHqilwrRCzAO8UuF+AWmJXqpEL0A4xG/VIhfYDqilwrRCzAu8UuF+AWmIXqpEL0A4xO/VIhfYHiilwrRCzAP8UuF+AWGJXqpEL0A8xG/VIhfYDiilwrRCzAv8UuF+AWGIXqpEL0A8xO/VIhfoHuilwrRC7AO8UuF+AW6JXqpEL0A6xG/VIhfoDuilwrRC7Au8UuF+AW6IXqpEL0AiF8qxC9wOdFLhegF4Eb8UiF+gcuIXipELwBJ/FIhfoHmRC8VoheAe8QvFeIXaEb0UiF6AXhE/FIhfoHTiV4qRC8Ae4lfKsQvcBrRS4XoBaBK/FIhfoHDiV4qRC8AzxK/VIhf4DCilwrRC8CrxC8V4hd4meilQvQCcBTxS4X4BZ4meqkQvQAcTfxSIX6BMtFLhegF4CzilwrxC+wmeqkQvQCcTfxSIX6Bh0QvFaIXgFbELxXiF7hL9FIhegFoTfxSIX6BX4heKkQvAFcRv1SIX+BfopcK0QvA1cQvFeIXEL2UiF4AeiF+qRC/sDDRS4XoBaA34pcK8QsLEr1UiF4AeiV+qRC/sBDRS4XoBaB34pcK8QsLEL1UiF4ARiF+qRC/MDHRS4XoBWA04pcK8QsTEr1UiF4ARiV+qRC/MBHRS4XoBWB04pcK8QsTEL1UiF4AZiF+qRC/MDDRS4XoBWA24pcK8QsDEr1UiF4AZiV+qRC/MBDRS4XoBWB24pcK8QsDEL1UiF4AViF+qRC/0DHRS4XoBWA14pcK8QsdEr1UiF4AViV+qRC/0BHRS4XoBWB14pcK8QsdEL1UiF4A+If4pUL8woVELxWiFwA+Er9UiF+4gOilQvQCwOfELxXiFxoSvVSIXgD4mvilQvxCA6KXCtELAPuIXyrEL5xI9FIhegGgRvxSIX7hBKKXCtELAM8Rv1SIXziQ6KVC9ALAa8QvFeIXDiB6qRC9AHAM8UuF+IUXiF4qRC8AHEv8UiF+4QmilwrRCwDnEL9UiF8oEL1UiF4AOJf4pUL8wg6ilwrRCwBtiF8qxC98QfRSIXoBoC3xS4X4hU+IXipELwBcQ/xSIX7hHdFLhegFgGuJXyrEL/wmeqkRvQDQB/FLhfhlaaKXCtELAH0Rv1SIX5YkeqkQvQDQJ/FLhfhlKaKXCtELAH0Tv1SIX5YgeqkQvQAwBvFLhfhlaqKXCtELAGMRv1SIX6YkeqkQvQAwJvFLhfhlKqKXCtELAGMTv1SIX6YgeqkQvQAwB/FLhfhlaKKXCtELAHMRv1SIX4YkeqkQvQAwJ/FLhfhlKKKXCtELAHMTv1SIX4YgeqkQvQCwBvFLhfila6KXCtELAGsRv1SIX7okeqkQvQCwJvFLhfilK6KXCtELAGsTv1SIX7ogeqkQvQDARvxSIX65lOilQvQCAO+JXyrEL5cQvVSIXgDgM+KXCvFLU6KXCtELAHxF/FIhfmlC9FIhegGAPcQvFeKXU4leKkQvAFAhfqkQv5xC9FIhegGAZ4hfKsQvhxK9VIheAOAV4pcK8cshRC8VohcAOIL4pUL88hLRS4XoBQCOJH6pEL88RfRSIXoBgDOIXyrELyWilwrRCwCcSfxSIX7ZRfRSIXoBgBbELxXily+JXipELwDQkvilQvzyKdFLhegFAK4gfqkQv3wgeqkQvQDAlcQvFeKX/xK9VIheAKAH4pcK8bs40UuF6AUAeiJ+qRC/ixK9VIheAKBH4pcK8bsY0UuF6AUAeiZ+qRC/ixC9VIheAGAE4pcK8Ts50UuF6AUARiJ+qRC/kxK9VIheAGBE4pcK8TsZ0UuF6AUARiZ+qRC/kxC9VIheAGAG4pcK8Ts40UuF6AUAZiJ+qRC/gxK9VIheAGBG4pcK8TsY0UuF6AUAZiZ+qRC/gxC9VIheAGAF4pcK8ds50UuF6AUAViJ+qRC/nRK9VIheAGBF4pcK8dsZ0UuF6AUAViZ+qRC/HcnLgXtELwCA+KUmfz9cIC8F7hG9AAA/iV8q8vdDQ3kZcI/oBQD4lfilIn8/NJCXAPeIXgCA+8QvFfn74UR5+HCP6AUAeEz8UpG/H06Qhw73iF4AgP3ELxX5++FgeeDwGdELAFAnftkrfzscKA8bPiN6AQCeJ37ZK387HCAPGT4jegEAXid+2St/O7woDxiS6AUAOI74ZY/83fCCPFxIohcA4Hjilz3yd8OT8mDhPdELAHAe8csj+ZvhCXmo8J7oBQA4n/jlkfzNUJQHCjeiFwCgHfHLV/L3QkEeJtyIXgCA9sQvX8nfCzvlQcJG9AIAXEf8ck/+VtghDxE2ohcA4Hril3vyt8IDeYAgegEA+iF++Uz+TnggD5C1iV4AgP6IX1L+RvhCHh5rE70AAP0Sv6T8jXBHHhzrEr0AAP0Tv7yXvw/uyINjTaIXAGAc4peb/G3wiTw01iR6AQDGI365yd8GIQ+M9YheAIBxiV82+bsg5IGxFtELADA+8Uv+Jgh5YKxD9AIAzEP8ri1/D4Q8MNYgegEA5iN+15W/Bd7Jw2INohcAYF7id135W+BNHhTzE70AAPMTv2vK3wFv8qCYm+gFAFiH+F1P/gZ4kwfFvEQvAMB6xO9a8v55kwfFnEQvAMC6xO868u55kwfFfEQvAADidw1577zJg2IuohcAgBvxO7+8c97kQTEP0QsAQBK/c8v75k0eFHMQvQAA3CN+55V3zZs8KMYnegEAeET8zinvmTd5UIxN9AIAsJf4nU/eMW/yoBiX6AUAoEr8ziXvlzd5UIxJ9AIA8CzxO4+8W97kQTEe0QsAwKvE7xzyXnmTB8VYRC8AAEcRv+PLO+WdPCzGIHoBADia+B1X3iUhD4z+iV4AAM4ifseU90jIA6NvohcAgLOJ3/HkHRLywOiX6AUAoBXxO5a8P0IeGH0SvQAAtCZ+x5F3xyfy0OiL6AUA4Crit395Z9yRB0c/RC8AAFcTv33L++KOPDj6IHoBAOiF+O1X3hVfyMPjWqIXAIDeiN/+5B3xQB4g1xG9AAD0Svz2Je+HB/IAuYboBQCgd+K3H3k37JCHSFuiFwCAUYjf6+WdsFMeJO2IXgAARiN+r5X3QUEeJucTvQAAjEr8XiPvgaI8UM4legEAGJ34bS/vgCfkoXIO0QsAwCzEbzt59jwpD5bjiV4AAGYjftvIc+cFebgcR/QCADAr8XuuPG9elAfMMUQvAACzE7/nybPmAHnIvEb0AgCwCvF7vDxjDpSHzXNELwAAqxG/x8mz5WB54NSJXgAAViV+j5Hnygny0NlP9AIAsDrx+5o8T06Uh89johcAAP4hfp+T50gDeQncJ3oBAOAj8VuT50cjP378+JaXwa9ELwAAfE787rO1V54dDYnfr4leAAD4mvj9mujthPj9nOgFAIB9xO/nRG9nxO9HeT4AAMBj+V29MtHbKfH7jzwXAABgv/y+XpHoHUBe2kryLAAAgLr8zl5JngUdy8tbQZ4BAADwvPzeXkGeAQPIS5xV/t0AAMBx8vt7Vvl3M5i80Jnk3woAABwvv8Nnkn8rA8vLHV3+fQAAwPnyu3x0+fcxibzoEeXfBAAAtJPf5yPKv4lJ5cWPIP8GAADgOvm9PoL8G1hE/hB6lP9mAACgH/n93qP8N7Oo/GH0IP+NAABAv/J7vgf5b4R/5Y+lpfy3AAAA48nv/Jby3wIP5Y/oaPn/AwAA5pMdcLT8/8HL8ke2V/53AACAdWUv7JX/HR77f8gCxblnNWvpAAAAAElFTkSuQmCC"},2003:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-capsule-2431a7ac5ef2ad09ed6f95c0bdc851cc.png"},9948:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-connect-154f70dedb0fdc2925c947b72c9b5e63.png"},2625:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-joint-4a2efa37d7b523b21cea374679424637.png"},561:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-quad-capsule-b5f5c7122375176a3a612ac132814fe5.png"},2621:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/uni-quad-faf9f304af7d8eb2aa3e3f4b48fe0a24.png"},9289:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-capsule-1a4d1542500b2b4bc675225002014fb5.png"},8533:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-connect-7370fb26c99bcde2bd3a2a2472e1762e.png"},8058:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-inside-3f14e22e18826517a08aefef56ca7b68.png"},9528:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-near-ee8cdfc7cab5636a8382e54837f25a35.png"},1642:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-parameters-9d4c6d7aa31d0f61fd39ba9f69eaae6d.png"},8917:(s,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/var-theta-12b21c91e67f9f33e901ae6d7435f111.png"}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.cc49c654.js b/assets/js/runtime~main.c8dce5ea.js similarity index 53% rename from assets/js/runtime~main.cc49c654.js rename to assets/js/runtime~main.c8dce5ea.js index 439c299..6ba6397 100644 --- a/assets/js/runtime~main.cc49c654.js +++ b/assets/js/runtime~main.c8dce5ea.js @@ -1 +1 @@ -(()=>{"use strict";var e,t,r,o,a,n={},i={};function d(e){var t=i[e];if(void 0!==t)return t.exports;var r=i[e]={id:e,loaded:!1,exports:{}};return n[e].call(r.exports,r,r.exports,d),r.loaded=!0,r.exports}d.m=n,d.c=i,e=[],d.O=(t,r,o,a)=>{if(!r){var n=1/0;for(u=0;u=a)&&Object.keys(d.O).every((e=>d.O[e](r[c])))?r.splice(c--,1):(i=!1,a0&&e[u-1][2]>a;u--)e[u]=e[u-1];e[u]=[r,o,a]},d.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return d.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,o){if(1&o&&(e=this(e)),8&o)return e;if("object"==typeof e&&e){if(4&o&&e.__esModule)return e;if(16&o&&"function"==typeof e.then)return e}var a=Object.create(null);d.r(a);var n={};t=t||[null,r({}),r([]),r(r)];for(var i=2&o&&e;"object"==typeof i&&!~t.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach((t=>n[t]=()=>e[t]));return n.default=()=>e,d.d(a,n),a},d.d=(e,t)=>{for(var r in t)d.o(t,r)&&!d.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((t,r)=>(d.f[r](e,t),t)),[])),d.u=e=>"assets/js/"+({53:"935f2afb",147:"26251b8b",195:"22948d09",274:"3b358ec9",342:"e7f20846",364:"ac092286",368:"a94703ab",370:"ed94b18f",394:"5244698c",518:"a7bd4aaa",592:"common",613:"6ae0415c",661:"5e95c892",736:"d50c89f1",805:"bc662926",817:"14eb3368",915:"6858f5cd",918:"17896441",940:"a7b05c2e"}[e]||e)+"."+{53:"d6c8afee",147:"b79fd33c",195:"f22bad27",274:"1690454c",342:"5985105c",364:"f7f1d5f0",368:"b1e8d1f0",370:"9dbb1674",394:"15347dcb",518:"799f9698",592:"4cd2e3f2",613:"257c2e09",661:"21b5de99",736:"d592ad16",772:"9c6e198c",805:"4b304381",817:"d6f9c9a0",915:"fdfe4d72",918:"a8762edc",940:"fd1fd14f"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o={},a="brush-stroke-tutorial:",d.l=(e,t,r,n)=>{if(o[e])o[e].push(t);else{var i,c;if(void 0!==r)for(var f=document.getElementsByTagName("script"),u=0;u{i.onerror=i.onload=null,clearTimeout(s);var a=o[e];if(delete o[e],i.parentNode&&i.parentNode.removeChild(i),a&&a.forEach((e=>e(r))),t)return t(r)},s=setTimeout(b.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=b.bind(null,i.onerror),i.onload=b.bind(null,i.onload),c&&document.head.appendChild(i)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/brush-rendering-tutorial/",d.gca=function(e){return e={17896441:"918","935f2afb":"53","26251b8b":"147","22948d09":"195","3b358ec9":"274",e7f20846:"342",ac092286:"364",a94703ab:"368",ed94b18f:"370","5244698c":"394",a7bd4aaa:"518",common:"592","6ae0415c":"613","5e95c892":"661",d50c89f1:"736",bc662926:"805","14eb3368":"817","6858f5cd":"915",a7b05c2e:"940"}[e]||e,d.p+d.u(e)},(()=>{var e={303:0,532:0};d.f.j=(t,r)=>{var o=d.o(e,t)?e[t]:void 0;if(0!==o)if(o)r.push(o[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var a=new Promise(((r,a)=>o=e[t]=[r,a]));r.push(o[2]=a);var n=d.p+d.u(t),i=new Error;d.l(n,(r=>{if(d.o(e,t)&&(0!==(o=e[t])&&(e[t]=void 0),o)){var a=r&&("load"===r.type?"missing":r.type),n=r&&r.target&&r.target.src;i.message="Loading chunk "+t+" failed.\n("+a+": "+n+")",i.name="ChunkLoadError",i.type=a,i.request=n,o[1](i)}}),"chunk-"+t,t)}},d.O.j=t=>0===e[t];var t=(t,r)=>{var o,a,n=r[0],i=r[1],c=r[2],f=0;if(n.some((t=>0!==e[t]))){for(o in i)d.o(i,o)&&(d.m[o]=i[o]);if(c)var u=c(d)}for(t&&t(r);f{"use strict";var e,t,r,o,a,n={},i={};function c(e){var t=i[e];if(void 0!==t)return t.exports;var r=i[e]={id:e,loaded:!1,exports:{}};return n[e].call(r.exports,r,r.exports,c),r.loaded=!0,r.exports}c.m=n,c.c=i,e=[],c.O=(t,r,o,a)=>{if(!r){var n=1/0;for(u=0;u=a)&&Object.keys(c.O).every((e=>c.O[e](r[d])))?r.splice(d--,1):(i=!1,a0&&e[u-1][2]>a;u--)e[u]=e[u-1];e[u]=[r,o,a]},c.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return c.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,c.t=function(e,o){if(1&o&&(e=this(e)),8&o)return e;if("object"==typeof e&&e){if(4&o&&e.__esModule)return e;if(16&o&&"function"==typeof e.then)return e}var a=Object.create(null);c.r(a);var n={};t=t||[null,r({}),r([]),r(r)];for(var i=2&o&&e;"object"==typeof i&&!~t.indexOf(i);i=r(i))Object.getOwnPropertyNames(i).forEach((t=>n[t]=()=>e[t]));return n.default=()=>e,c.d(a,n),a},c.d=(e,t)=>{for(var r in t)c.o(t,r)&&!c.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},c.f={},c.e=e=>Promise.all(Object.keys(c.f).reduce(((t,r)=>(c.f[r](e,t),t)),[])),c.u=e=>"assets/js/"+({53:"935f2afb",147:"26251b8b",195:"22948d09",274:"3b358ec9",342:"e7f20846",364:"ac092286",368:"a94703ab",370:"ed94b18f",394:"5244698c",518:"a7bd4aaa",592:"common",613:"6ae0415c",661:"5e95c892",736:"d50c89f1",805:"bc662926",817:"14eb3368",915:"6858f5cd",918:"17896441",940:"a7b05c2e"}[e]||e)+"."+{53:"d6c8afee",147:"b79fd33c",195:"f22bad27",274:"1690454c",342:"5985105c",364:"bc24b4de",368:"b1e8d1f0",370:"9dbb1674",394:"15347dcb",518:"799f9698",592:"4cd2e3f2",613:"257c2e09",661:"21b5de99",736:"d592ad16",772:"9c6e198c",805:"39ae1e06",817:"d6f9c9a0",915:"fdfe4d72",918:"a8762edc",940:"fd1fd14f"}[e]+".js",c.miniCssF=e=>{},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),o={},a="brush-stroke-tutorial:",c.l=(e,t,r,n)=>{if(o[e])o[e].push(t);else{var i,d;if(void 0!==r)for(var f=document.getElementsByTagName("script"),u=0;u{i.onerror=i.onload=null,clearTimeout(s);var a=o[e];if(delete o[e],i.parentNode&&i.parentNode.removeChild(i),a&&a.forEach((e=>e(r))),t)return t(r)},s=setTimeout(b.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=b.bind(null,i.onerror),i.onload=b.bind(null,i.onload),d&&document.head.appendChild(i)}},c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.p="/brush-rendering-tutorial/",c.gca=function(e){return e={17896441:"918","935f2afb":"53","26251b8b":"147","22948d09":"195","3b358ec9":"274",e7f20846:"342",ac092286:"364",a94703ab:"368",ed94b18f:"370","5244698c":"394",a7bd4aaa:"518",common:"592","6ae0415c":"613","5e95c892":"661",d50c89f1:"736",bc662926:"805","14eb3368":"817","6858f5cd":"915",a7b05c2e:"940"}[e]||e,c.p+c.u(e)},(()=>{var e={303:0,532:0};c.f.j=(t,r)=>{var o=c.o(e,t)?e[t]:void 0;if(0!==o)if(o)r.push(o[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var a=new Promise(((r,a)=>o=e[t]=[r,a]));r.push(o[2]=a);var n=c.p+c.u(t),i=new Error;c.l(n,(r=>{if(c.o(e,t)&&(0!==(o=e[t])&&(e[t]=void 0),o)){var a=r&&("load"===r.type?"missing":r.type),n=r&&r.target&&r.target.src;i.message="Loading chunk "+t+" failed.\n("+a+": "+n+")",i.name="ChunkLoadError",i.type=a,i.request=n,o[1](i)}}),"chunk-"+t,t)}},c.O.j=t=>0===e[t];var t=(t,r)=>{var o,a,n=r[0],i=r[1],d=r[2],f=0;if(n.some((t=>0!==e[t]))){for(o in i)c.o(i,o)&&(c.m[o]=i[o]);if(d)var u=d(c)}for(t&&t(r);f -Appendix | Brush Rendering Tutorial - +Appendix | Brush Rendering Tutorial + diff --git a/category/basics/index.html b/category/basics/index.html index 441386a..d9a8295 100644 --- a/category/basics/index.html +++ b/category/basics/index.html @@ -3,8 +3,8 @@ -Basics | Brush Rendering Tutorial - +Basics | Brush Rendering Tutorial + diff --git a/index.html b/index.html index 868d26c..1b3bdfc 100644 --- a/index.html +++ b/index.html @@ -3,8 +3,8 @@ -Table of Contents | Brush Rendering Tutorial - +Table of Contents | Brush Rendering Tutorial +